texenvprogram: fix for ARB_draw_buffers.
[mesa.git] / progs / es1 / xegl / torus.c
1 /*
2 * Copyright (C) 2008 Tunsgten Graphics,Inc. All Rights Reserved.
3 */
4
5 /*
6 * Draw a lit, textured torus with X/EGL and OpenGL ES 1.x
7 * Brian Paul
8 * July 2008
9 */
10
11
12 #include <assert.h>
13 #include <math.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <X11/keysym.h>
20 #include <GLES/gl.h>
21 #include <GLES/glext.h>
22 #include <EGL/egl.h>
23
24
25 static const struct {
26 GLenum internalFormat;
27 const char *name;
28 GLuint num_entries;
29 GLuint size;
30 } cpal_formats[] = {
31 { GL_PALETTE4_RGB8_OES, "GL_PALETTE4_RGB8_OES", 16, 3 },
32 { GL_PALETTE4_RGBA8_OES, "GL_PALETTE4_RGBA8_OES", 16, 4 },
33 { GL_PALETTE4_R5_G6_B5_OES, "GL_PALETTE4_R5_G6_B5_OES", 16, 2 },
34 { GL_PALETTE4_RGBA4_OES, "GL_PALETTE4_RGBA4_OES", 16, 2 },
35 { GL_PALETTE4_RGB5_A1_OES, "GL_PALETTE4_RGB5_A1_OES", 16, 2 },
36 { GL_PALETTE8_RGB8_OES, "GL_PALETTE8_RGB8_OES", 256, 3 },
37 { GL_PALETTE8_RGBA8_OES, "GL_PALETTE8_RGBA8_OES", 256, 4 },
38 { GL_PALETTE8_R5_G6_B5_OES, "GL_PALETTE8_R5_G6_B5_OES", 256, 2 },
39 { GL_PALETTE8_RGBA4_OES, "GL_PALETTE8_RGBA4_OES", 256, 2 },
40 { GL_PALETTE8_RGB5_A1_OES, "GL_PALETTE8_RGB5_A1_OES", 256, 2 }
41 };
42 #define NUM_CPAL_FORMATS (sizeof(cpal_formats) / sizeof(cpal_formats[0]))
43
44 static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
45 static GLint tex_format = NUM_CPAL_FORMATS;
46
47
48 static void
49 Normal(GLfloat *n, GLfloat nx, GLfloat ny, GLfloat nz)
50 {
51 n[0] = nx;
52 n[1] = ny;
53 n[2] = nz;
54 }
55
56 static void
57 Vertex(GLfloat *v, GLfloat vx, GLfloat vy, GLfloat vz)
58 {
59 v[0] = vx;
60 v[1] = vy;
61 v[2] = vz;
62 }
63
64 static void
65 Texcoord(GLfloat *v, GLfloat s, GLfloat t)
66 {
67 v[0] = s;
68 v[1] = t;
69 }
70
71
72 /* Borrowed from glut, adapted */
73 static void
74 draw_torus(GLfloat r, GLfloat R, GLint nsides, GLint rings)
75 {
76 int i, j;
77 GLfloat theta, phi, theta1;
78 GLfloat cosTheta, sinTheta;
79 GLfloat cosTheta1, sinTheta1;
80 GLfloat ringDelta, sideDelta;
81 GLfloat varray[100][3], narray[100][3], tarray[100][2];
82 int vcount;
83
84 glVertexPointer(3, GL_FLOAT, 0, varray);
85 glNormalPointer(GL_FLOAT, 0, narray);
86 glTexCoordPointer(2, GL_FLOAT, 0, tarray);
87 glEnableClientState(GL_VERTEX_ARRAY);
88 glEnableClientState(GL_NORMAL_ARRAY);
89 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
90
91 ringDelta = 2.0 * M_PI / rings;
92 sideDelta = 2.0 * M_PI / nsides;
93
94 theta = 0.0;
95 cosTheta = 1.0;
96 sinTheta = 0.0;
97 for (i = rings - 1; i >= 0; i--) {
98 theta1 = theta + ringDelta;
99 cosTheta1 = cos(theta1);
100 sinTheta1 = sin(theta1);
101
102 vcount = 0; /* glBegin(GL_QUAD_STRIP); */
103
104 phi = 0.0;
105 for (j = nsides; j >= 0; j--) {
106 GLfloat s0, s1, t;
107 GLfloat cosPhi, sinPhi, dist;
108
109 phi += sideDelta;
110 cosPhi = cos(phi);
111 sinPhi = sin(phi);
112 dist = R + r * cosPhi;
113
114 s0 = 20.0 * theta / (2.0 * M_PI);
115 s1 = 20.0 * theta1 / (2.0 * M_PI);
116 t = 8.0 * phi / (2.0 * M_PI);
117
118 Normal(narray[vcount], cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
119 Texcoord(tarray[vcount], s1, t);
120 Vertex(varray[vcount], cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
121 vcount++;
122
123 Normal(narray[vcount], cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
124 Texcoord(tarray[vcount], s0, t);
125 Vertex(varray[vcount], cosTheta * dist, -sinTheta * dist, r * sinPhi);
126 vcount++;
127 }
128
129 /*glEnd();*/
130 assert(vcount <= 100);
131 glDrawArrays(GL_TRIANGLE_STRIP, 0, vcount);
132
133 theta = theta1;
134 cosTheta = cosTheta1;
135 sinTheta = sinTheta1;
136 }
137
138 glDisableClientState(GL_VERTEX_ARRAY);
139 glDisableClientState(GL_NORMAL_ARRAY);
140 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
141 }
142
143
144 static void
145 draw(void)
146 {
147 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
148
149 glPushMatrix();
150 glRotatef(view_rotx, 1, 0, 0);
151 glRotatef(view_roty, 0, 1, 0);
152 glRotatef(view_rotz, 0, 0, 1);
153 glScalef(0.5, 0.5, 0.5);
154
155 draw_torus(1.0, 3.0, 30, 60);
156
157 glPopMatrix();
158 }
159
160
161 /* new window size or exposure */
162 static void
163 reshape(int width, int height)
164 {
165 GLfloat ar = (GLfloat) width / (GLfloat) height;
166
167 glViewport(0, 0, (GLint) width, (GLint) height);
168
169 glMatrixMode(GL_PROJECTION);
170 glLoadIdentity();
171
172 #ifdef GL_VERSION_ES_CM_1_0
173 glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
174 #else
175 glFrustum(-ar, ar, -1, 1, 5.0, 60.0);
176 #endif
177
178 glMatrixMode(GL_MODELVIEW);
179 glLoadIdentity();
180 glTranslatef(0.0, 0.0, -15.0);
181 }
182
183
184 static GLint
185 make_cpal_texture(GLint idx)
186 {
187 #define SZ 64
188 GLenum internalFormat = GL_PALETTE4_RGB8_OES + idx;
189 GLenum Filter = GL_LINEAR;
190 GLubyte palette[256 * 4 + SZ * SZ];
191 GLubyte *indices;
192 GLsizei image_size;
193 GLuint i, j;
194 GLuint packed_indices = 0;
195
196 assert(cpal_formats[idx].internalFormat == internalFormat);
197
198 /* init palette */
199 switch (internalFormat) {
200 case GL_PALETTE4_RGB8_OES:
201 case GL_PALETTE8_RGB8_OES:
202 /* first entry */
203 palette[0] = 255;
204 palette[1] = 255;
205 palette[2] = 255;
206 /* second entry */
207 palette[3] = 127;
208 palette[4] = 127;
209 palette[5] = 127;
210 break;
211 case GL_PALETTE4_RGBA8_OES:
212 case GL_PALETTE8_RGBA8_OES:
213 /* first entry */
214 palette[0] = 255;
215 palette[1] = 255;
216 palette[2] = 255;
217 palette[3] = 255;
218 /* second entry */
219 palette[4] = 127;
220 palette[5] = 127;
221 palette[6] = 127;
222 palette[7] = 255;
223 break;
224 case GL_PALETTE4_R5_G6_B5_OES:
225 case GL_PALETTE8_R5_G6_B5_OES:
226 {
227 GLushort *pal = (GLushort *) palette;
228 /* first entry */
229 pal[0] = (31 << 11 | 63 << 5 | 31);
230 /* second entry */
231 pal[1] = (15 << 11 | 31 << 5 | 15);
232 }
233 break;
234 case GL_PALETTE4_RGBA4_OES:
235 case GL_PALETTE8_RGBA4_OES:
236 {
237 GLushort *pal = (GLushort *) palette;
238 /* first entry */
239 pal[0] = (15 << 12 | 15 << 8 | 15 << 4 | 15);
240 /* second entry */
241 pal[1] = (7 << 12 | 7 << 8 | 7 << 4 | 15);
242 }
243 break;
244 case GL_PALETTE4_RGB5_A1_OES:
245 case GL_PALETTE8_RGB5_A1_OES:
246 {
247 GLushort *pal = (GLushort *) palette;
248 /* first entry */
249 pal[0] = (31 << 11 | 31 << 6 | 31 << 1 | 1);
250 /* second entry */
251 pal[1] = (15 << 11 | 15 << 6 | 15 << 1 | 1);
252 }
253 break;
254 }
255
256 image_size = cpal_formats[idx].size * cpal_formats[idx].num_entries;
257 indices = palette + image_size;
258 for (i = 0; i < SZ; i++) {
259 for (j = 0; j < SZ; j++) {
260 GLfloat d;
261 GLint index;
262 d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
263 d = sqrt(d);
264 index = (d < SZ / 3) ? 0 : 1;
265
266 if (cpal_formats[idx].num_entries == 16) {
267 /* 4-bit indices packed in GLubyte */
268 packed_indices |= index << (4 * (1 - (j % 2)));
269 if (j % 2) {
270 *(indices + (i * SZ + j - 1) / 2) = packed_indices & 0xff;
271 packed_indices = 0;
272 image_size += 1;
273 }
274 }
275 else {
276 /* 8-bit indices */
277 *(indices + i * SZ + j) = index;
278 image_size += 1;
279 }
280 }
281 }
282
283 glActiveTexture(GL_TEXTURE0); /* unit 0 */
284 glBindTexture(GL_TEXTURE_2D, 42);
285 glCompressedTexImage2D(GL_TEXTURE_2D, 0, internalFormat, SZ, SZ, 0,
286 image_size, palette);
287
288 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
289 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
290 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
291 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
292 #undef SZ
293
294 return image_size;
295 }
296
297
298 static GLint
299 make_texture(void)
300 {
301 #define SZ 64
302 GLenum Filter = GL_LINEAR;
303 GLubyte image[SZ][SZ][4];
304 GLuint i, j;
305
306 for (i = 0; i < SZ; i++) {
307 for (j = 0; j < SZ; j++) {
308 GLfloat d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
309 d = sqrt(d);
310 if (d < SZ/3) {
311 image[i][j][0] = 255;
312 image[i][j][1] = 255;
313 image[i][j][2] = 255;
314 image[i][j][3] = 255;
315 }
316 else {
317 image[i][j][0] = 127;
318 image[i][j][1] = 127;
319 image[i][j][2] = 127;
320 image[i][j][3] = 255;
321 }
322 }
323 }
324
325 glActiveTexture(GL_TEXTURE0); /* unit 0 */
326 glBindTexture(GL_TEXTURE_2D, 42);
327 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ, SZ, 0,
328 GL_RGBA, GL_UNSIGNED_BYTE, image);
329 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
330 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
333 #undef SZ
334
335 return sizeof(image);
336 }
337
338
339
340 static void
341 init(void)
342 {
343 static const GLfloat red[4] = {1, 0, 0, 0};
344 static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
345 static const GLfloat diffuse[4] = {0.7, 0.7, 0.7, 1.0};
346 static const GLfloat specular[4] = {0.001, 0.001, 0.001, 1.0};
347 static const GLfloat pos[4] = {20, 20, 50, 1};
348
349 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
350 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
351 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 9.0);
352
353 glEnable(GL_LIGHTING);
354 glEnable(GL_LIGHT0);
355 glLightfv(GL_LIGHT0, GL_POSITION, pos);
356 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
357 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
358
359 glClearColor(0.4, 0.4, 0.4, 0.0);
360 glEnable(GL_DEPTH_TEST);
361
362 make_texture();
363 glEnable(GL_TEXTURE_2D);
364 }
365
366
367 /*
368 * Create an RGB, double-buffered X window.
369 * Return the window and context handles.
370 */
371 static void
372 make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
373 const char *name,
374 int x, int y, int width, int height,
375 Window *winRet,
376 EGLContext *ctxRet,
377 EGLSurface *surfRet)
378 {
379 static const EGLint attribs[] = {
380 EGL_RED_SIZE, 1,
381 EGL_GREEN_SIZE, 1,
382 EGL_BLUE_SIZE, 1,
383 EGL_DEPTH_SIZE, 1,
384 EGL_NONE
385 };
386
387 int scrnum;
388 XSetWindowAttributes attr;
389 unsigned long mask;
390 Window root;
391 Window win;
392 XVisualInfo *visInfo, visTemplate;
393 int num_visuals;
394 EGLContext ctx;
395 EGLConfig config;
396 EGLint num_configs;
397 EGLint vid;
398
399 scrnum = DefaultScreen( x_dpy );
400 root = RootWindow( x_dpy, scrnum );
401
402 if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
403 printf("Error: couldn't get an EGL visual config\n");
404 exit(1);
405 }
406
407 assert(config);
408 assert(num_configs > 0);
409
410 if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
411 printf("Error: eglGetConfigAttrib() failed\n");
412 exit(1);
413 }
414
415 /* The X window visual must match the EGL config */
416 visTemplate.visualid = vid;
417 visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
418 if (!visInfo) {
419 printf("Error: couldn't get X visual\n");
420 exit(1);
421 }
422
423 /* window attributes */
424 attr.background_pixel = 0;
425 attr.border_pixel = 0;
426 attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
427 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
428 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
429
430 win = XCreateWindow( x_dpy, root, 0, 0, width, height,
431 0, visInfo->depth, InputOutput,
432 visInfo->visual, mask, &attr );
433
434 /* set hints and properties */
435 {
436 XSizeHints sizehints;
437 sizehints.x = x;
438 sizehints.y = y;
439 sizehints.width = width;
440 sizehints.height = height;
441 sizehints.flags = USSize | USPosition;
442 XSetNormalHints(x_dpy, win, &sizehints);
443 XSetStandardProperties(x_dpy, win, name, name,
444 None, (char **)NULL, 0, &sizehints);
445 }
446
447 eglBindAPI(EGL_OPENGL_ES_API);
448
449 ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
450 if (!ctx) {
451 printf("Error: eglCreateContext failed\n");
452 exit(1);
453 }
454
455 *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
456
457 if (!*surfRet) {
458 printf("Error: eglCreateWindowSurface failed\n");
459 exit(1);
460 }
461
462 XFree(visInfo);
463
464 *winRet = win;
465 *ctxRet = ctx;
466 }
467
468
469 static void
470 event_loop(Display *dpy, Window win,
471 EGLDisplay egl_dpy, EGLSurface egl_surf)
472 {
473 int anim = 1;
474
475 while (1) {
476 int redraw = 0;
477
478 if (!anim || XPending(dpy)) {
479 XEvent event;
480 XNextEvent(dpy, &event);
481
482 switch (event.type) {
483 case Expose:
484 redraw = 1;
485 break;
486 case ConfigureNotify:
487 reshape(event.xconfigure.width, event.xconfigure.height);
488 break;
489 case KeyPress:
490 {
491 char buffer[10];
492 int r, code;
493 code = XLookupKeysym(&event.xkey, 0);
494 if (code == XK_Left) {
495 view_roty += 5.0;
496 }
497 else if (code == XK_Right) {
498 view_roty -= 5.0;
499 }
500 else if (code == XK_Up) {
501 view_rotx += 5.0;
502 }
503 else if (code == XK_Down) {
504 view_rotx -= 5.0;
505 }
506 else if (code == XK_t) {
507 GLint size;
508 tex_format = (tex_format + 1) % (NUM_CPAL_FORMATS + 1);
509 if (tex_format < NUM_CPAL_FORMATS) {
510 size = make_cpal_texture(tex_format);
511 printf("Using %s (%d bytes)\n",
512 cpal_formats[tex_format].name, size);
513 }
514 else {
515 size = make_texture();
516 printf("Using uncompressed texture (%d bytes)\n", size);
517 }
518 }
519 else {
520 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
521 NULL, NULL);
522 if (buffer[0] == ' ') {
523 anim = !anim;
524 }
525 else if (buffer[0] == 27) {
526 /* escape */
527 return;
528 }
529 }
530 }
531 redraw = 1;
532 break;
533 default:
534 ; /*no-op*/
535 }
536 }
537
538 if (anim) {
539 view_rotx += 1.0;
540 view_roty += 2.0;
541 redraw = 1;
542 }
543
544 if (redraw) {
545 draw();
546 eglSwapBuffers(egl_dpy, egl_surf);
547 }
548 }
549 }
550
551
552 static void
553 usage(void)
554 {
555 printf("Usage:\n");
556 printf(" -display <displayname> set the display to run on\n");
557 printf(" -info display OpenGL renderer info\n");
558 }
559
560
561 int
562 main(int argc, char *argv[])
563 {
564 const int winWidth = 300, winHeight = 300;
565 Display *x_dpy;
566 Window win;
567 EGLSurface egl_surf;
568 EGLContext egl_ctx;
569 EGLDisplay egl_dpy;
570 char *dpyName = NULL;
571 GLboolean printInfo = GL_FALSE;
572 EGLint egl_major, egl_minor;
573 int i;
574 const char *s;
575
576 for (i = 1; i < argc; i++) {
577 if (strcmp(argv[i], "-display") == 0) {
578 dpyName = argv[i+1];
579 i++;
580 }
581 else if (strcmp(argv[i], "-info") == 0) {
582 printInfo = GL_TRUE;
583 }
584 else {
585 usage();
586 return -1;
587 }
588 }
589
590 x_dpy = XOpenDisplay(dpyName);
591 if (!x_dpy) {
592 printf("Error: couldn't open display %s\n",
593 dpyName ? dpyName : getenv("DISPLAY"));
594 return -1;
595 }
596
597 egl_dpy = eglGetDisplay(x_dpy);
598 if (!egl_dpy) {
599 printf("Error: eglGetDisplay() failed\n");
600 return -1;
601 }
602
603 if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
604 printf("Error: eglInitialize() failed\n");
605 return -1;
606 }
607
608 s = eglQueryString(egl_dpy, EGL_VERSION);
609 printf("EGL_VERSION = %s\n", s);
610
611 s = eglQueryString(egl_dpy, EGL_VENDOR);
612 printf("EGL_VENDOR = %s\n", s);
613
614 s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
615 printf("EGL_EXTENSIONS = %s\n", s);
616
617 s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
618 printf("EGL_CLIENT_APIS = %s\n", s);
619
620 make_x_window(x_dpy, egl_dpy,
621 "torus", 0, 0, winWidth, winHeight,
622 &win, &egl_ctx, &egl_surf);
623
624 XMapWindow(x_dpy, win);
625 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
626 printf("Error: eglMakeCurrent() failed\n");
627 return -1;
628 }
629
630 if (printInfo) {
631 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
632 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
633 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
634 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
635 }
636
637 init();
638
639 /* Set initial projection/viewing transformation.
640 * We can't be sure we'll get a ConfigureNotify event when the window
641 * first appears.
642 */
643 reshape(winWidth, winHeight);
644
645 event_loop(x_dpy, win, egl_dpy, egl_surf);
646
647 eglDestroyContext(egl_dpy, egl_ctx);
648 eglDestroySurface(egl_dpy, egl_surf);
649 eglTerminate(egl_dpy);
650
651
652 XDestroyWindow(x_dpy, win);
653 XCloseDisplay(x_dpy);
654
655 return 0;
656 }