summaryrefslogtreecommitdiffstats
path: root/progs/xdemos
diff options
context:
space:
mode:
authorThierry Reding <[email protected]>2006-10-14 03:46:41 +0000
committerThierry Reding <[email protected]>2006-10-14 03:46:41 +0000
commit1ddf606332a188e46a47607cd41eb5d81bdf4c8a (patch)
tree8cb51078803106d87aedeae7bbd7a762a0d369d1 /progs/xdemos
Import Mesa 6.5.1 (MesaLib, MesaDemos, MesaGLUT).
Diffstat (limited to 'progs/xdemos')
-rw-r--r--progs/xdemos/Makefile83
-rw-r--r--progs/xdemos/descrip.mms83
-rw-r--r--progs/xdemos/glthreads.c544
-rw-r--r--progs/xdemos/glxcontexts.c609
-rw-r--r--progs/xdemos/glxdemo.c127
-rw-r--r--progs/xdemos/glxgears.c621
-rw-r--r--progs/xdemos/glxgears2.c522
-rw-r--r--progs/xdemos/glxgears_fbconfig.c602
-rw-r--r--progs/xdemos/glxheads.c286
-rw-r--r--progs/xdemos/glxinfo.c956
-rw-r--r--progs/xdemos/glxpbdemo.c430
-rw-r--r--progs/xdemos/glxpixmap.c186
-rw-r--r--progs/xdemos/glxswapcontrol.c824
-rw-r--r--progs/xdemos/manywin.c393
-rw-r--r--progs/xdemos/offset.c323
-rw-r--r--progs/xdemos/opencloseopen.c189
-rw-r--r--progs/xdemos/overlay.c245
-rw-r--r--progs/xdemos/pbdemo.c478
-rw-r--r--progs/xdemos/pbinfo.c106
-rw-r--r--progs/xdemos/pbutil.c426
-rw-r--r--progs/xdemos/pbutil.h66
-rw-r--r--progs/xdemos/shape.c394
-rw-r--r--progs/xdemos/vgears.c282
-rw-r--r--progs/xdemos/vindex.c65
-rw-r--r--progs/xdemos/vtest.c82
-rw-r--r--progs/xdemos/wincopy.c329
-rw-r--r--progs/xdemos/xdemo.c334
-rw-r--r--progs/xdemos/xfont.c206
-rw-r--r--progs/xdemos/xrotfontdemo.c220
-rw-r--r--progs/xdemos/xuserotfont.c399
-rw-r--r--progs/xdemos/xuserotfont.h12
-rw-r--r--progs/xdemos/yuvrect_client.c326
32 files changed, 10748 insertions, 0 deletions
diff --git a/progs/xdemos/Makefile b/progs/xdemos/Makefile
new file mode 100644
index 00000000000..4ca8b107a24
--- /dev/null
+++ b/progs/xdemos/Makefile
@@ -0,0 +1,83 @@
+# progs/xdemos/Makefile
+
+TOP = ../..
+include $(TOP)/configs/current
+
+
+INCDIR = $(TOP)/include
+
+LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME)
+
+PROGS = glthreads \
+ glxdemo \
+ glxgears \
+ glxgears_fbconfig \
+ glxcontexts \
+ glxheads \
+ glxinfo \
+ glxpixmap \
+ glxpbdemo \
+ glxswapcontrol \
+ manywin \
+ offset \
+ overlay \
+ pbinfo \
+ pbdemo \
+ wincopy \
+ xdemo \
+ xfont \
+ xrotfontdemo \
+ yuvrect_client
+
+
+
+##### RULES #####
+
+.SUFFIXES:
+.SUFFIXES: .c
+
+.c: $(LIB_DEP)
+ $(CC) -I$(INCDIR) $(CFLAGS) $< $(APP_LIB_DEPS) -o $@
+
+
+##### TARGETS #####
+
+default: $(PROGS)
+
+
+clean:
+ -rm -f $(PROGS)
+ -rm -f *.o *~
+
+
+# special cases
+pbinfo: pbinfo.o pbutil.o
+ $(CC) -I$(INCDIR) $(CFLAGS) pbinfo.o pbutil.o $(APP_LIB_DEPS) -o $@
+
+pbdemo: pbdemo.o pbutil.o
+ $(CC) -I$(INCDIR) $(CFLAGS) pbdemo.o pbutil.o $(APP_LIB_DEPS) -o $@
+
+pbinfo.o: pbinfo.c pbutil.h
+ $(CC) -c -I. -I$(INCDIR) $(CFLAGS) pbinfo.c
+
+pbdemo.o: pbdemo.c pbutil.h
+ $(CC) -c -I. -I$(INCDIR) $(CFLAGS) pbdemo.c
+
+pbutil.o: pbutil.c pbutil.h
+ $(CC) -c -I. -I$(INCDIR) $(CFLAGS) pbutil.c
+
+glxgears_fbconfig: glxgears_fbconfig.o pbutil.o
+ $(CC) -I$(INCDIR) $(CFLAGS) glxgears_fbconfig.o pbutil.o $(APP_LIB_DEPS) -o $@
+
+glxgears_fbconfig.o: glxgears_fbconfig.c pbutil.h
+ $(CC) -I$(INCDIR) $(CFLAGS) -c -I. $(CFLAGS) glxgears_fbconfig.c
+
+xrotfontdemo: xrotfontdemo.o xuserotfont.o
+ $(CC) -I$(INCDIR) $(CFLAGS) xrotfontdemo.o xuserotfont.o $(APP_LIB_DEPS) -o $@
+
+xuserotfont.o: xuserotfont.c xuserotfont.h
+ $(CC) -c -I. -I$(INCDIR) $(CFLAGS) xuserotfont.c
+
+xrotfontdemo.o: xrotfontdemo.c xuserotfont.h
+ $(CC) -c -I. -I$(INCDIR) $(CFLAGS) xrotfontdemo.c
+
diff --git a/progs/xdemos/descrip.mms b/progs/xdemos/descrip.mms
new file mode 100644
index 00000000000..aa74daff599
--- /dev/null
+++ b/progs/xdemos/descrip.mms
@@ -0,0 +1,83 @@
+# Makefile for GLUT-based demo programs for VMS
+# contributed by Jouk Jansen [email protected]
+
+
+.first
+ define gl [--.include.gl]
+
+.include [--]mms-config.
+
+##### MACROS #####
+
+INCDIR = ([--.include],[-.util])
+CFLAGS = /include=$(INCDIR)/prefix=all/name=(as_is,short)/nowarn/float=ieee/ieee=denorm
+
+.ifdef SHARE
+GL_LIBS = $(XLIBS)
+.else
+GL_LIBS = [--.lib]libGLUT/l,libMesaGLU/l,libMesaGL/l,$(XLIBS)
+.endif
+
+LIB_DEP = [--.lib]$(GL_LIB) [--.lib]$(GLU_LIB) [--.lib]$(GLUT_LIB)
+
+PROGS =glthreads.exe,\
+ glxdemo.exe,\
+ glxgears.exe,\
+ glxheads.exe,\
+ glxinfo.exe,\
+ glxpixmap.exe,\
+ manywin.exe,\
+ offset.exe,\
+ pbinfo.exe,\
+ pbdemo.exe,\
+ wincopy.exe,\
+ xdemo.exe,\
+ xfont.exe
+
+##### RULES #####
+.obj.exe :
+ cxxlink $(MMS$TARGET_NAME),$(GL_LIBS)
+
+##### TARGETS #####
+default :
+ $(MMS)$(MMSQUALIFIERS) $(PROGS)
+
+clean :
+ delete *.obj;*
+
+realclean :
+ delete $(PROGS)
+ delete *.obj;*
+
+
+glthreads.exe : glthreads.obj $(LIB_DEP)
+glxdemo.exe : glxdemo.obj $(LIB_DEP)
+glxgears.exe : glxgears.obj $(LIB_DEP)
+glxheads.exe : glxheads.obj $(LIB_DEP)
+glxinfo.exe : glxinfo.obj $(LIB_DEP)
+glxpixmap.exe : glxpixmap.obj $(LIB_DEP)
+manywin.exe : manywin.obj $(LIB_DEP)
+offset.exe : offset.obj $(LIB_DEP)
+pbinfo.exe : pbinfo.obj pbutil.obj $(LIB_DEP)
+ cxxlink pbinfo.obj,pbutil.obj,$(GL_LIBS)
+pbdemo.exe : pbdemo.obj pbutil.obj $(LIB_DEP)
+ cxxlink pbdemo.obj,pbutil.obj,$(GL_LIBS)
+wincopy.exe : wincopy.obj $(LIB_DEP)
+xdemo.exe : xdemo.obj $(LIB_DEP)
+xfont.exe :xfont.obj $(LIB_DEP)
+
+
+glthreads.obj : glthreads.c
+glxdemo.obj : glxdemo.c
+glxgears.obj : glxgears.c
+glxheads.obj : glxheads.c
+glxinfo.obj : glxinfo.c
+glxpixmap.obj : glxpixmap.c
+manywin.obj : manywin.c
+offset.obj : offset.c
+pbinfo.obj : pbinfo.c
+pbutil.obj : pbutil.c
+pbdemo.obj : pbdemo.c
+wincopy.obj : wincopy.c
+xdemo.obj : xdemo.c
+xfont.obj :xfont.c
diff --git a/progs/xdemos/glthreads.c b/progs/xdemos/glthreads.c
new file mode 100644
index 00000000000..83413383dd4
--- /dev/null
+++ b/progs/xdemos/glthreads.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * This program tests GLX thread safety.
+ * Command line options:
+ * -p Open a display connection for each thread
+ * -n <num threads> Number of threads to create (default is 2)
+ * -display <display name> Specify X display (default is :0.0)
+ *
+ * Brian Paul 20 July 2000
+ */
+
+
+#if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */
+
+#include <assert.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+
+
+/*
+ * Each window/thread/context:
+ */
+struct winthread {
+ Display *Dpy;
+ int Index;
+ pthread_t Thread;
+ Window Win;
+ GLXContext Context;
+ float Angle;
+ int WinWidth, WinHeight;
+ GLboolean NewSize;
+};
+
+
+#define MAX_WINTHREADS 100
+static struct winthread WinThreads[MAX_WINTHREADS];
+static int NumWinThreads = 0;
+static volatile GLboolean ExitFlag = GL_FALSE;
+
+static GLboolean MultiDisplays = 0;
+static GLboolean Locking = 0;
+
+static pthread_mutex_t Mutex;
+
+
+static void
+Error(const char *msg)
+{
+ fprintf(stderr, "Error: %s\n", msg);
+ exit(1);
+}
+
+
+/* draw a colored cube */
+static void
+draw_object(void)
+{
+ glPushMatrix();
+ glScalef(0.75, 0.75, 0.75);
+
+ glColor3f(1, 0, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(1, -1, -1);
+ glVertex3f(1, 1, -1);
+ glVertex3f(1, 1, 1);
+ glVertex3f(1, -1, 1);
+ glEnd();
+
+ glColor3f(0, 1, 1);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, -1);
+ glVertex3f(-1, 1, -1);
+ glVertex3f(-1, 1, 1);
+ glVertex3f(-1, -1, 1);
+ glEnd();
+
+ glColor3f(0, 1, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, 1, -1);
+ glVertex3f( 1, 1, -1);
+ glVertex3f( 1, 1, 1);
+ glVertex3f(-1, 1, 1);
+ glEnd();
+
+ glColor3f(1, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, -1);
+ glVertex3f( 1, -1, -1);
+ glVertex3f( 1, -1, 1);
+ glVertex3f(-1, -1, 1);
+ glEnd();
+
+ glColor3f(0, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, 1);
+ glVertex3f( 1, -1, 1);
+ glVertex3f( 1, 1, 1);
+ glVertex3f(-1, 1, 1);
+ glEnd();
+
+ glColor3f(1, 1, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, -1);
+ glVertex3f( 1, -1, -1);
+ glVertex3f( 1, 1, -1);
+ glVertex3f(-1, 1, -1);
+ glEnd();
+ glPopMatrix();
+}
+
+
+/* signal resize of given window */
+static void
+resize(struct winthread *wt, int w, int h)
+{
+ wt->NewSize = GL_TRUE;
+ wt->WinWidth = w;
+ wt->WinHeight = h;
+}
+
+
+/*
+ * We have an instance of this for each thread.
+ */
+static void
+draw_loop(struct winthread *wt)
+{
+ GLboolean firstIter = GL_TRUE;
+
+ while (!ExitFlag) {
+
+ if (Locking)
+ pthread_mutex_lock(&Mutex);
+
+ glXMakeCurrent(wt->Dpy, wt->Win, wt->Context);
+ if (firstIter) {
+ printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index,
+ (char *) glGetString(GL_RENDERER));
+ firstIter = GL_FALSE;
+ }
+
+ if (Locking)
+ pthread_mutex_unlock(&Mutex);
+
+ glEnable(GL_DEPTH_TEST);
+
+ if (wt->NewSize) {
+ GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
+ glViewport(0, 0, wt->WinWidth, wt->WinHeight);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0, 0, -2.5);
+ wt->NewSize = GL_FALSE;
+ }
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(wt->Angle, 0, 0, 1);
+ glRotatef(wt->Angle, 1, 0, 0);
+ glScalef(0.7, 0.7, 0.7);
+ draw_object();
+ glPopMatrix();
+
+ if (Locking)
+ pthread_mutex_lock(&Mutex);
+
+ glXSwapBuffers(wt->Dpy, wt->Win);
+
+ if (Locking)
+ pthread_mutex_unlock(&Mutex);
+
+ usleep(5000);
+ wt->Angle += 1.0;
+ }
+}
+
+
+/*
+ * The main process thread runs this loop.
+ * Single display connection for all threads.
+ */
+static void
+event_loop(Display *dpy)
+{
+ XEvent event;
+ int i;
+
+ assert(!MultiDisplays);
+
+ while (!ExitFlag) {
+
+ if (Locking) {
+ while (1) {
+ int k;
+ pthread_mutex_lock(&Mutex);
+ k = XPending(dpy);
+ if (k) {
+ XNextEvent(dpy, &event);
+ pthread_mutex_unlock(&Mutex);
+ break;
+ }
+ pthread_mutex_unlock(&Mutex);
+ usleep(5000);
+ }
+ }
+ else {
+ XNextEvent(dpy, &event);
+ }
+
+ switch (event.type) {
+ case ConfigureNotify:
+ /* Find winthread for this event's window */
+ for (i = 0; i < NumWinThreads; i++) {
+ struct winthread *wt = &WinThreads[i];
+ if (event.xconfigure.window == wt->Win) {
+ resize(wt, event.xconfigure.width,
+ event.xconfigure.height);
+ break;
+ }
+ }
+ break;
+ case KeyPress:
+ /* tell all threads to exit */
+ ExitFlag = GL_TRUE;
+ /*printf("exit draw_loop %d\n", wt->Index);*/
+ return;
+ default:
+ /*no-op*/ ;
+ }
+ }
+}
+
+
+/*
+ * Separate display connection for each thread.
+ */
+static void
+event_loop_multi(void)
+{
+ XEvent event;
+ int w = 0;
+
+ assert(MultiDisplays);
+
+ while (!ExitFlag) {
+ struct winthread *wt = &WinThreads[w];
+ if (XPending(wt->Dpy)) {
+ XNextEvent(wt->Dpy, &event);
+ switch (event.type) {
+ case ConfigureNotify:
+ resize(wt, event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ /* tell all threads to exit */
+ ExitFlag = GL_TRUE;
+ /*printf("exit draw_loop %d\n", wt->Index);*/
+ return;
+ default:
+ /*no-op*/ ;
+ }
+ }
+ w = (w + 1) % NumWinThreads;
+ usleep(5000);
+ }
+}
+
+
+
+/*
+ * we'll call this once for each thread, before the threads are created.
+ */
+static void
+create_window(struct winthread *wt)
+{
+ Window win;
+ GLXContext ctx;
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ XVisualInfo *visinfo;
+ int width = 80, height = 80;
+ int xpos = (wt->Index % 10) * 90;
+ int ypos = (wt->Index / 10) * 100;
+
+ scrnum = DefaultScreen(wt->Dpy);
+ root = RootWindow(wt->Dpy, scrnum);
+
+ visinfo = glXChooseVisual(wt->Dpy, scrnum, attrib);
+ if (!visinfo) {
+ Error("Unable to find RGB, Z, double-buffered visual");
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(wt->Dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(wt->Dpy, root, xpos, ypos, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+ if (!win) {
+ Error("Couldn't create window");
+ }
+
+ {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(wt->Dpy, win, &sizehints);
+ XSetStandardProperties(wt->Dpy, win, "glthreads", "glthreads",
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ ctx = glXCreateContext(wt->Dpy, visinfo, NULL, True);
+ if (!ctx) {
+ Error("Couldn't create GLX context");
+ }
+
+ XMapWindow(wt->Dpy, win);
+ XSync(wt->Dpy, 0);
+
+ /* save the info for this window/context */
+ wt->Win = win;
+ wt->Context = ctx;
+ wt->Angle = 0.0;
+ wt->WinWidth = width;
+ wt->WinHeight = height;
+ wt->NewSize = GL_TRUE;
+}
+
+
+/*
+ * Called by pthread_create()
+ */
+static void *
+thread_function(void *p)
+{
+ struct winthread *wt = (struct winthread *) p;
+ draw_loop(wt);
+ return NULL;
+}
+
+
+/*
+ * called before exit to wait for all threads to finish
+ */
+static void
+clean_up(void)
+{
+ int i;
+
+ /* wait for threads to finish */
+ for (i = 0; i < NumWinThreads; i++) {
+ pthread_join(WinThreads[i].Thread, NULL);
+ }
+
+ for (i = 0; i < NumWinThreads; i++) {
+ glXDestroyContext(WinThreads[i].Dpy, WinThreads[i].Context);
+ XDestroyWindow(WinThreads[i].Dpy, WinThreads[i].Win);
+ }
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+ char *displayName = ":0.0";
+ int numThreads = 2;
+ Display *dpy = NULL;
+ int i;
+ Status threadStat;
+
+ if (argc == 1) {
+ printf("glthreads: test of GL thread safety (any key = exit)\n");
+ printf("Usage:\n");
+ printf(" glthreads [-display dpyName] [-n numthreads]\n");
+ }
+ else {
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
+ displayName = argv[i + 1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-p") == 0) {
+ MultiDisplays = 1;
+ }
+ else if (strcmp(argv[i], "-l") == 0) {
+ Locking = 1;
+ }
+ else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
+ numThreads = atoi(argv[i + 1]);
+ if (numThreads < 1)
+ numThreads = 1;
+ else if (numThreads > MAX_WINTHREADS)
+ numThreads = MAX_WINTHREADS;
+ i++;
+ }
+ else {
+ fprintf(stderr, "glthreads: unexpected flag: %s\n", argv[i]);
+ }
+ }
+ }
+
+ if (Locking)
+ printf("glthreads: Using explict locks around Xlib calls.\n");
+ else
+ printf("glthreads: No explict locking.\n");
+
+ if (MultiDisplays)
+ printf("glthreads: Per-thread display connections.\n");
+ else
+ printf("glthreads: Single display connection.\n");
+
+ /*
+ * VERY IMPORTANT: call XInitThreads() before any other Xlib functions.
+ */
+ if (!MultiDisplays) {
+ if (!Locking) {
+ threadStat = XInitThreads();
+ if (threadStat) {
+ printf("XInitThreads() returned %d (success)\n", (int) threadStat);
+ }
+ else {
+ printf("XInitThreads() returned 0 (failure- this program may fail)\n");
+ }
+ }
+
+ dpy = XOpenDisplay(displayName);
+ if (!dpy) {
+ fprintf(stderr, "Unable to open display %s\n", displayName);
+ return -1;
+ }
+ }
+
+ if (Locking) {
+ pthread_mutex_init(&Mutex, NULL);
+ }
+
+ printf("glthreads: creating windows\n");
+
+ NumWinThreads = numThreads;
+
+ /* Create the GLX windows and contexts */
+ for (i = 0; i < numThreads; i++) {
+ if (MultiDisplays) {
+ WinThreads[i].Dpy = XOpenDisplay(displayName);
+ assert(WinThreads[i].Dpy);
+ }
+ else {
+ WinThreads[i].Dpy = dpy;
+ }
+ WinThreads[i].Index = i;
+ create_window(&WinThreads[i]);
+ }
+
+ printf("glthreads: creating threads\n");
+
+ /* Create the threads */
+ for (i = 0; i < numThreads; i++) {
+ pthread_create(&WinThreads[i].Thread, NULL, thread_function,
+ (void*) &WinThreads[i]);
+ printf("glthreads: Created thread %u\n", (unsigned int) WinThreads[i].Thread);
+ }
+
+ if (MultiDisplays)
+ event_loop_multi();
+ else
+ event_loop(dpy);
+
+ clean_up();
+
+ if (MultiDisplays) {
+ for (i = 0; i < numThreads; i++) {
+ XCloseDisplay(WinThreads[i].Dpy);
+ }
+ }
+ else {
+ XCloseDisplay(dpy);
+ }
+
+ return 0;
+}
+
+
+#else /* PTHREADS */
+
+
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+ printf("Sorry, this program wasn't compiled with PTHREADS defined.\n");
+ return 0;
+}
+
+
+#endif /* PTHREADS */
diff --git a/progs/xdemos/glxcontexts.c b/progs/xdemos/glxcontexts.c
new file mode 100644
index 00000000000..fbc296ef625
--- /dev/null
+++ b/progs/xdemos/glxcontexts.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
+ * Port by Brian Paul 23 March 2001
+ *
+ * Command line options:
+ * -info print GL implementation information
+ * -stereo use stereo enabled GLX visual
+ *
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+
+#define BENCHMARK
+
+#ifdef BENCHMARK
+
+/* XXX this probably isn't very portable */
+
+#include <sys/time.h>
+#include <unistd.h>
+
+/* return current time (in seconds) */
+static double
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+#else /*BENCHMARK*/
+
+/* dummy */
+static double
+current_time(void)
+{
+ /* update this function for other platforms! */
+ static double t = 0.0;
+ static int warn = 1;
+ if (warn) {
+ fprintf(stderr, "Warning: current_time() not implemented!!\n");
+ warn = 0;
+ }
+ return t += 1.0;
+}
+
+#endif /*BENCHMARK*/
+
+
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+
+static GLboolean fullscreen = GL_FALSE; /* Create a single fullscreen window */
+static GLboolean stereo = GL_FALSE; /* Enable stereo. */
+static GLfloat eyesep = 5.0; /* Eye separation. */
+static GLfloat fix_point = 40.0; /* Fixation point distance. */
+static GLfloat left, right, asp; /* Stereo frustum params. */
+
+ XVisualInfo *visinfo;
+
+
+/*
+ *
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void
+gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ glShadeModel(GL_FLAT);
+
+ glNormal3f(0.0, 0.0, 1.0);
+
+ /* draw front face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ glEnd();
+
+ glNormal3f(0.0, 0.0, -1.0);
+
+ /* draw back face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ }
+ glEnd();
+
+ /* draw outward faces of teeth */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ u = r2 * cos(angle + da) - r1 * cos(angle);
+ v = r2 * sin(angle + da) - r1 * sin(angle);
+ len = sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
+ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ }
+
+ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
+ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
+
+ glEnd();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glNormal3f(-cos(angle), -sin(angle), 0.0);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ }
+ glEnd();
+}
+
+
+static void
+do_draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(view_rotx, 1.0, 0.0, 0.0);
+ glRotatef(view_roty, 0.0, 1.0, 0.0);
+ glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+ glPushMatrix();
+ glTranslatef(-3.0, -2.0, 0.0);
+ glRotatef(angle, 0.0, 0.0, 1.0);
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(3.1, -2.0, 0.0);
+ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(-3.1, 4.2, 0.0);
+ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+}
+
+
+
+/* new window size or exposure */
+static void
+reshape(int width, int height)
+{
+ glViewport(0, 0, (GLint) width, (GLint) height);
+
+ if (stereo) {
+ GLfloat w;
+
+ asp = (GLfloat) height / (GLfloat) width;
+ w = fix_point * (1.0 / 5.0);
+
+ left = -5.0 * ((w - 0.5 * eyesep) / fix_point);
+ right = 5.0 * ((w + 0.5 * eyesep) / fix_point);
+ } else {
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+}
+
+
+
+static void
+init(void)
+{
+ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0, 4.0, 1.0, 20, 0.7);
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5, 2.0, 2.0, 10, 0.7);
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3, 2.0, 0.5, 10, 0.7);
+ glEndList();
+
+ glEnable(GL_NORMALIZE);
+}
+
+
+static void
+draw( Display *dpy, Window win )
+{
+ GLXContext ctx;
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ glXMakeCurrent(dpy, win, ctx);
+
+ init();
+
+ if (stereo) {
+ /* First left eye. */
+ glDrawBuffer(GL_BACK_LEFT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(left, right, -asp, asp, 5.0, 60.0);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glPushMatrix();
+ glTranslated(+0.5 * eyesep, 0.0, 0.0);
+ do_draw();
+ glPopMatrix();
+
+ /* Then right eye. */
+ glDrawBuffer(GL_BACK_RIGHT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-right, -left, -asp, asp, 5.0, 60.0);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glPushMatrix();
+ glTranslated(-0.5 * eyesep, 0.0, 0.0);
+ do_draw();
+ glPopMatrix();
+ } else
+ do_draw();
+
+ glXSwapBuffers(dpy, win);
+ glXDestroyContext(dpy, ctx);
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet)
+{
+ int attribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ int stereoAttribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ GLX_STEREO,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ if (fullscreen) {
+ x = 0; y = 0;
+ width = DisplayWidth( dpy, scrnum );
+ height = DisplayHeight( dpy, scrnum );
+ }
+
+ if (stereo)
+ visinfo = glXChooseVisual( dpy, scrnum, stereoAttribs );
+ else
+ visinfo = glXChooseVisual( dpy, scrnum, attribs );
+ if (!visinfo) {
+ if (stereo) {
+ printf("Error: couldn't get an RGB, "
+ "Double-buffered, Stereo visual\n");
+ } else
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ attr.override_redirect = fullscreen;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
+
+ win = XCreateWindow( dpy, root, x, y, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ *winRet = win;
+}
+
+
+static void
+event_loop(Display *dpy)
+{
+ Window win;
+ make_window(dpy, "glxgears", 0, 0, 300, 300, &win);
+ XMapWindow(dpy, win);
+
+
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ if (code == XK_Left) {
+ view_roty += 5.0;
+ }
+ else if (code == XK_Right) {
+ view_roty -= 5.0;
+ }
+ else if (code == XK_Up) {
+ view_rotx += 5.0;
+ }
+ else if (code == XK_Down) {
+ view_rotx -= 5.0;
+ }
+ else {
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ {
+ static int frames = 0;
+ static double tRot0 = -1.0, tRate0 = -1.0;
+ double dt, t = current_time();
+ if (tRot0 < 0.0)
+ tRot0 = t;
+ dt = t - tRot0;
+ tRot0 = t;
+
+ /* advance rotation for next frame */
+ angle += 70.0 * dt; /* 70 degrees per second */
+ if (angle > 3600.0)
+ angle -= 3600.0;
+
+ draw( dpy, win );
+
+ frames++;
+
+ if (tRate0 < 0.0)
+ tRate0 = t;
+
+ if (t - tRate0 >= 1.0) {
+ GLfloat seconds = t - tRate0;
+ GLfloat fps = frames / seconds;
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
+ fps);
+ tRate0 = t;
+
+ XDestroyWindow(dpy, win);
+ make_window(dpy, "glxgears", (int)(fps * 100) % 100, (int)(fps * 100) % 100, 300, 300, &win);
+ XMapWindow(dpy, win);
+
+ frames = 0;
+ }
+ }
+ }
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ char *dpyName = NULL;
+ GLboolean printInfo = GL_FALSE;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-stereo") == 0) {
+ stereo = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-fullscreen") == 0) {
+ fullscreen = GL_TRUE;
+ }
+ else
+ printf("Warrning: unknown parameter: %s\n", argv[i]);
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n",
+ dpyName ? dpyName : getenv("DISPLAY"));
+ return -1;
+ }
+
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+
+ event_loop(dpy);
+
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/progs/xdemos/glxdemo.c b/progs/xdemos/glxdemo.c
new file mode 100644
index 00000000000..37df64ebee8
--- /dev/null
+++ b/progs/xdemos/glxdemo.c
@@ -0,0 +1,127 @@
+
+
+/*
+ * A demonstration of using the GLX functions. This program is in the
+ * public domain.
+ *
+ * Brian Paul
+ */
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+static void redraw( Display *dpy, Window w )
+{
+ printf("Redraw event\n");
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glColor3f( 1.0, 1.0, 0.0 );
+ glRectf( -0.8, -0.8, 0.8, 0.8 );
+
+ glXSwapBuffers( dpy, w );
+}
+
+
+
+static void resize( unsigned int width, unsigned int height )
+{
+ printf("Resize event\n");
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
+}
+
+
+
+static Window make_rgb_db_window( Display *dpy,
+ unsigned int width, unsigned int height )
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ glXMakeCurrent( dpy, win, ctx );
+
+ return win;
+}
+
+
+static void event_loop( Display *dpy )
+{
+ XEvent event;
+
+ while (1) {
+ XNextEvent( dpy, &event );
+
+ switch (event.type) {
+ case Expose:
+ redraw( dpy, event.xany.window );
+ break;
+ case ConfigureNotify:
+ resize( event.xconfigure.width, event.xconfigure.height );
+ break;
+ }
+ }
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ Display *dpy;
+ Window win;
+
+ dpy = XOpenDisplay(NULL);
+
+ win = make_rgb_db_window( dpy, 300, 300 );
+
+ glShadeModel( GL_FLAT );
+ glClearColor( 0.5, 0.5, 0.5, 1.0 );
+
+ XMapWindow( dpy, win );
+
+ event_loop( dpy );
+ return 0;
+}
diff --git a/progs/xdemos/glxgears.c b/progs/xdemos/glxgears.c
new file mode 100644
index 00000000000..75d63e51a2e
--- /dev/null
+++ b/progs/xdemos/glxgears.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
+ * Port by Brian Paul 23 March 2001
+ *
+ * Command line options:
+ * -info print GL implementation information
+ * -stereo use stereo enabled GLX visual
+ *
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+
+#define BENCHMARK
+
+#ifdef BENCHMARK
+
+/* XXX this probably isn't very portable */
+
+#include <sys/time.h>
+#include <unistd.h>
+
+/* return current time (in seconds) */
+static double
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+#else /*BENCHMARK*/
+
+/* dummy */
+static double
+current_time(void)
+{
+ /* update this function for other platforms! */
+ static double t = 0.0;
+ static int warn = 1;
+ if (warn) {
+ fprintf(stderr, "Warning: current_time() not implemented!!\n");
+ warn = 0;
+ }
+ return t += 1.0;
+}
+
+#endif /*BENCHMARK*/
+
+
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+
+static GLboolean fullscreen = GL_FALSE; /* Create a single fullscreen window */
+static GLboolean stereo = GL_FALSE; /* Enable stereo. */
+static GLfloat eyesep = 5.0; /* Eye separation. */
+static GLfloat fix_point = 40.0; /* Fixation point distance. */
+static GLfloat left, right, asp; /* Stereo frustum params. */
+
+
+/*
+ *
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void
+gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ glShadeModel(GL_FLAT);
+
+ glNormal3f(0.0, 0.0, 1.0);
+
+ /* draw front face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ glEnd();
+
+ glNormal3f(0.0, 0.0, -1.0);
+
+ /* draw back face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ }
+ glEnd();
+
+ /* draw outward faces of teeth */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ u = r2 * cos(angle + da) - r1 * cos(angle);
+ v = r2 * sin(angle + da) - r1 * sin(angle);
+ len = sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
+ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ }
+
+ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
+ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
+
+ glEnd();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glNormal3f(-cos(angle), -sin(angle), 0.0);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ }
+ glEnd();
+}
+
+
+static void
+do_draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(view_rotx, 1.0, 0.0, 0.0);
+ glRotatef(view_roty, 0.0, 1.0, 0.0);
+ glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+ glPushMatrix();
+ glTranslatef(-3.0, -2.0, 0.0);
+ glRotatef(angle, 0.0, 0.0, 1.0);
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(3.1, -2.0, 0.0);
+ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(-3.1, 4.2, 0.0);
+ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+}
+
+static void
+draw(void)
+{
+ if (stereo) {
+ /* First left eye. */
+ glDrawBuffer(GL_BACK_LEFT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(left, right, -asp, asp, 5.0, 60.0);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glPushMatrix();
+ glTranslated(+0.5 * eyesep, 0.0, 0.0);
+ do_draw();
+ glPopMatrix();
+
+ /* Then right eye. */
+ glDrawBuffer(GL_BACK_RIGHT);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-right, -left, -asp, asp, 5.0, 60.0);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glPushMatrix();
+ glTranslated(-0.5 * eyesep, 0.0, 0.0);
+ do_draw();
+ glPopMatrix();
+ } else
+ do_draw();
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int width, int height)
+{
+ glViewport(0, 0, (GLint) width, (GLint) height);
+
+ if (stereo) {
+ GLfloat w;
+
+ asp = (GLfloat) height / (GLfloat) width;
+ w = fix_point * (1.0 / 5.0);
+
+ left = -5.0 * ((w - 0.5 * eyesep) / fix_point);
+ right = 5.0 * ((w + 0.5 * eyesep) / fix_point);
+ } else {
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+}
+
+
+
+static void
+init(void)
+{
+ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0, 4.0, 1.0, 20, 0.7);
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5, 2.0, 2.0, 10, 0.7);
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3, 2.0, 0.5, 10, 0.7);
+ glEndList();
+
+ glEnable(GL_NORMALIZE);
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet)
+{
+ int attribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ int stereoAttribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ GLX_STEREO,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ if (fullscreen) {
+ x = 0; y = 0;
+ width = DisplayWidth( dpy, scrnum );
+ height = DisplayHeight( dpy, scrnum );
+ }
+
+ if (stereo)
+ visinfo = glXChooseVisual( dpy, scrnum, stereoAttribs );
+ else
+ visinfo = glXChooseVisual( dpy, scrnum, attribs );
+ if (!visinfo) {
+ if (stereo) {
+ printf("Error: couldn't get an RGB, "
+ "Double-buffered, Stereo visual\n");
+ } else
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ attr.override_redirect = fullscreen;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win)
+{
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ if (code == XK_Left) {
+ view_roty += 5.0;
+ }
+ else if (code == XK_Right) {
+ view_roty -= 5.0;
+ }
+ else if (code == XK_Up) {
+ view_rotx += 5.0;
+ }
+ else if (code == XK_Down) {
+ view_rotx -= 5.0;
+ }
+ else {
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ {
+ static int frames = 0;
+ static double tRot0 = -1.0, tRate0 = -1.0;
+ double dt, t = current_time();
+ if (tRot0 < 0.0)
+ tRot0 = t;
+ dt = t - tRot0;
+ tRot0 = t;
+
+ /* advance rotation for next frame */
+ angle += 70.0 * dt; /* 70 degrees per second */
+ if (angle > 3600.0)
+ angle -= 3600.0;
+
+ draw();
+ glXSwapBuffers(dpy, win);
+
+ frames++;
+
+ if (tRate0 < 0.0)
+ tRate0 = t;
+ if (t - tRate0 >= 5.0) {
+ GLfloat seconds = t - tRate0;
+ GLfloat fps = frames / seconds;
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
+ fps);
+ tRate0 = t;
+ frames = 0;
+ }
+ }
+ }
+}
+
+
+static void
+usage(void)
+{
+ printf("Usage:\n");
+ printf(" -display <displayname> set the display to run on\n");
+ printf(" -stereo run in stereo mode\n");
+ printf(" -fullscreen run in fullscreen mode\n");
+ printf(" -info display OpenGL renderer info\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ const int winWidth = 300, winHeight = 300;
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ char *dpyName = NULL;
+ GLboolean printInfo = GL_FALSE;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-stereo") == 0) {
+ stereo = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-fullscreen") == 0) {
+ fullscreen = GL_TRUE;
+ }
+ else {
+ usage();
+ return -1;
+ }
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n",
+ dpyName ? dpyName : getenv("DISPLAY"));
+ return -1;
+ }
+
+ make_window(dpy, "glxgears", 0, 0, winWidth, winHeight, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+ init();
+
+ /* Set initial projection/viewing transformation.
+ * We can't be sure we'll get a ConfigureNotify event when the window
+ * first appears.
+ */
+ reshape(winWidth, winHeight);
+
+ event_loop(dpy, win);
+
+ glDeleteLists(gear1, 1);
+ glDeleteLists(gear2, 1);
+ glDeleteLists(gear3, 1);
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/progs/xdemos/glxgears2.c b/progs/xdemos/glxgears2.c
new file mode 100644
index 00000000000..5de5601240e
--- /dev/null
+++ b/progs/xdemos/glxgears2.c
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
+ * Port by Brian Paul 23 March 2001
+ *
+ * Command line options:
+ * -info print GL implementation information
+ *
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+
+#define BENCHMARK
+
+#ifdef BENCHMARK
+
+/* XXX this probably isn't very portable */
+
+#include <sys/time.h>
+#include <unistd.h>
+
+/* return current time (in seconds) */
+static int
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (int) tv.tv_sec;
+}
+
+#else /*BENCHMARK*/
+
+/* dummy */
+static int
+current_time(void)
+{
+ return 0;
+}
+
+#endif /*BENCHMARK*/
+
+
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+static GLint WinWidth = 300, WinHeight = 300;
+
+/*
+ *
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void
+gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ glShadeModel(GL_FLAT);
+
+ glNormal3f(0.0, 0.0, 1.0);
+
+ /* draw front face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ glEnd();
+
+ glNormal3f(0.0, 0.0, -1.0);
+
+ /* draw back face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ }
+ glEnd();
+
+ /* draw outward faces of teeth */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ u = r2 * cos(angle + da) - r1 * cos(angle);
+ v = r2 * sin(angle + da) - r1 * sin(angle);
+ len = sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
+ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ }
+
+ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
+ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
+
+ glEnd();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glNormal3f(-cos(angle), -sin(angle), 0.0);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ }
+ glEnd();
+}
+
+
+static void
+draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(view_rotx, 1.0, 0.0, 0.0);
+ glRotatef(view_roty, 0.0, 1.0, 0.0);
+ glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+ glPushMatrix();
+ glTranslatef(-3.0, -2.0, 0.0);
+ glRotatef(angle, 0.0, 0.0, 1.0);
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(3.1, -2.0, 0.0);
+ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(-3.1, 4.2, 0.0);
+ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int width, int height)
+{
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+
+ glViewport(0, 0, (GLint) width, (GLint) height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+ WinWidth = width;
+ WinHeight = height;
+}
+
+
+static void
+init(void)
+{
+ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+
+ glClearColor(1, 0, 0, 0);
+
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0, 4.0, 1.0, 20, 0.7);
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5, 2.0, 2.0, 10, 0.7);
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3, 2.0, 0.5, 10, 0.7);
+ glEndList();
+
+ glEnable(GL_NORMALIZE);
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet)
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win)
+{
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ if (code == XK_Left) {
+ view_roty += 5.0;
+ }
+ else if (code == XK_Right) {
+ view_roty -= 5.0;
+ }
+ else if (code == XK_Up) {
+ view_rotx += 5.0;
+ }
+ else if (code == XK_Down) {
+ view_rotx -= 5.0;
+ }
+ else {
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* next frame */
+ angle += 2.0;
+
+ draw();
+
+#if 0
+ glXSwapBuffers(dpy, win);
+#else
+ {
+ GLfloat c[4];
+
+ glReadBuffer(GL_BACK);
+
+ glReadPixels(WinWidth-1, 0, 1, 1, GL_RGB, GL_FLOAT, c);
+ printf("Bottom right pixel color: %g, %g, %g\n", c[0], c[1], c[2]);
+
+ glDrawBuffer(GL_FRONT);
+ glWindowPos2iARB(0,0);
+ glCopyPixels(WinWidth/2, 0, WinWidth/2, WinHeight, GL_COLOR);
+ glDrawBuffer(GL_BACK);
+ }
+#endif
+
+ /* calc framerate */
+ {
+ static int t0 = -1;
+ static int frames = 0;
+ int t = current_time();
+
+ if (t0 < 0)
+ t0 = t;
+
+ frames++;
+
+ if (t - t0 >= 5.0) {
+ GLfloat seconds = t - t0;
+ GLfloat fps = frames / seconds;
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
+ fps);
+ t0 = t;
+ frames = 0;
+ }
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ char *dpyName = ":0";
+ GLboolean printInfo = GL_FALSE;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n", dpyName);
+ return -1;
+ }
+
+ make_window(dpy, "glxgears", 0, 0, WinWidth, WinHeight, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+ init();
+
+ event_loop(dpy, win);
+
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/progs/xdemos/glxgears_fbconfig.c b/progs/xdemos/glxgears_fbconfig.c
new file mode 100644
index 00000000000..acbadd21ac5
--- /dev/null
+++ b/progs/xdemos/glxgears_fbconfig.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file glxgears_fbconfig.c
+ * Yet-another-version of gears. Originally ported to GLX by Brian Paul on
+ * 23 March 2001. Modified to use fbconfigs by Ian Romanick on 10 Feb 2004.
+ *
+ * Command line options:
+ * -info print GL implementation information
+ *
+ * \author Brian Paul
+ * \author Ian Romanick <[email protected]>
+ */
+
+
+#define GLX_GLXEXT_PROTOTYPES
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glxext.h>
+#include <assert.h>
+#include "pbutil.h"
+
+/* I had to use the SGIX versions of these because for some reason glxext.h
+ * doesn't define the core versions if GLX_VERSION_1_3 is defined, and glx.h
+ * doesn't define them at all. One or both header files is clearly broken.
+ */
+static PFNGLXCHOOSEFBCONFIGSGIXPROC choose_fbconfig = NULL;
+static PFNGLXGETVISUALFROMFBCONFIGSGIXPROC get_visual_from_fbconfig = NULL;
+static PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC create_new_context = NULL;
+
+#define BENCHMARK
+
+#ifdef BENCHMARK
+
+/* XXX this probably isn't very portable */
+
+#include <sys/time.h>
+#include <unistd.h>
+
+/* return current time (in seconds) */
+static int
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (int) tv.tv_sec;
+}
+
+#else /*BENCHMARK*/
+
+/* dummy */
+static int
+current_time(void)
+{
+ return 0;
+}
+
+#endif /*BENCHMARK*/
+
+
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+
+
+/*
+ *
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void
+gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ glShadeModel(GL_FLAT);
+
+ glNormal3f(0.0, 0.0, 1.0);
+
+ /* draw front face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ glEnd();
+
+ glNormal3f(0.0, 0.0, -1.0);
+
+ /* draw back face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ }
+ glEnd();
+
+ /* draw outward faces of teeth */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ u = r2 * cos(angle + da) - r1 * cos(angle);
+ v = r2 * sin(angle + da) - r1 * sin(angle);
+ len = sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
+ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ }
+
+ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
+ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
+
+ glEnd();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glNormal3f(-cos(angle), -sin(angle), 0.0);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ }
+ glEnd();
+}
+
+
+static void
+draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(view_rotx, 1.0, 0.0, 0.0);
+ glRotatef(view_roty, 0.0, 1.0, 0.0);
+ glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+ glPushMatrix();
+ glTranslatef(-3.0, -2.0, 0.0);
+ glRotatef(angle, 0.0, 0.0, 1.0);
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(3.1, -2.0, 0.0);
+ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(-3.1, 4.2, 0.0);
+ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int width, int height)
+{
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+
+ glViewport(0, 0, (GLint) width, (GLint) height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+}
+
+
+static void
+init(void)
+{
+ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0, 4.0, 1.0, 20, 0.7);
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5, 2.0, 2.0, 10, 0.7);
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3, 2.0, 0.5, 10, 0.7);
+ glEndList();
+
+ glEnable(GL_NORMALIZE);
+}
+
+
+/**
+ * Initialize fbconfig related function pointers.
+ */
+static void
+init_fbconfig_functions(Display *dpy, int scrnum)
+{
+ const char * glx_extensions;
+ const char * match;
+ static const char ext_name[] = "GLX_SGIX_fbconfig";
+ const size_t len = strlen( ext_name );
+ int major;
+ int minor;
+ GLboolean ext_version_supported;
+ GLboolean glx_1_3_supported;
+
+
+ /* Determine if GLX 1.3 or greater is supported.
+ */
+ glXQueryVersion(dpy, & major, & minor);
+ glx_1_3_supported = (major == 1) && (minor >= 3);
+
+ /* Determine if GLX_SGIX_fbconfig is supported.
+ */
+ glx_extensions = glXQueryExtensionsString(dpy, scrnum);
+ match = strstr( glx_extensions, ext_name );
+
+ ext_version_supported = (match != NULL)
+ && ((match[len] == '\0') || (match[len] == ' '));
+
+ printf( "GLX 1.3 is %ssupported.\n",
+ (glx_1_3_supported) ? "" : "not " );
+ printf( "%s is %ssupported.\n",
+ ext_name, (ext_version_supported) ? "" : "not " );
+
+ if ( glx_1_3_supported ) {
+ choose_fbconfig = (PFNGLXCHOOSEFBCONFIGSGIXPROC) glXGetProcAddressARB(
+ (GLubyte *) "glXChooseFBConfig");
+ get_visual_from_fbconfig = (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) glXGetProcAddressARB(
+ (GLubyte *) "glXGetVisualFromFBConfig");
+ create_new_context = (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) glXGetProcAddressARB(
+ (GLubyte *) "glXCreateNewContext");
+ }
+ else if ( ext_version_supported ) {
+ choose_fbconfig = (PFNGLXCHOOSEFBCONFIGSGIXPROC) glXGetProcAddressARB(
+ (GLubyte *) "glXChooseFBConfigSGIX");
+ get_visual_from_fbconfig = (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) glXGetProcAddressARB(
+ (GLubyte *) "glXGetVisualFromFBConfigSGIX");
+ create_new_context = (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) glXGetProcAddressARB(
+ (GLubyte *) "glXCreateContextWithConfigSGIX");
+ }
+ else {
+ printf( "This demo requires either GLX 1.3 or %s be supported.\n",
+ ext_name );
+ exit(1);
+ }
+
+ if ( choose_fbconfig == NULL ) {
+ printf( "glXChooseFBConfig not found!\n" );
+ exit(1);
+ }
+
+ if ( get_visual_from_fbconfig == NULL ) {
+ printf( "glXGetVisualFromFBConfig not found!\n" );
+ exit(1);
+ }
+
+ if ( create_new_context == NULL ) {
+ printf( "glXCreateNewContext not found!\n" );
+ exit(1);
+ }
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet)
+{
+ int attrib[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER, GL_TRUE,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ GLXFBConfig * fbconfig;
+ int num_configs;
+ int scrnum;
+ int i;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ init_fbconfig_functions(dpy, scrnum);
+ fbconfig = (*choose_fbconfig)(dpy, scrnum, attrib, & num_configs);
+ if (fbconfig == NULL) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ printf("\nThe following fbconfigs meet the requirements. The first one "
+ "will be used.\n\n");
+ for ( i = 0 ; i < num_configs ; i++ ) {
+ PrintFBConfigInfo(dpy, scrnum, fbconfig[i], GL_TRUE);
+ }
+
+ /* window attributes */
+ visinfo = (*get_visual_from_fbconfig)(dpy, fbconfig[0]);
+ assert(visinfo != NULL);
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = (*create_new_context)(dpy, fbconfig[0], GLX_RGBA_TYPE, NULL, GL_TRUE);
+ if (!ctx) {
+ printf("Error: glXCreateNewContext failed\n");
+ exit(1);
+ }
+
+ XFree(fbconfig);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win)
+{
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ if (code == XK_Left) {
+ view_roty += 5.0;
+ }
+ else if (code == XK_Right) {
+ view_roty -= 5.0;
+ }
+ else if (code == XK_Up) {
+ view_rotx += 5.0;
+ }
+ else if (code == XK_Down) {
+ view_rotx -= 5.0;
+ }
+ else {
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* next frame */
+ angle += 2.0;
+
+ draw();
+ glXSwapBuffers(dpy, win);
+
+ /* calc framerate */
+ {
+ static int t0 = -1;
+ static int frames = 0;
+ int t = current_time();
+
+ if (t0 < 0)
+ t0 = t;
+
+ frames++;
+
+ if (t - t0 >= 5.0) {
+ GLfloat seconds = t - t0;
+ GLfloat fps = frames / seconds;
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
+ fps);
+ t0 = t;
+ frames = 0;
+ }
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ const char *dpyName = NULL;
+ GLboolean printInfo = GL_FALSE;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n", dpyName);
+ return -1;
+ }
+
+ make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+ init();
+
+ event_loop(dpy, win);
+
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/progs/xdemos/glxheads.c b/progs/xdemos/glxheads.c
new file mode 100644
index 00000000000..0145a70e91c
--- /dev/null
+++ b/progs/xdemos/glxheads.c
@@ -0,0 +1,286 @@
+
+/*
+ * Exercise multiple GLX connections on multiple X displays.
+ * Direct GLX contexts are attempted first, then indirect.
+ * Each window will display a spinning green triangle.
+ *
+ * Copyright (C) 2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+
+/*
+ * Each display/window/context:
+ */
+struct head {
+ char DisplayName[1000];
+ Display *Dpy;
+ Window Win;
+ GLXContext Context;
+ float Angle;
+ char Renderer[1000];
+ char Vendor[1000];
+ char Version[1000];
+};
+
+
+#define MAX_HEADS 20
+static struct head Heads[MAX_HEADS];
+static int NumHeads = 0;
+
+
+static void
+Error(const char *display, const char *msg)
+{
+ fprintf(stderr, "Error on display %s - %s\n", display, msg);
+ exit(1);
+}
+
+
+static struct head *
+AddHead(const char *displayName)
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ XVisualInfo *visinfo;
+ int width = 300, height = 300;
+ int xpos = 10, ypos = 10;
+
+ if (NumHeads >= MAX_HEADS)
+ return NULL;
+
+ dpy = XOpenDisplay(displayName);
+ if (!dpy) {
+ Error(displayName, "Unable to open display");
+ return NULL;
+ }
+
+ scrnum = DefaultScreen(dpy);
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attrib);
+ if (!visinfo) {
+ Error(displayName, "Unable to find RGB, double-buffered visual");
+ return NULL;
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+ if (!win) {
+ Error(displayName, "Couldn't create window");
+ return NULL;
+ }
+
+ {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, displayName, displayName,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ ctx = glXCreateContext(dpy, visinfo, NULL, True);
+ if (!ctx) {
+ Error(displayName, "Couldn't create GLX context");
+ return NULL;
+ }
+
+ XMapWindow(dpy, win);
+
+ if (!glXMakeCurrent(dpy, win, ctx)) {
+ Error(displayName, "glXMakeCurrent failed");
+ printf("glXMakeCurrent failed in Redraw()\n");
+ return NULL;
+ }
+
+ /* save the info for this head */
+ {
+ struct head *h = &Heads[NumHeads];
+ strcpy(h->DisplayName, displayName);
+ h->Dpy = dpy;
+ h->Win = win;
+ h->Context = ctx;
+ h->Angle = 0.0;
+ strcpy(h->Version, (char *) glGetString(GL_VERSION));
+ strcpy(h->Vendor, (char *) glGetString(GL_VENDOR));
+ strcpy(h->Renderer, (char *) glGetString(GL_RENDERER));
+ NumHeads++;
+ return &Heads[NumHeads-1];
+ }
+
+}
+
+
+static void
+Redraw(struct head *h)
+{
+ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
+ Error(h->DisplayName, "glXMakeCurrent failed");
+ printf("glXMakeCurrent failed in Redraw()\n");
+ return;
+ }
+
+ h->Angle += 1.0;
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.5, 0.5, 0.5, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* draw green triangle */
+ glColor3f(0.0, 1.0, 0.0);
+ glPushMatrix();
+ glRotatef(h->Angle, 0, 0, 1);
+ glBegin(GL_TRIANGLES);
+ glVertex2f(0, 0.8);
+ glVertex2f(-0.8, -0.7);
+ glVertex2f(0.8, -0.7);
+ glEnd();
+ glPopMatrix();
+
+ glXSwapBuffers(h->Dpy, h->Win);
+}
+
+
+
+static void
+Resize(const struct head *h, unsigned int width, unsigned int height)
+{
+ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
+ Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
+ return;
+ }
+ glFlush();
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
+}
+
+
+
+static void
+EventLoop(void)
+{
+ while (1) {
+ int i;
+ for (i = 0; i < NumHeads; i++) {
+ struct head *h = &Heads[i];
+ while (XPending(h->Dpy) > 0) {
+ XEvent event;
+ XNextEvent(h->Dpy, &event);
+ if (event.xany.window == h->Win) {
+ switch (event.type) {
+ case Expose:
+ Redraw(h);
+ break;
+ case ConfigureNotify:
+ Resize(h, event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ return;
+ default:
+ /*no-op*/ ;
+ }
+ }
+ else {
+ printf("window mismatch\n");
+ }
+ }
+ Redraw(h);
+ }
+ usleep(1);
+ }
+}
+
+
+
+static void
+PrintInfo(const struct head *h)
+{
+ printf("Name: %s\n", h->DisplayName);
+ printf(" Display: %p\n", (void *) h->Dpy);
+ printf(" Window: 0x%x\n", (int) h->Win);
+ printf(" Context: 0x%lx\n", (long) h->Context);
+ printf(" GL_VERSION: %s\n", h->Version);
+ printf(" GL_VENDOR: %s\n", h->Vendor);
+ printf(" GL_RENDERER: %s\n", h->Renderer);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ if (argc == 1) {
+ struct head *h;
+ printf("glxheads: exercise multiple GLX connections (any key = exit)\n");
+ printf("Usage:\n");
+ printf(" glxheads xdisplayname ...\n");
+ printf("Example:\n");
+ printf(" glxheads :0 mars:0 venus:1\n");
+ h = AddHead(":0");
+ if (h)
+ PrintInfo(h);
+ }
+ else {
+ for (i = 1; i < argc; i++) {
+ const char *name = argv[i];
+ struct head *h = AddHead(name);
+ if (h) {
+ PrintInfo(h);
+ }
+ }
+ }
+
+ EventLoop();
+ return 0;
+}
diff --git a/progs/xdemos/glxinfo.c b/progs/xdemos/glxinfo.c
new file mode 100644
index 00000000000..fdd1c0523f6
--- /dev/null
+++ b/progs/xdemos/glxinfo.c
@@ -0,0 +1,956 @@
+/*
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * This program is a work-alike of the IRIX glxinfo program.
+ * Command line options:
+ * -t print wide table
+ * -v print verbose information
+ * -display DisplayName specify the X display to interogate
+ * -b only print ID of "best" visual on screen 0
+ * -i use indirect rendering connection only
+ * -l print interesting OpenGL limits (added 5 Sep 2002)
+ *
+ * Brian Paul 26 January 2000
+ */
+
+#define GLX_GLXEXT_PROTOTYPES
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#ifndef GLX_NONE_EXT
+#define GLX_NONE_EXT 0x8000
+#endif
+
+#ifndef GLX_TRANSPARENT_RGB
+#define GLX_TRANSPARENT_RGB 0x8008
+#endif
+
+
+typedef enum
+{
+ Normal,
+ Wide,
+ Verbose
+} InfoMode;
+
+
+struct visual_attribs
+{
+ /* X visual attribs */
+ int id;
+ int klass;
+ int depth;
+ int redMask, greenMask, blueMask;
+ int colormapSize;
+ int bitsPerRGB;
+
+ /* GL visual attribs */
+ int supportsGL;
+ int transparentType;
+ int transparentRedValue;
+ int transparentGreenValue;
+ int transparentBlueValue;
+ int transparentAlphaValue;
+ int transparentIndexValue;
+ int bufferSize;
+ int level;
+ int rgba;
+ int doubleBuffer;
+ int stereo;
+ int auxBuffers;
+ int redSize, greenSize, blueSize, alphaSize;
+ int depthSize;
+ int stencilSize;
+ int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
+ int numSamples, numMultisample;
+ int visualCaveat;
+};
+
+
+/*
+ * Print a list of extensions, with word-wrapping.
+ */
+static void
+print_extension_list(const char *ext)
+{
+ const char *indentString = " ";
+ const int indent = 4;
+ const int max = 79;
+ int width, i, j;
+
+ if (!ext || !ext[0])
+ return;
+
+ width = indent;
+ printf(indentString);
+ i = j = 0;
+ while (1) {
+ if (ext[j] == ' ' || ext[j] == 0) {
+ /* found end of an extension name */
+ const int len = j - i;
+ if (width + len > max) {
+ /* start a new line */
+ printf("\n");
+ width = indent;
+ printf(indentString);
+ }
+ /* print the extension name between ext[i] and ext[j] */
+ while (i < j) {
+ printf("%c", ext[i]);
+ i++;
+ }
+ /* either we're all done, or we'll continue with next extension */
+ width += len + 1;
+ if (ext[j] == 0) {
+ break;
+ }
+ else {
+ i++;
+ j++;
+ if (ext[j] == 0)
+ break;
+ printf(", ");
+ width += 2;
+ }
+ }
+ j++;
+ }
+ printf("\n");
+}
+
+
+static void
+print_display_info(Display *dpy)
+{
+ printf("name of display: %s\n", DisplayString(dpy));
+}
+
+
+/**
+ * Print interesting limits for vertex/fragment programs.
+ */
+static void
+print_program_limits(GLenum target)
+{
+#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program)
+ struct token_name {
+ GLenum token;
+ const char *name;
+ };
+ static const struct token_name limits[] = {
+ { GL_MAX_PROGRAM_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_INSTRUCTIONS_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB" },
+ { GL_MAX_PROGRAM_TEMPORARIES_ARB, "GL_MAX_PROGRAM_TEMPORARIES_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB" },
+ { GL_MAX_PROGRAM_PARAMETERS_ARB, "GL_MAX_PROGRAM_PARAMETERS_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB" },
+ { GL_MAX_PROGRAM_ATTRIBS_ARB, "GL_MAX_PROGRAM_ATTRIBS_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB" },
+ { GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" },
+ { GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB" },
+ { GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB" },
+ { GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB" },
+ { GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB" },
+ { GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" },
+ { GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" },
+ { (GLenum) 0, NULL }
+ };
+ PFNGLGETPROGRAMIVARBPROC GetProgramivARB_func = (PFNGLGETPROGRAMIVARBPROC)
+ glXGetProcAddressARB((GLubyte *) "glGetProgramivARB");
+ GLint max[1];
+ int i;
+
+ if (target == GL_VERTEX_PROGRAM_ARB) {
+ printf(" GL_VERTEX_PROGRAM_ARB:\n");
+ }
+ else if (target == GL_FRAGMENT_PROGRAM_ARB) {
+ printf(" GL_FRAGMENT_PROGRAM_ARB:\n");
+ }
+ else {
+ return; /* something's wrong */
+ }
+
+ for (i = 0; limits[i].token; i++) {
+ GetProgramivARB_func(target, limits[i].token, max);
+ if (glGetError() == GL_NO_ERROR) {
+ printf(" %s = %d\n", limits[i].name, max[0]);
+ }
+ }
+#endif /* GL_ARB_vertex_program / GL_ARB_fragment_program */
+}
+
+
+/**
+ * Print interesting limits for vertex/fragment shaders.
+ */
+static void
+print_shader_limits(GLenum target)
+{
+ struct token_name {
+ GLenum token;
+ const char *name;
+ };
+#if defined(GL_ARB_vertex_shader)
+ static const struct token_name vertex_limits[] = {
+ { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB" },
+ { GL_MAX_VARYING_FLOATS_ARB, "GL_MAX_VARYING_FLOATS_ARB" },
+ { GL_MAX_VERTEX_ATTRIBS_ARB, "GL_MAX_VERTEX_ATTRIBS_ARB" },
+ { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
+ { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB" },
+ { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB" },
+ { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" },
+ { (GLenum) 0, NULL }
+ };
+#endif
+#if defined(GL_ARB_fragment_shader)
+ static const struct token_name fragment_limits[] = {
+ { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB" },
+ { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" },
+ { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
+ { (GLenum) 0, NULL }
+ };
+#endif
+ GLint max[1];
+ int i;
+
+#if defined(GL_ARB_vertex_shader)
+ if (target == GL_VERTEX_SHADER_ARB) {
+ printf(" GL_VERTEX_SHADER_ARB:\n");
+ for (i = 0; vertex_limits[i].token; i++) {
+ glGetIntegerv(vertex_limits[i].token, max);
+ if (glGetError() == GL_NO_ERROR) {
+ printf(" %s = %d\n", vertex_limits[i].name, max[0]);
+ }
+ }
+ }
+#endif
+#if defined(GL_ARB_fragment_shader)
+ if (target == GL_FRAGMENT_SHADER_ARB) {
+ printf(" GL_FRAGMENT_SHADER_ARB:\n");
+ for (i = 0; fragment_limits[i].token; i++) {
+ glGetIntegerv(fragment_limits[i].token, max);
+ if (glGetError() == GL_NO_ERROR) {
+ printf(" %s = %d\n", fragment_limits[i].name, max[0]);
+ }
+ }
+ }
+#endif
+}
+
+
+/**
+ * Print interesting OpenGL implementation limits.
+ */
+static void
+print_limits(const char *extensions)
+{
+ struct token_name {
+ GLuint count;
+ GLenum token;
+ const char *name;
+ };
+ static const struct token_name limits[] = {
+ { 1, GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH" },
+ { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH" },
+ { 1, GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES" },
+ { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "GL_MAX_COLOR_MATRIX_STACK_DEPTH" },
+ { 1, GL_MAX_ELEMENTS_VERTICES, "GL_MAX_ELEMENTS_VERTICES" },
+ { 1, GL_MAX_ELEMENTS_INDICES, "GL_MAX_ELEMENTS_INDICES" },
+ { 1, GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER" },
+ { 1, GL_MAX_LIGHTS, "GL_MAX_LIGHTS" },
+ { 1, GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING" },
+ { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH" },
+ { 1, GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH" },
+ { 1, GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE" },
+ { 1, GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH" },
+ { 1, GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH" },
+ { 1, GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE" },
+ { 1, GL_MAX_3D_TEXTURE_SIZE, "GL_MAX_3D_TEXTURE_SIZE" },
+ { 2, GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS" },
+ { 2, GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE" },
+ { 2, GL_SMOOTH_LINE_WIDTH_RANGE, "GL_SMOOTH_LINE_WIDTH_RANGE" },
+ { 2, GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE" },
+ { 2, GL_SMOOTH_POINT_SIZE_RANGE, "GL_SMOOTH_POINT_SIZE_RANGE" },
+#if defined(GL_ARB_texture_cube_map)
+ { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB" },
+#endif
+#if defined(GLX_NV_texture_rectangle)
+ { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV" },
+#endif
+#if defined(GL_ARB_texture_compression)
+ { 1, GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, "GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB" },
+#endif
+#if defined(GL_ARB_multitexture)
+ { 1, GL_MAX_TEXTURE_UNITS_ARB, "GL_MAX_TEXTURE_UNITS_ARB" },
+#endif
+#if defined(GL_EXT_texture_lod_bias)
+ { 1, GL_MAX_TEXTURE_LOD_BIAS_EXT, "GL_MAX_TEXTURE_LOD_BIAS_EXT" },
+#endif
+#if defined(GL_EXT_texture_filter_anisotropic)
+ { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" },
+#endif
+#if defined(GL_ARB_draw_buffers)
+ { 1, GL_MAX_DRAW_BUFFERS_ARB, "GL_MAX_DRAW_BUFFERS_ARB" },
+#endif
+ { 0, (GLenum) 0, NULL }
+ };
+ GLint i, max[2];
+
+ printf("OpenGL limits:\n");
+ for (i = 0; limits[i].count; i++) {
+ glGetIntegerv(limits[i].token, max);
+ if (glGetError() == GL_NO_ERROR) {
+ if (limits[i].count == 1)
+ printf(" %s = %d\n", limits[i].name, max[0]);
+ else /* XXX fix if we ever query something with more than 2 values */
+ printf(" %s = %d, %d\n", limits[i].name, max[0], max[1]);
+ }
+ }
+
+ /* these don't fit into the above mechanism, unfortunately */
+ glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_WIDTH, max);
+ glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_HEIGHT, max+1);
+ if (glGetError() == GL_NONE) {
+ printf(" GL_MAX_CONVOLUTION_WIDTH/HEIGHT = %d, %d\n", max[0], max[1]);
+ }
+
+#if defined(GL_ARB_vertex_program)
+ if (strstr(extensions, "GL_ARB_vertex_program")) {
+ print_program_limits(GL_VERTEX_PROGRAM_ARB);
+ }
+#endif
+#if defined(GL_ARB_fragment_program)
+ if (strstr(extensions, "GL_ARB_fragment_program")) {
+ print_program_limits(GL_FRAGMENT_PROGRAM_ARB);
+ }
+#endif
+#if defined(GL_ARB_vertex_shader)
+ if (strstr(extensions, "GL_ARB_vertex_shader")) {
+ print_shader_limits(GL_VERTEX_SHADER_ARB);
+ }
+#endif
+#if defined(GL_ARB_fragment_shader)
+ if (strstr(extensions, "GL_ARB_fragment_shader")) {
+ print_shader_limits(GL_FRAGMENT_SHADER_ARB);
+ }
+#endif
+}
+
+
+static void
+print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits)
+{
+ Window win;
+ int attribSingle[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ None };
+ int attribDouble[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+ int width = 100, height = 100;
+
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
+ if (!visinfo) {
+ visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
+ if (!visinfo) {
+ fprintf(stderr, "Error: couldn't find RGB GLX visual\n");
+ return;
+ }
+ }
+
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+ win = XCreateWindow(dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
+ if (!ctx) {
+ fprintf(stderr, "Error: glXCreateContext failed\n");
+ XFree(visinfo);
+ XDestroyWindow(dpy, win);
+ return;
+ }
+
+ if (glXMakeCurrent(dpy, win, ctx)) {
+ const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
+ const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
+ const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
+ const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
+ const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
+ const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
+ const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
+ const char *glVendor = (const char *) glGetString(GL_VENDOR);
+ const char *glRenderer = (const char *) glGetString(GL_RENDERER);
+ const char *glVersion = (const char *) glGetString(GL_VERSION);
+ const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
+ int glxVersionMajor;
+ int glxVersionMinor;
+ char *displayName = NULL;
+ char *colon = NULL, *period = NULL;
+
+ if (! glXQueryVersion( dpy, & glxVersionMajor, & glxVersionMinor )) {
+ fprintf(stderr, "Error: glXQueryVersion failed\n");
+ exit(1);
+ }
+
+ /* Strip the screen number from the display name, if present. */
+ if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
+ fprintf(stderr, "Error: malloc() failed\n");
+ exit(1);
+ }
+ strcpy(displayName, DisplayString(dpy));
+ colon = strrchr(displayName, ':');
+ if (colon) {
+ period = strchr(colon, '.');
+ if (period)
+ *period = '\0';
+ }
+ printf("display: %s screen: %d\n", displayName, scrnum);
+ free(displayName);
+ printf("direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
+ printf("server glx vendor string: %s\n", serverVendor);
+ printf("server glx version string: %s\n", serverVersion);
+ printf("server glx extensions:\n");
+ print_extension_list(serverExtensions);
+ printf("client glx vendor string: %s\n", clientVendor);
+ printf("client glx version string: %s\n", clientVersion);
+ printf("client glx extensions:\n");
+ print_extension_list(clientExtensions);
+ printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor);
+ printf("GLX extensions:\n");
+ print_extension_list(glxExtensions);
+ printf("OpenGL vendor string: %s\n", glVendor);
+ printf("OpenGL renderer string: %s\n", glRenderer);
+ printf("OpenGL version string: %s\n", glVersion);
+ printf("OpenGL extensions:\n");
+ print_extension_list(glExtensions);
+ if (limits)
+ print_limits(glExtensions);
+ }
+ else {
+ fprintf(stderr, "Error: glXMakeCurrent failed\n");
+ }
+
+ glXDestroyContext(dpy, ctx);
+ XFree(visinfo);
+ XDestroyWindow(dpy, win);
+}
+
+
+static const char *
+visual_class_name(int cls)
+{
+ switch (cls) {
+ case StaticColor:
+ return "StaticColor";
+ case PseudoColor:
+ return "PseudoColor";
+ case StaticGray:
+ return "StaticGray";
+ case GrayScale:
+ return "GrayScale";
+ case TrueColor:
+ return "TrueColor";
+ case DirectColor:
+ return "DirectColor";
+ default:
+ return "";
+ }
+}
+
+
+static const char *
+visual_class_abbrev(int cls)
+{
+ switch (cls) {
+ case StaticColor:
+ return "sc";
+ case PseudoColor:
+ return "pc";
+ case StaticGray:
+ return "sg";
+ case GrayScale:
+ return "gs";
+ case TrueColor:
+ return "tc";
+ case DirectColor:
+ return "dc";
+ default:
+ return "";
+ }
+}
+
+
+static void
+get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
+ struct visual_attribs *attribs)
+{
+ const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
+
+ memset(attribs, 0, sizeof(struct visual_attribs));
+
+ attribs->id = vInfo->visualid;
+#if defined(__cplusplus) || defined(c_plusplus)
+ attribs->klass = vInfo->c_class;
+#else
+ attribs->klass = vInfo->class;
+#endif
+ attribs->depth = vInfo->depth;
+ attribs->redMask = vInfo->red_mask;
+ attribs->greenMask = vInfo->green_mask;
+ attribs->blueMask = vInfo->blue_mask;
+ attribs->colormapSize = vInfo->colormap_size;
+ attribs->bitsPerRGB = vInfo->bits_per_rgb;
+
+ if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0)
+ return;
+ glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
+ glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
+ glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba);
+ glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
+ glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
+ glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
+ glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
+ glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
+ glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
+ glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
+ glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
+ glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
+ glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
+ glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
+ glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
+ glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
+
+ /* get transparent pixel stuff */
+ glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
+ if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
+ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
+ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
+ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
+ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
+ }
+ else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
+ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
+ }
+
+ /* multisample attribs */
+#ifdef GLX_ARB_multisample
+ if (ext && strstr(ext, "GLX_ARB_multisample") == 0) {
+ glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
+ glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
+ }
+#endif
+ else {
+ attribs->numSamples = 0;
+ attribs->numMultisample = 0;
+ }
+
+#if defined(GLX_EXT_visual_rating)
+ if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
+ glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
+ }
+ else {
+ attribs->visualCaveat = GLX_NONE_EXT;
+ }
+#else
+ attribs->visualCaveat = 0;
+#endif
+}
+
+
+static void
+print_visual_attribs_verbose(const struct visual_attribs *attribs)
+{
+ printf("Visual ID: %x depth=%d class=%s\n",
+ attribs->id, attribs->depth, visual_class_name(attribs->klass));
+ printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
+ attribs->bufferSize, attribs->level, attribs->rgba ? "rgba" : "ci",
+ attribs->doubleBuffer, attribs->stereo);
+ printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
+ attribs->redSize, attribs->greenSize,
+ attribs->blueSize, attribs->alphaSize);
+ printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n",
+ attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
+ printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
+ attribs->accumRedSize, attribs->accumGreenSize,
+ attribs->accumBlueSize, attribs->accumAlphaSize);
+ printf(" multiSample=%d multiSampleBuffers=%d\n",
+ attribs->numSamples, attribs->numMultisample);
+#ifdef GLX_EXT_visual_rating
+ if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
+ printf(" visualCaveat=None\n");
+ else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
+ printf(" visualCaveat=Slow\n");
+ else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
+ printf(" visualCaveat=Nonconformant\n");
+#endif
+ if (attribs->transparentType == GLX_NONE) {
+ printf(" Opaque.\n");
+ }
+ else if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
+ printf(" Transparent RGB: Red=%d Green=%d Blue=%d Alpha=%d\n",attribs->transparentRedValue,attribs->transparentGreenValue,attribs->transparentBlueValue,attribs->transparentAlphaValue);
+ }
+ else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
+ printf(" Transparent index=%d\n",attribs->transparentIndexValue);
+ }
+}
+
+
+static void
+print_visual_attribs_short_header(void)
+{
+ printf(" visual x bf lv rg d st colorbuffer ax dp st accumbuffer ms cav\n");
+ printf(" id dep cl sp sz l ci b ro r g b a bf th cl r g b a ns b eat\n");
+ printf("----------------------------------------------------------------------\n");
+}
+
+
+static void
+print_visual_attribs_short(const struct visual_attribs *attribs)
+{
+ char *caveat = NULL;
+#ifdef GLX_EXT_visual_rating
+ if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
+ caveat = "None";
+ else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
+ caveat = "Slow";
+ else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
+ caveat = "Ncon";
+ else
+ caveat = "None";
+#else
+ caveat = "None";
+#endif
+
+ printf("0x%2x %2d %2s %2d %2d %2d %1s %2s %2s %2d %2d %2d %2d %2d %2d %2d",
+ attribs->id,
+ attribs->depth,
+ visual_class_abbrev(attribs->klass),
+ attribs->transparentType != GLX_NONE,
+ attribs->bufferSize,
+ attribs->level,
+ attribs->rgba ? "r" : "c",
+ attribs->doubleBuffer ? "y" : ".",
+ attribs->stereo ? "y" : ".",
+ attribs->redSize, attribs->greenSize,
+ attribs->blueSize, attribs->alphaSize,
+ attribs->auxBuffers,
+ attribs->depthSize,
+ attribs->stencilSize
+ );
+
+ printf(" %2d %2d %2d %2d %2d %1d %s\n",
+ attribs->accumRedSize, attribs->accumGreenSize,
+ attribs->accumBlueSize, attribs->accumAlphaSize,
+ attribs->numSamples, attribs->numMultisample,
+ caveat
+ );
+}
+
+
+static void
+print_visual_attribs_long_header(void)
+{
+ printf("Vis Vis Visual Trans buff lev render DB ste r g b a aux dep ste accum buffers MS MS\n");
+ printf(" ID Depth Type parent size el type reo sz sz sz sz buf th ncl r g b a num bufs\n");
+ printf("----------------------------------------------------------------------------------------------------\n");
+}
+
+
+static void
+print_visual_attribs_long(const struct visual_attribs *attribs)
+{
+ printf("0x%2x %2d %-11s %2d %2d %2d %4s %3d %3d %3d %3d %3d %3d",
+ attribs->id,
+ attribs->depth,
+ visual_class_name(attribs->klass),
+ attribs->transparentType != GLX_NONE,
+ attribs->bufferSize,
+ attribs->level,
+ attribs->rgba ? "rgba" : "ci ",
+ attribs->doubleBuffer,
+ attribs->stereo,
+ attribs->redSize, attribs->greenSize,
+ attribs->blueSize, attribs->alphaSize
+ );
+
+ printf(" %3d %4d %2d %3d %3d %3d %3d %2d %2d\n",
+ attribs->auxBuffers,
+ attribs->depthSize,
+ attribs->stencilSize,
+ attribs->accumRedSize, attribs->accumGreenSize,
+ attribs->accumBlueSize, attribs->accumAlphaSize,
+ attribs->numSamples, attribs->numMultisample
+ );
+}
+
+
+static void
+print_visual_info(Display *dpy, int scrnum, InfoMode mode)
+{
+ XVisualInfo theTemplate;
+ XVisualInfo *visuals;
+ int numVisuals;
+ long mask;
+ int i;
+
+ /* get list of all visuals on this screen */
+ theTemplate.screen = scrnum;
+ mask = VisualScreenMask;
+ visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
+
+ if (mode == Verbose) {
+ for (i = 0; i < numVisuals; i++) {
+ struct visual_attribs attribs;
+ get_visual_attribs(dpy, &visuals[i], &attribs);
+ print_visual_attribs_verbose(&attribs);
+ }
+ }
+ else if (mode == Normal) {
+ print_visual_attribs_short_header();
+ for (i = 0; i < numVisuals; i++) {
+ struct visual_attribs attribs;
+ get_visual_attribs(dpy, &visuals[i], &attribs);
+ print_visual_attribs_short(&attribs);
+ }
+ }
+ else if (mode == Wide) {
+ print_visual_attribs_long_header();
+ for (i = 0; i < numVisuals; i++) {
+ struct visual_attribs attribs;
+ get_visual_attribs(dpy, &visuals[i], &attribs);
+ print_visual_attribs_long(&attribs);
+ }
+ }
+
+ XFree(visuals);
+}
+
+
+/*
+ * Stand-alone Mesa doesn't really implement the GLX protocol so it
+ * doesn't really know the GLX attributes associated with an X visual.
+ * The first time a visual is presented to Mesa's pseudo-GLX it
+ * attaches ancilliary buffers to it (like depth and stencil).
+ * But that usually only works if glXChooseVisual is used.
+ * This function calls glXChooseVisual() to sort of "prime the pump"
+ * for Mesa's GLX so that the visuals that get reported actually
+ * reflect what applications will see.
+ * This has no effect when using true GLX.
+ */
+static void
+mesa_hack(Display *dpy, int scrnum)
+{
+ static int attribs[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 1,
+ GLX_STENCIL_SIZE, 1,
+ GLX_ACCUM_RED_SIZE, 1,
+ GLX_ACCUM_GREEN_SIZE, 1,
+ GLX_ACCUM_BLUE_SIZE, 1,
+ GLX_ACCUM_ALPHA_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+ XVisualInfo *visinfo;
+
+ visinfo = glXChooseVisual(dpy, scrnum, attribs);
+ if (visinfo)
+ XFree(visinfo);
+}
+
+
+/*
+ * Examine all visuals to find the so-called best one.
+ * We prefer deepest RGBA buffer with depth, stencil and accum
+ * that has no caveats.
+ */
+static int
+find_best_visual(Display *dpy, int scrnum)
+{
+ XVisualInfo theTemplate;
+ XVisualInfo *visuals;
+ int numVisuals;
+ long mask;
+ int i;
+ struct visual_attribs bestVis;
+
+ /* get list of all visuals on this screen */
+ theTemplate.screen = scrnum;
+ mask = VisualScreenMask;
+ visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
+
+ /* init bestVis with first visual info */
+ get_visual_attribs(dpy, &visuals[0], &bestVis);
+
+ /* try to find a "better" visual */
+ for (i = 1; i < numVisuals; i++) {
+ struct visual_attribs vis;
+
+ get_visual_attribs(dpy, &visuals[i], &vis);
+
+ /* always skip visuals with caveats */
+ if (vis.visualCaveat != GLX_NONE_EXT)
+ continue;
+
+ /* see if this vis is better than bestVis */
+ if ((!bestVis.supportsGL && vis.supportsGL) ||
+ (bestVis.visualCaveat != GLX_NONE_EXT) ||
+ (!bestVis.rgba && vis.rgba) ||
+ (!bestVis.doubleBuffer && vis.doubleBuffer) ||
+ (bestVis.redSize < vis.redSize) ||
+ (bestVis.greenSize < vis.greenSize) ||
+ (bestVis.blueSize < vis.blueSize) ||
+ (bestVis.alphaSize < vis.alphaSize) ||
+ (bestVis.depthSize < vis.depthSize) ||
+ (bestVis.stencilSize < vis.stencilSize) ||
+ (bestVis.accumRedSize < vis.accumRedSize)) {
+ /* found a better visual */
+ bestVis = vis;
+ }
+ }
+
+ XFree(visuals);
+
+ return bestVis.id;
+}
+
+
+static void
+usage(void)
+{
+ printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-display <dname>]\n");
+ printf("\t-v: Print visuals info in verbose form.\n");
+ printf("\t-t: Print verbose table.\n");
+ printf("\t-display <dname>: Print GLX visuals on specified server.\n");
+ printf("\t-h: This information.\n");
+ printf("\t-i: Force an indirect rendering context.\n");
+ printf("\t-b: Find the 'best' visual and print it's number.\n");
+ printf("\t-l: Print interesting OpenGL limits.\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char *displayName = NULL;
+ Display *dpy;
+ int numScreens, scrnum;
+ InfoMode mode = Normal;
+ GLboolean findBest = GL_FALSE;
+ GLboolean limits = GL_FALSE;
+ Bool allowDirect = True;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
+ displayName = argv[i + 1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-t") == 0) {
+ mode = Wide;
+ }
+ else if (strcmp(argv[i], "-v") == 0) {
+ mode = Verbose;
+ }
+ else if (strcmp(argv[i], "-b") == 0) {
+ findBest = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-i") == 0) {
+ allowDirect = False;
+ }
+ else if (strcmp(argv[i], "-l") == 0) {
+ limits = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-h") == 0) {
+ usage();
+ return 0;
+ }
+ else {
+ printf("Unknown option `%s'\n", argv[i]);
+ usage();
+ return 0;
+ }
+ }
+
+ dpy = XOpenDisplay(displayName);
+ if (!dpy) {
+ fprintf(stderr, "Error: unable to open display %s\n", displayName);
+ return -1;
+ }
+
+ if (findBest) {
+ int b;
+ mesa_hack(dpy, 0);
+ b = find_best_visual(dpy, 0);
+ printf("%d\n", b);
+ }
+ else {
+ numScreens = ScreenCount(dpy);
+ print_display_info(dpy);
+ for (scrnum = 0; scrnum < numScreens; scrnum++) {
+ mesa_hack(dpy, scrnum);
+ print_screen_info(dpy, scrnum, allowDirect, limits);
+ printf("\n");
+ print_visual_info(dpy, scrnum, mode);
+ if (scrnum + 1 < numScreens)
+ printf("\n\n");
+ }
+ }
+
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/progs/xdemos/glxpbdemo.c b/progs/xdemos/glxpbdemo.c
new file mode 100644
index 00000000000..91fd30dcaa6
--- /dev/null
+++ b/progs/xdemos/glxpbdemo.c
@@ -0,0 +1,430 @@
+
+/*
+ * This program demonstrates how to do "off-screen" rendering using
+ * the GLX pixel buffer extension.
+ *
+ * Written by Brian Paul for the "OpenGL and Window System Integration"
+ * course presented at SIGGRAPH '97. Updated on 5 October 2002.
+ *
+ * Updated on 31 January 2004 to use native GLX by
+ * Andrew P. Lentvorski, Jr. <[email protected]>
+ *
+ * Usage:
+ * glxpbdemo width height imgfile
+ * Where:
+ * width is the width, in pixels, of the image to generate.
+ * height is the height, in pixels, of the image to generate.
+ * imgfile is the name of the PPM image file to write.
+ *
+ *
+ * This demo draws 3-D boxes with random orientation.
+ *
+ * On machines such as the SGI Indigo you may have to reconfigure your
+ * display/X server to enable pbuffers. Look in the /usr/gfx/ucode/MGRAS/vof/
+ * directory for display configurations with the _pbuf suffix. Use
+ * setmon -x <vof> to configure your X server and display for pbuffers.
+ *
+ * O2 systems seem to support pbuffers well.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+/* Some ugly global vars */
+static GLXFBConfig gFBconfig = 0;
+static Display *gDpy = NULL;
+static int gScreen = 0;
+static GLXPbuffer gPBuffer = 0;
+static int gWidth, gHeight;
+
+
+/*
+ * Test for appropriate version of GLX to run this program
+ * Input: dpy - the X display
+ * screen - screen number
+ * Return: 0 = GLX not available.
+ * 1 = GLX available.
+ */
+static int
+RuntimeQueryGLXVersion(Display *dpy, int screen)
+{
+#if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4)
+ char *glxversion;
+
+ glxversion = (char *) glXGetClientString(dpy, GLX_VERSION);
+ if (!(strstr(glxversion, "1.3") || strstr(glxversion, "1.4")))
+ return 0;
+
+ glxversion = (char *) glXQueryServerString(dpy, screen, GLX_VERSION);
+ if (!(strstr(glxversion, "1.3") || strstr(glxversion, "1.4")))
+ return 0;
+
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+
+
+/*
+ * Create the pbuffer and return a GLXPbuffer handle.
+ */
+static GLXPbuffer
+MakePbuffer( Display *dpy, int screen, int width, int height )
+{
+ GLXFBConfig *fbConfigs;
+ GLXFBConfig chosenFBConfig;
+ GLXPbuffer pBuffer = None;
+
+ int nConfigs;
+ int fbconfigid;
+
+ int fbAttribs[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DEPTH_SIZE, 1,
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_PBUFFER_BIT,
+ None
+ };
+
+ int pbAttribs[] = {
+ GLX_PBUFFER_WIDTH, 0,
+ GLX_PBUFFER_HEIGHT, 0,
+ GLX_LARGEST_PBUFFER, False,
+ GLX_PRESERVED_CONTENTS, False,
+ None
+ };
+
+ pbAttribs[1] = width;
+ pbAttribs[3] = height;
+
+ fbConfigs = glXChooseFBConfig(dpy, screen, fbAttribs, &nConfigs);
+
+ if (0 == nConfigs || !fbConfigs) {
+ printf("Error: glxChooseFBConfig failed\n");
+ XCloseDisplay(dpy);
+ return 0;
+ }
+
+ chosenFBConfig = fbConfigs[0];
+
+ glXGetFBConfigAttrib(dpy, chosenFBConfig, GLX_FBCONFIG_ID, &fbconfigid);
+ printf("Chose 0x%x as fbconfigid\n", fbconfigid);
+
+ /* Create the pbuffer using first fbConfig in the list that works. */
+ pBuffer = glXCreatePbuffer(dpy, chosenFBConfig, pbAttribs);
+
+ if (pBuffer) {
+ gFBconfig = chosenFBConfig;
+ gWidth = width;
+ gHeight = height;
+ }
+
+ XFree(fbConfigs);
+
+ return pBuffer;
+}
+
+
+
+/*
+ * Do all the X / GLX setup stuff.
+ */
+static int
+Setup(int width, int height)
+{
+#if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4)
+ GLXContext glCtx;
+
+ /* Open the X display */
+ gDpy = XOpenDisplay(NULL);
+ if (!gDpy) {
+ printf("Error: couldn't open default X display.\n");
+ return 0;
+ }
+
+ /* Get default screen */
+ gScreen = DefaultScreen(gDpy);
+
+ /* Test that GLX is available */
+ if (!RuntimeQueryGLXVersion(gDpy, gScreen)) {
+ printf("Error: GLX 1.3 or 1.4 not available\n");
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ /* Create Pbuffer */
+ gPBuffer = MakePbuffer( gDpy, gScreen, width, height );
+ if (gPBuffer==None) {
+ printf("Error: couldn't create pbuffer\n");
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ /* Create GLX context */
+ glCtx = glXCreateNewContext(gDpy, gFBconfig, GLX_RGBA_TYPE, NULL, True);
+ if (glCtx) {
+ if (!glXIsDirect(gDpy, glCtx)) {
+ printf("Warning: using indirect GLXContext\n");
+ }
+ }
+ else {
+ printf("Error: Couldn't create GLXContext\n");
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ /* Bind context to pbuffer */
+ if (!glXMakeCurrent(gDpy, gPBuffer, glCtx)) {
+ printf("Error: glXMakeCurrent failed\n");
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ return 1; /* Success!! */
+#else
+ printf("Error: GLX version 1.3 or 1.4 not available at compile time\n");
+ return 0;
+#endif
+}
+
+
+
+/* One-time GL setup */
+static void
+InitGL(void)
+{
+ static GLfloat pos[4] = {0.0, 0.0, 10.0, 0.0};
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_NORMALIZE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+
+ glViewport(0, 0, gWidth, gHeight);
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+
+}
+
+
+/* Return random float in [0,1] */
+static float
+Random(void)
+{
+ int i = rand();
+ return (float) (i % 1000) / 1000.0;
+}
+
+
+static void
+RandomColor(void)
+{
+ GLfloat c[4];
+ c[0] = Random();
+ c[1] = Random();
+ c[2] = Random();
+ c[3] = 1.0;
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
+}
+
+
+/* This function borrowed from Mark Kilgard's GLUT */
+static void
+drawBox(GLfloat x0, GLfloat x1, GLfloat y0, GLfloat y1,
+ GLfloat z0, GLfloat z1, GLenum type)
+{
+ static GLfloat n[6][3] =
+ {
+ {-1.0, 0.0, 0.0},
+ {0.0, 1.0, 0.0},
+ {1.0, 0.0, 0.0},
+ {0.0, -1.0, 0.0},
+ {0.0, 0.0, 1.0},
+ {0.0, 0.0, -1.0}
+ };
+ static GLint faces[6][4] =
+ {
+ {0, 1, 2, 3},
+ {3, 2, 6, 7},
+ {7, 6, 5, 4},
+ {4, 5, 1, 0},
+ {5, 6, 2, 1},
+ {7, 4, 0, 3}
+ };
+ GLfloat v[8][3], tmp;
+ GLint i;
+
+ if (x0 > x1) {
+ tmp = x0;
+ x0 = x1;
+ x1 = tmp;
+ }
+ if (y0 > y1) {
+ tmp = y0;
+ y0 = y1;
+ y1 = tmp;
+ }
+ if (z0 > z1) {
+ tmp = z0;
+ z0 = z1;
+ z1 = tmp;
+ }
+ v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
+ v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
+ v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
+ v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
+ v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
+ v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
+
+ for (i = 0; i < 6; i++) {
+ glBegin(type);
+ glNormal3fv(&n[i][0]);
+ glVertex3fv(&v[faces[i][0]][0]);
+ glVertex3fv(&v[faces[i][1]][0]);
+ glVertex3fv(&v[faces[i][2]][0]);
+ glVertex3fv(&v[faces[i][3]][0]);
+ glEnd();
+ }
+}
+
+
+
+/* Render a scene */
+static void
+Render(void)
+{
+ int NumBoxes = 100;
+ int i;
+
+ InitGL();
+ glClearColor(0.2, 0.2, 0.9, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ for (i=0;i<NumBoxes;i++) {
+ float tx = -2.0 + 4.0 * Random();
+ float ty = -2.0 + 4.0 * Random();
+ float tz = 4.0 - 16.0 * Random();
+ float sx = 0.1 + Random() * 0.4;
+ float sy = 0.1 + Random() * 0.4;
+ float sz = 0.1 + Random() * 0.4;
+ float rx = Random();
+ float ry = Random();
+ float rz = Random();
+ float ra = Random() * 360.0;
+ glPushMatrix();
+ glTranslatef(tx, ty, tz);
+ glRotatef(ra, rx, ry, rz);
+ glScalef(sx, sy, sz);
+ RandomColor();
+ drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON);
+ glPopMatrix();
+ }
+
+ glFinish();
+}
+
+
+
+static void
+WriteFile(const char *filename)
+{
+ FILE *f;
+ GLubyte *image;
+ int i;
+
+ image = malloc(gWidth * gHeight * 3 * sizeof(GLubyte));
+ if (!image) {
+ printf("Error: couldn't allocate image buffer\n");
+ return;
+ }
+
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glReadPixels(0, 0, gWidth, gHeight, GL_RGB, GL_UNSIGNED_BYTE, image);
+
+ f = fopen(filename, "w");
+ if (!f) {
+ printf("Couldn't open image file: %s\n", filename);
+ return;
+ }
+ fprintf(f,"P6\n");
+ fprintf(f,"# ppm-file created by %s\n", "trdemo2");
+ fprintf(f,"%i %i\n", gWidth, gHeight);
+ fprintf(f,"255\n");
+ fclose(f);
+ f = fopen(filename, "ab"); /* now append binary data */
+ if (!f) {
+ printf("Couldn't append to image file: %s\n", filename);
+ return;
+ }
+
+ for (i=0;i<gHeight;i++) {
+ GLubyte *rowPtr;
+ /* Remember, OpenGL images are bottom to top. Have to reverse. */
+ rowPtr = image + (gHeight-1-i) * gWidth*3;
+ fwrite(rowPtr, 1, gWidth*3, f);
+ }
+
+ fclose(f);
+ free(image);
+
+ printf("Wrote %d by %d image file: %s\n", gWidth, gHeight, filename);
+}
+
+
+
+/*
+ * Print message describing command line parameters.
+ */
+static void
+Usage(const char *appName)
+{
+ printf("Usage:\n");
+ printf(" %s width height imgfile\n", appName);
+ printf("Where imgfile is a ppm file\n");
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+ if (argc!=4) {
+ Usage(argv[0]);
+ }
+ else {
+ int width = atoi(argv[1]);
+ int height = atoi(argv[2]);
+ char *fileName = argv[3];
+ if (width<=0) {
+ printf("Error: width parameter must be at least 1.\n");
+ return 1;
+ }
+ if (height<=0) {
+ printf("Error: height parameter must be at least 1.\n");
+ return 1;
+ }
+ if (!Setup(width, height)) {
+ return 1;
+ }
+
+ printf("Setup completed\n");
+ Render();
+ printf("Render completed.\n");
+ WriteFile(fileName);
+ printf("File write completed.\n");
+
+ glXDestroyPbuffer( gDpy, gPBuffer );
+ }
+ return 0;
+}
+
diff --git a/progs/xdemos/glxpixmap.c b/progs/xdemos/glxpixmap.c
new file mode 100644
index 00000000000..9db4df2c8b8
--- /dev/null
+++ b/progs/xdemos/glxpixmap.c
@@ -0,0 +1,186 @@
+
+
+/*
+ * A demonstration of using the GLXPixmap functions. This program is in
+ * the public domain.
+ *
+ * Brian Paul
+ */
+
+
+#include <GL/gl.h>
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static GLXContext ctx;
+static XVisualInfo *visinfo;
+static GC gc;
+
+
+
+static Window make_rgb_window( Display *dpy,
+ unsigned int width, unsigned int height )
+{
+ const int sbAttrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ None };
+ const int dbAttrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, (int *) sbAttrib );
+ if (!visinfo) {
+ visinfo = glXChooseVisual( dpy, scrnum, (int *) dbAttrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB visual\n");
+ exit(1);
+ }
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ /* TODO: share root colormap if possible */
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* make an X GC so we can do XCopyArea later */
+ gc = XCreateGC( dpy, win, 0, NULL );
+
+ /* need indirect context */
+ ctx = glXCreateContext( dpy, visinfo, NULL, False );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(-1);
+ }
+
+ printf("Direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
+
+ return win;
+}
+
+
+static GLXPixmap make_pixmap( Display *dpy, Window win,
+ unsigned int width, unsigned int height,
+ Pixmap *pixmap)
+{
+ Pixmap pm;
+ GLXPixmap glxpm;
+ XWindowAttributes attr;
+
+ pm = XCreatePixmap( dpy, win, width, height, visinfo->depth );
+ if (!pm) {
+ printf("Error: XCreatePixmap failed\n");
+ exit(-1);
+ }
+
+ XGetWindowAttributes( dpy, win, &attr );
+
+ /*
+ * IMPORTANT:
+ * Use the glXCreateGLXPixmapMESA funtion when using Mesa because
+ * Mesa needs to know the colormap associated with a pixmap in order
+ * to render correctly. This is because Mesa allows RGB rendering
+ * into any kind of visual, not just TrueColor or DirectColor.
+ */
+#ifdef GLX_MESA_pixmap_colormap
+ if (strstr(glXQueryExtensionsString(dpy, 0), "GLX_MESA_pixmap_colormap")) {
+ /* stand-alone Mesa, specify the colormap */
+ glxpm = glXCreateGLXPixmapMESA( dpy, visinfo, pm, attr.colormap );
+ }
+ else {
+ glxpm = glXCreateGLXPixmap( dpy, visinfo, pm );
+ }
+#else
+ /* This will work with Mesa too if the visual is TrueColor or DirectColor */
+ glxpm = glXCreateGLXPixmap( dpy, visinfo, pm );
+#endif
+
+ if (!glxpm) {
+ printf("Error: GLXCreateGLXPixmap failed\n");
+ exit(-1);
+ }
+
+ *pixmap = pm;
+
+ return glxpm;
+}
+
+
+
+static void event_loop( Display *dpy, GLXPixmap pm )
+{
+ XEvent event;
+
+ while (1) {
+ XNextEvent( dpy, &event );
+
+ switch (event.type) {
+ case Expose:
+ printf("Redraw\n");
+ /* copy the image from GLXPixmap to window */
+ XCopyArea( dpy, pm, event.xany.window, /* src, dest */
+ gc, 0, 0, 300, 300, /* gc, src pos, size */
+ 0, 0 ); /* dest pos */
+ break;
+ case ConfigureNotify:
+ /* nothing */
+ break;
+ }
+ }
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ Display *dpy;
+ Window win;
+ Pixmap pm;
+ GLXPixmap glxpm;
+
+ dpy = XOpenDisplay(NULL);
+
+ win = make_rgb_window( dpy, 300, 300 );
+ glxpm = make_pixmap( dpy, win, 300, 300, &pm );
+
+ glXMakeCurrent( dpy, glxpm, ctx );
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+
+ /* Render an image into the pixmap */
+ glShadeModel( GL_FLAT );
+ glClearColor( 0.5, 0.5, 0.5, 1.0 );
+ glClear( GL_COLOR_BUFFER_BIT );
+ glViewport( 0, 0, 300, 300 );
+ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
+ glColor3f( 0.0, 1.0, 1.0 );
+ glRectf( -0.75, -0.75, 0.75, 0.75 );
+ glFlush();
+
+ XMapWindow( dpy, win );
+
+ event_loop( dpy, pm );
+ return 0;
+}
diff --git a/progs/xdemos/glxswapcontrol.c b/progs/xdemos/glxswapcontrol.c
new file mode 100644
index 00000000000..0ed5ebe4722
--- /dev/null
+++ b/progs/xdemos/glxswapcontrol.c
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
+ * Port by Brian Paul 23 March 2001
+ *
+ * Modified by Ian Romanick <[email protected]> 09 April 2003 to support
+ * GLX_{MESA,SGI}_swap_control and GLX_OML_sync_control.
+ *
+ * Command line options:
+ * -display Name of the display to use.
+ * -info print GL implementation information
+ * -swap N Attempt to set the swap interval to 1/N second
+ * -forcegetrate Get the display refresh rate even if the required GLX
+ * extension is not supported.
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#ifndef __VMS
+/*# include <stdint.h>*/
+#endif
+# define GLX_GLXEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#ifndef GLX_MESA_swap_control
+typedef GLint ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
+typedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC) ( void );
+#endif
+
+#if !defined( GLX_OML_sync_control ) && defined( _STDINT_H )
+#define GLX_OML_sync_control 1
+typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
+#endif
+
+#ifndef GLX_MESA_swap_frame_usage
+#define GLX_MESA_swap_frame_usage 1
+typedef int ( * PFNGLXGETFRAMEUSAGEMESAPROC) (Display *dpy, GLXDrawable drawable, float * usage );
+#endif
+
+#define BENCHMARK
+
+PFNGLXGETFRAMEUSAGEMESAPROC get_frame_usage = NULL;
+
+#ifdef BENCHMARK
+
+/* XXX this probably isn't very portable */
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#define NUL '\0'
+
+/* return current time (in seconds) */
+static int
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (int) tv.tv_sec;
+}
+
+#else /*BENCHMARK*/
+
+/* dummy */
+static int
+current_time(void)
+{
+ return 0;
+}
+
+#endif /*BENCHMARK*/
+
+
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+
+static GLboolean has_OML_sync_control = GL_FALSE;
+static GLboolean has_SGI_swap_control = GL_FALSE;
+static GLboolean has_MESA_swap_control = GL_FALSE;
+static GLboolean has_MESA_swap_frame_usage = GL_FALSE;
+
+static char ** extension_table = NULL;
+static unsigned num_extensions;
+
+static GLboolean use_ztrick = GL_FALSE;
+static GLfloat aspect;
+
+/*
+ *
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void
+gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ glShadeModel(GL_FLAT);
+
+ glNormal3f(0.0, 0.0, 1.0);
+
+ /* draw front face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ glEnd();
+
+ glNormal3f(0.0, 0.0, -1.0);
+
+ /* draw back face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ }
+ glEnd();
+
+ /* draw outward faces of teeth */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ u = r2 * cos(angle + da) - r1 * cos(angle);
+ v = r2 * sin(angle + da) - r1 * sin(angle);
+ len = sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
+ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ }
+
+ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
+ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
+
+ glEnd();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glNormal3f(-cos(angle), -sin(angle), 0.0);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ }
+ glEnd();
+}
+
+
+static void
+draw(void)
+{
+ if ( use_ztrick ) {
+ static GLboolean flip = GL_FALSE;
+ static const GLfloat vert[4][3] = {
+ { -1, -1, -0.999 },
+ { 1, -1, -0.999 },
+ { 1, 1, -0.999 },
+ { -1, 1, -0.999 }
+ };
+ static const GLfloat col[4][3] = {
+ { 1.0, 0.6, 0.0 },
+ { 1.0, 0.6, 0.0 },
+ { 0.0, 0.0, 0.0 },
+ { 0.0, 0.0, 0.0 },
+ };
+
+ if ( flip ) {
+ glDepthRange(0, 0.5);
+ glDepthFunc(GL_LEQUAL);
+ }
+ else {
+ glDepthRange(1.0, 0.4999);
+ glDepthFunc(GL_GEQUAL);
+ }
+
+ flip = !flip;
+
+ /* The famous Quake "Z trick" only works when the whole screen is
+ * re-drawn each frame.
+ */
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 1);
+ glDisable(GL_LIGHTING);
+ glShadeModel(GL_SMOOTH);
+
+ glEnable( GL_VERTEX_ARRAY );
+ glEnable( GL_COLOR_ARRAY );
+ glVertexPointer( 3, GL_FLOAT, 0, vert );
+ glColorPointer( 3, GL_FLOAT, 0, col );
+ glDrawArrays( GL_POLYGON, 0, 4 );
+ glDisable( GL_COLOR_ARRAY );
+ glDisable( GL_VERTEX_ARRAY );
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -aspect, aspect, 5.0, 60.0);
+
+ glEnable(GL_LIGHTING);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+ }
+ else {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+
+ glPushMatrix();
+ glRotatef(view_rotx, 1.0, 0.0, 0.0);
+ glRotatef(view_roty, 0.0, 1.0, 0.0);
+ glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+ glPushMatrix();
+ glTranslatef(-3.0, -2.0, 0.0);
+ glRotatef(angle, 0.0, 0.0, 1.0);
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(3.1, -2.0, 0.0);
+ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(-3.1, 4.2, 0.0);
+ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int width, int height)
+{
+ aspect = (GLfloat) height / (GLfloat) width;
+
+
+ glViewport(0, 0, (GLint) width, (GLint) height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glFrustum(-1.0, 1.0, -aspect, aspect, 5.0, 60.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+}
+
+
+static void
+init(void)
+{
+ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0, 4.0, 1.0, 20, 0.7);
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5, 2.0, 2.0, 10, 0.7);
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3, 2.0, 0.5, 10, 0.7);
+ glEndList();
+
+ glEnable(GL_NORMALIZE);
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet)
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win)
+{
+ float frame_usage = 0.0;
+
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ if (code == XK_Left) {
+ view_roty += 5.0;
+ }
+ else if (code == XK_Right) {
+ view_roty -= 5.0;
+ }
+ else if (code == XK_Up) {
+ view_rotx += 5.0;
+ }
+ else if (code == XK_Down) {
+ view_rotx -= 5.0;
+ }
+ else {
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* next frame */
+ angle += 2.0;
+
+ draw();
+ if ( get_frame_usage != NULL ) {
+ GLfloat temp;
+
+ (*get_frame_usage)( dpy, win, & temp );
+ frame_usage += temp;
+ }
+
+ glXSwapBuffers(dpy, win);
+
+ /* calc framerate */
+ {
+ static int t0 = -1;
+ static int frames = 0;
+ int t = current_time();
+
+ if (t0 < 0)
+ t0 = t;
+
+ frames++;
+
+ if (t - t0 >= 5.0) {
+ GLfloat seconds = t - t0;
+ GLfloat fps = frames / seconds;
+ if ( get_frame_usage != NULL ) {
+ printf("%d frames in %3.1f seconds = %6.3f FPS (%3.1f%% usage)\n",
+ frames, seconds, fps,
+ (frame_usage * 100.0) / (float) frames );
+ }
+ else {
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n",
+ frames, seconds, fps);
+ }
+
+ t0 = t;
+ frames = 0;
+ frame_usage = 0.0;
+ }
+ }
+ }
+}
+
+
+/**
+ * Display the refresh rate of the display using the GLX_OML_sync_control
+ * extension.
+ */
+
+static void
+show_refresh_rate( Display * dpy )
+{
+#if defined(GLX_OML_sync_control) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ PFNGLXGETMSCRATEOMLPROC get_msc_rate;
+ int32_t n;
+ int32_t d;
+
+ get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetMscRateOML" );
+ if ( get_msc_rate != NULL ) {
+ (*get_msc_rate)( dpy, glXGetCurrentDrawable(), &n, &d );
+ printf( "refresh rate: %.1fHz\n", (float) n / d );
+ return;
+ }
+#endif
+ printf( "glXGetMscRateOML not supported.\n" );
+}
+
+
+/**
+ * Fill in the table of extension strings from a supplied extensions string
+ * (as returned by glXQueryExtensionsString).
+ *
+ * \param string String of GLX extensions.
+ * \sa is_extension_supported
+ */
+
+static void
+make_extension_table( const char * string )
+{
+ char ** string_tab;
+ unsigned num_strings;
+ unsigned base;
+ unsigned idx;
+ unsigned i;
+
+ /* Count the number of spaces in the string. That gives a base-line
+ * figure for the number of extension in the string.
+ */
+
+ num_strings = 1;
+ for ( i = 0 ; string[i] != NUL ; i++ ) {
+ if ( string[i] == ' ' ) {
+ num_strings++;
+ }
+ }
+
+ string_tab = (char **) malloc( sizeof( char * ) * num_strings );
+ if ( string_tab == NULL ) {
+ return;
+ }
+
+ base = 0;
+ idx = 0;
+
+ while ( string[ base ] != NUL ) {
+ /* Determine the length of the next extension string.
+ */
+
+ for ( i = 0
+ ; (string[ base + i ] != NUL) && (string[ base + i ] != ' ')
+ ; i++ ) {
+ /* empty */ ;
+ }
+
+ if ( i > 0 ) {
+ /* If the string was non-zero length, add it to the table. We
+ * can get zero length strings if there is a space at the end of
+ * the string or if there are two (or more) spaces next to each
+ * other in the string.
+ */
+
+ string_tab[ idx ] = malloc( sizeof( char ) * (i + 1) );
+ if ( string_tab[ idx ] == NULL ) {
+ return;
+ }
+
+ (void) memcpy( string_tab[ idx ], & string[ base ], i );
+ string_tab[ idx ][i] = NUL;
+ idx++;
+ }
+
+
+ /* Skip to the start of the next extension string.
+ */
+
+ for ( base += i
+ ; (string[ base ] == ' ') && (string[ base ] != NUL)
+ ; base++ ) {
+ /* empty */ ;
+ }
+ }
+
+ extension_table = string_tab;
+ num_extensions = idx;
+}
+
+
+/**
+ * Determine of an extension is supported. The extension string table
+ * must have already be initialized by calling \c make_extension_table.
+ *
+ * \praram ext Extension to be tested.
+ * \return GL_TRUE of the extension is supported, GL_FALSE otherwise.
+ * \sa make_extension_table
+ */
+
+static GLboolean
+is_extension_supported( const char * ext )
+{
+ unsigned i;
+
+ for ( i = 0 ; i < num_extensions ; i++ ) {
+ if ( strcmp( ext, extension_table[i] ) == 0 ) {
+ return GL_TRUE;
+ }
+ }
+
+ return GL_FALSE;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ char *dpyName = ":0";
+ int swap_interval = 1;
+ GLboolean do_swap_interval = GL_FALSE;
+ GLboolean force_get_rate = GL_FALSE;
+ GLboolean printInfo = GL_FALSE;
+ int i;
+ PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL;
+ PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL;
+
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-swap") == 0 && i + 1 < argc) {
+ swap_interval = atoi( argv[i+1] );
+ do_swap_interval = GL_TRUE;
+ i++;
+ }
+ else if (strcmp(argv[i], "-forcegetrate") == 0) {
+ /* This option was put in because some DRI drivers don't support the
+ * full GLX_OML_sync_control extension, but they do support
+ * glXGetMscRateOML.
+ */
+ force_get_rate = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-ztrick") == 0) {
+ use_ztrick = GL_TRUE;
+ }
+ else if (strcmp(argv[i], "-help") == 0) {
+ printf("Usage:\n");
+ printf(" gears [options]\n");
+ printf("Options:\n");
+ printf(" -help Print this information\n");
+ printf(" -display displayName Specify X display\n");
+ printf(" -info Display GL information\n");
+ printf(" -swap N Swap no more than once per N vertical refreshes\n");
+ printf(" -forcegetrate Try to use glXGetMscRateOML function\n");
+ return 0;
+ }
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n", dpyName);
+ return -1;
+ }
+
+ make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) );
+ has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" );
+ has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" );
+ has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" );
+ has_MESA_swap_frame_usage = is_extension_supported( "GLX_MESA_swap_frame_usage" );
+
+ if ( has_MESA_swap_control ) {
+ set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalMESA" );
+ get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetSwapIntervalMESA" );
+ }
+ else if ( has_SGI_swap_control ) {
+ set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalSGI" );
+ }
+
+
+ if ( has_MESA_swap_frame_usage ) {
+ get_frame_usage = (PFNGLXGETFRAMEUSAGEMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetFrameUsageMESA" );
+ }
+
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ if ( has_OML_sync_control || force_get_rate ) {
+ show_refresh_rate( dpy );
+ }
+
+ if ( get_swap_interval != NULL ) {
+ printf("Default swap interval = %d\n", (*get_swap_interval)() );
+ }
+ }
+
+ if ( do_swap_interval ) {
+ if ( set_swap_interval != NULL ) {
+ if ( ((swap_interval == 0) && !has_MESA_swap_control)
+ || (swap_interval < 0) ) {
+ printf( "Swap interval must be non-negative or greater than zero "
+ "if GLX_MESA_swap_control is not supported.\n" );
+ }
+ else {
+ (*set_swap_interval)( swap_interval );
+ }
+
+ if ( printInfo && (get_swap_interval != NULL) ) {
+ printf("Current swap interval = %d\n", (*get_swap_interval)() );
+ }
+ }
+ else {
+ printf("Unable to set swap-interval. Neither GLX_SGI_swap_control "
+ "nor GLX_MESA_swap_control are supported.\n" );
+ }
+ }
+
+ init();
+
+ event_loop(dpy, win);
+
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}
diff --git a/progs/xdemos/manywin.c b/progs/xdemos/manywin.c
new file mode 100644
index 00000000000..c9cca751341
--- /dev/null
+++ b/progs/xdemos/manywin.c
@@ -0,0 +1,393 @@
+/*
+ * Create N GLX windows/contexts and render to them in round-robin order.
+ * Also, have the contexts share all texture objects.
+ * Press 'd' to delete a texture, 'u' to unbind it.
+ *
+ * Copyright (C) 2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <X11/keysym.h>
+
+
+/*
+ * Each display/window/context:
+ */
+struct head {
+ char DisplayName[1000];
+ Display *Dpy;
+ Window Win;
+ GLXContext Context;
+ float Angle;
+ char Renderer[1000];
+ char Vendor[1000];
+ char Version[1000];
+};
+
+
+#define MAX_HEADS 200
+static struct head Heads[MAX_HEADS];
+static int NumHeads = 0;
+static GLboolean SwapSeparate = GL_TRUE;
+static GLuint TexObj = 0;
+
+
+static void
+Error(const char *display, const char *msg)
+{
+ fprintf(stderr, "Error on display %s - %s\n", display, msg);
+ exit(1);
+}
+
+
+static struct head *
+AddHead(const char *displayName, const char *name)
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ XVisualInfo *visinfo;
+ int width = 90, height = 90;
+ int xpos = 0, ypos = 0;
+
+ if (NumHeads >= MAX_HEADS)
+ return NULL;
+
+ dpy = XOpenDisplay(displayName);
+ if (!dpy) {
+ Error(displayName, "Unable to open display");
+ return NULL;
+ }
+
+ scrnum = DefaultScreen(dpy);
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attrib);
+ if (!visinfo) {
+ Error(displayName, "Unable to find RGB, double-buffered visual");
+ return NULL;
+ }
+
+ /* window attributes */
+ xpos = (NumHeads % 10) * 100;
+ ypos = (NumHeads / 10) * 100;
+ printf("%d, %d\n", xpos, ypos);
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(dpy, root, xpos, ypos, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+ if (!win) {
+ Error(displayName, "Couldn't create window");
+ return NULL;
+ }
+
+ {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ if (NumHeads == 0) {
+ ctx = glXCreateContext(dpy, visinfo, NULL, True);
+ }
+ else {
+ /* share textures & dlists with 0th context */
+ printf("sharing\n");
+ ctx = glXCreateContext(dpy, visinfo, Heads[0].Context, True);
+ }
+ if (!ctx) {
+ Error(displayName, "Couldn't create GLX context");
+ return NULL;
+ }
+
+ XMapWindow(dpy, win);
+
+ if (!glXMakeCurrent(dpy, win, ctx)) {
+ Error(displayName, "glXMakeCurrent failed");
+ printf("glXMakeCurrent failed in Redraw()\n");
+ return NULL;
+ }
+
+ if (NumHeads == 0) {
+ /* create texture object now */
+ static const GLubyte checker[2][2][4] = {
+ { {255, 255, 255, 255}, { 0, 0, 0, 255} },
+ { { 0, 0, 0, 0}, {255, 255, 255, 255} }
+ };
+ glGenTextures(1, &TexObj);
+ assert(TexObj);
+ glBindTexture(GL_TEXTURE_2D, TexObj);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGB,
+ GL_UNSIGNED_BYTE, checker);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ else {
+ /* bind 0th context's texture in this context too */
+ assert(TexObj);
+ glBindTexture(GL_TEXTURE_2D, TexObj);
+ }
+ glEnable(GL_TEXTURE_2D);
+
+ /* save the info for this head */
+ {
+ struct head *h = &Heads[NumHeads];
+ strcpy(h->DisplayName, name);
+ h->Dpy = dpy;
+ h->Win = win;
+ h->Context = ctx;
+ h->Angle = 0.0;
+ strcpy(h->Version, (char *) glGetString(GL_VERSION));
+ strcpy(h->Vendor, (char *) glGetString(GL_VENDOR));
+ strcpy(h->Renderer, (char *) glGetString(GL_RENDERER));
+ NumHeads++;
+ return &Heads[NumHeads-1];
+ }
+
+}
+
+
+static void
+DestroyHeads(void)
+{
+ int i;
+ for (i = 0; i < NumHeads; i++) {
+ XDestroyWindow(Heads[i].Dpy, Heads[i].Win);
+ glXDestroyContext(Heads[i].Dpy, Heads[i].Context);
+ XCloseDisplay(Heads[i].Dpy);
+ }
+}
+
+
+static void
+Redraw(struct head *h)
+{
+ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
+ Error(h->DisplayName, "glXMakeCurrent failed");
+ printf("glXMakeCurrent failed in Redraw()\n");
+ return;
+ }
+
+ h->Angle += 1.0;
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.5, 0.5, 0.5, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* draw green triangle */
+ glColor3f(0.0, 1.0, 0.0);
+ glPushMatrix();
+ glRotatef(h->Angle, 0, 0, 1);
+ glBegin(GL_TRIANGLES);
+ glTexCoord2f(0.5, 1.0); glVertex2f(0, 0.8);
+ glTexCoord2f(0.0, 0.0); glVertex2f(-0.8, -0.7);
+ glTexCoord2f(1.0, 0.0); glVertex2f(0.8, -0.7);
+ glEnd();
+ glPopMatrix();
+
+ if (!SwapSeparate)
+ glXSwapBuffers(h->Dpy, h->Win);
+}
+
+
+static void
+Swap(struct head *h)
+{
+ glXSwapBuffers(h->Dpy, h->Win);
+}
+
+
+static void
+Resize(const struct head *h, unsigned int width, unsigned int height)
+{
+ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
+ Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
+ return;
+ }
+ glFlush();
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
+}
+
+
+
+static void
+EventLoop(void)
+{
+ while (1) {
+ int i;
+ for (i = 0; i < NumHeads; i++) {
+ struct head *h = &Heads[i];
+ while (XPending(h->Dpy) > 0) {
+ XEvent event;
+ XNextEvent(h->Dpy, &event);
+ if (event.xany.window == h->Win) {
+ switch (event.type) {
+ case Expose:
+ Redraw(h);
+ if (SwapSeparate)
+ Swap(h);
+ break;
+ case ConfigureNotify:
+ Resize(h, event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buf[100];
+ KeySym keySym;
+ XComposeStatus stat;
+ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
+ switch (keySym) {
+ case XK_Escape:
+ exit(0);
+ break;
+ case XK_d:
+ case XK_D:
+ printf("Delete Texture in window %d\n", i);
+ glXMakeCurrent(h->Dpy, h->Win, h->Context);
+ glDeleteTextures(1, &TexObj);
+ break;
+ case XK_u:
+ case XK_U:
+ printf("Unbind Texture in window %d\n", i);
+ glXMakeCurrent(h->Dpy, h->Win, h->Context);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ break;
+ }
+ }
+ break;
+ default:
+ /*no-op*/ ;
+ }
+ }
+ else {
+ printf("window mismatch\n");
+ }
+ }
+ }
+
+ /* redraw all windows */
+ for (i = 0; i < NumHeads; i++) {
+ Redraw(&Heads[i]);
+ }
+ /* swapbuffers on all windows, if not already done */
+ if (SwapSeparate) {
+ for (i = 0; i < NumHeads; i++) {
+ Swap(&Heads[i]);
+ }
+ }
+ usleep(1);
+ }
+}
+
+
+
+static void
+PrintInfo(const struct head *h)
+{
+ printf("Name: %s\n", h->DisplayName);
+ printf(" Display: %p\n", (void *) h->Dpy);
+ printf(" Window: 0x%x\n", (int) h->Win);
+ printf(" Context: 0x%lx\n", (long) h->Context);
+ printf(" GL_VERSION: %s\n", h->Version);
+ printf(" GL_VENDOR: %s\n", h->Vendor);
+ printf(" GL_RENDERER: %s\n", h->Renderer);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char *dpyName = NULL;
+ int i;
+
+ if (argc == 1) {
+ printf("manywin: open N simultaneous glx windows\n");
+ printf("Usage:\n");
+ printf(" manywin [-s] numWindows\n");
+ printf("Options:\n");
+ printf(" -s = swap immediately after drawing (see src code)\n");
+ printf("Example:\n");
+ printf(" manywin 10\n");
+ return 0;
+ }
+ else {
+ int n = 3;
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-s") == 0) {
+ SwapSeparate = GL_FALSE;
+ }
+ else if (strcmp(argv[i], "-display") == 0 && i < argc) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else {
+ n = atoi(argv[i]);
+ }
+ }
+ if (n < 1)
+ n = 1;
+
+ printf("%d windows\n", n);
+ for (i = 0; i < n; i++) {
+ char name[100];
+ struct head *h;
+ sprintf(name, "%d", i);
+ h = AddHead(dpyName, name);
+ if (h) {
+ PrintInfo(h);
+ }
+ }
+ }
+
+ EventLoop();
+ DestroyHeads();
+ return 0;
+}
diff --git a/progs/xdemos/offset.c b/progs/xdemos/offset.c
new file mode 100644
index 00000000000..3e92e68daa7
--- /dev/null
+++ b/progs/xdemos/offset.c
@@ -0,0 +1,323 @@
+/****************************************************************************
+Copyright 1995 by Silicon Graphics Incorporated, Mountain View, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Silicon Graphics not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+****************************************************************************/
+
+/*
+ * Derived from code written by Kurt Akeley, November 1992
+ *
+ * Uses PolygonOffset to draw hidden-line images. PolygonOffset
+ * shifts the z values of polygons an amount that is
+ * proportional to their slope in screen z. This keeps
+ * the lines, which are drawn without displacement, from
+ * interacting with their respective polygons, and
+ * thus eliminates line dropouts.
+ *
+ * The left image shows an ordinary antialiased wireframe image.
+ * The center image shows an antialiased hidden-line image without
+ * PolygonOffset.
+ * The right image shows an antialiased hidden-line image using
+ * PolygonOffset to reduce artifacts.
+ *
+ * Drag with a mouse button pressed to rotate the models.
+ * Press the escape key to exit.
+ */
+
+/*
+ * Modified for OpenGL 1.1 glPolygonOffset() conventions
+ */
+
+
+#include <GL/glx.h>
+#include <GL/glu.h>
+#include <X11/keysym.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef GL_EXT_polygon_offset /* use GL 1.1 version instead of extension */
+
+
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+
+#define MAXQUAD 6
+
+typedef float Vertex[3];
+
+typedef Vertex Quad[4];
+
+/* data to define the six faces of a unit cube */
+Quad quads[MAXQUAD] = {
+ { {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0} },
+ { {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1} },
+ { {0,0,0}, {1,0,0}, {1,0,1}, {0,0,1} },
+ { {0,1,0}, {1,1,0}, {1,1,1}, {0,1,1} },
+ { {0,0,0}, {0,0,1}, {0,1,1}, {0,1,0} },
+ { {1,0,0}, {1,0,1}, {1,1,1}, {1,1,0} }
+};
+
+#define WIREFRAME 0
+#define HIDDEN_LINE 1
+
+static void error(const char* prog, const char* msg);
+static void cubes(int mx, int my, int mode);
+static void fill(Quad quad);
+static void outline(Quad quad);
+static void draw_hidden(Quad quad, int mode);
+static void process_input(Display *dpy, Window win);
+static int query_extension(char* extName);
+
+static int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None };
+
+static int dimension = 3;
+
+int main(int argc, char** argv) {
+ Display *dpy;
+ XVisualInfo *vi;
+ XSetWindowAttributes swa;
+ Window win;
+ GLXContext cx;
+
+ dpy = XOpenDisplay(0);
+ if (!dpy) error(argv[0], "can't open display");
+
+ vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
+ if (!vi) error(argv[0], "no suitable visual");
+
+ cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
+
+ swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocNone);
+
+ swa.border_pixel = 0;
+ swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
+ ButtonPressMask | ButtonMotionMask;
+ win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, 900, 300,
+ 0, vi->depth, InputOutput, vi->visual,
+ CWBorderPixel|CWColormap|CWEventMask, &swa);
+ XStoreName(dpy, win, "hiddenline");
+ XMapWindow(dpy, win);
+
+ glXMakeCurrent(dpy, win, cx);
+
+ /* check for the polygon offset extension */
+#ifndef GL_VERSION_1_1
+ if (!query_extension("GL_EXT_polygon_offset"))
+ error(argv[0], "polygon_offset extension is not available");
+#else
+ (void) query_extension;
+#endif
+
+ /* set up viewing parameters */
+ glMatrixMode(GL_PROJECTION);
+ gluPerspective(20, 1, 0.1, 20);
+ glMatrixMode(GL_MODELVIEW);
+ glTranslatef(0, 0, -15);
+
+ /* set other relevant state information */
+ glEnable(GL_DEPTH_TEST);
+
+#ifdef GL_EXT_polygon_offset
+ printf("using 1.0 offset extension\n");
+ glPolygonOffsetEXT( 1.0, 0.00001 );
+#else
+ printf("using 1.1 offset\n");
+ glPolygonOffset( 1.0, 0.5 );
+#endif
+
+ glShadeModel( GL_FLAT );
+ glDisable( GL_DITHER );
+
+ /* process events until the user presses ESC */
+ while (1) process_input(dpy, win);
+
+ return 0;
+}
+
+static void
+draw_scene(int mx, int my) {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glTranslatef(-1.7, 0.0, 0.0);
+ cubes(mx, my, WIREFRAME);
+ glPopMatrix();
+
+ glPushMatrix();
+ cubes(mx, my, HIDDEN_LINE);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(1.7, 0.0, 0.0);
+#ifdef GL_EXT_polygon_offset
+ glEnable(GL_POLYGON_OFFSET_EXT);
+#else
+ glEnable(GL_POLYGON_OFFSET_FILL);
+#endif
+ cubes(mx, my, HIDDEN_LINE);
+#ifdef GL_EXT_polygon_offset
+ glDisable(GL_POLYGON_OFFSET_EXT);
+#else
+ glDisable(GL_POLYGON_OFFSET_FILL);
+#endif
+ glPopMatrix();
+}
+
+
+static void
+cubes(int mx, int my, int mode) {
+ int x, y, z, i;
+
+ /* track the mouse */
+ glRotatef(mx / 2.0, 0, 1, 0);
+ glRotatef(my / 2.0, 1, 0, 0);
+
+ /* draw the lines as hidden polygons */
+ glTranslatef(-0.5, -0.5, -0.5);
+ glScalef(1.0/dimension, 1.0/dimension, 1.0/dimension);
+ for (z = 0; z < dimension; z++) {
+ for (y = 0; y < dimension; y++) {
+ for (x = 0; x < dimension; x++) {
+ glPushMatrix();
+ glTranslatef(x, y, z);
+ glScalef(0.8, 0.8, 0.8);
+ for (i = 0; i < MAXQUAD; i++)
+ draw_hidden(quads[i], mode);
+ glPopMatrix();
+ }
+ }
+ }
+}
+
+static void
+fill(Quad quad) {
+ /* draw a filled polygon */
+ glBegin(GL_QUADS);
+ glVertex3fv(quad[0]);
+ glVertex3fv(quad[1]);
+ glVertex3fv(quad[2]);
+ glVertex3fv(quad[3]);
+ glEnd();
+}
+
+static void
+outline(Quad quad) {
+ /* draw an outlined polygon */
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(quad[0]);
+ glVertex3fv(quad[1]);
+ glVertex3fv(quad[2]);
+ glVertex3fv(quad[3]);
+ glEnd();
+}
+
+static void
+draw_hidden(Quad quad, int mode) {
+ if (mode == HIDDEN_LINE) {
+ glColor3f(0, 0, 0);
+ fill(quad);
+ }
+
+ /* draw the outline using white, optionally fill the interior with black */
+ glColor3f(1, 1, 1);
+ outline(quad);
+}
+
+static void
+process_input(Display *dpy, Window win) {
+ XEvent event;
+ static int prevx, prevy;
+ static int deltax = 90, deltay = 40;
+
+ do {
+ char buf[31];
+ KeySym keysym;
+
+ XNextEvent(dpy, &event);
+ switch(event.type) {
+ case Expose:
+ break;
+ case ConfigureNotify: {
+ /* this approach preserves a 1:1 viewport aspect ratio */
+ int vX, vY, vW, vH;
+ int eW = event.xconfigure.width, eH = event.xconfigure.height;
+ if (eW >= eH) {
+ vX = 0;
+ vY = (eH - eW) >> 1;
+ vW = vH = eW;
+ } else {
+ vX = (eW - eH) >> 1;
+ vY = 0;
+ vW = vH = eH;
+ }
+ glViewport(vX, vY, vW, vH);
+ }
+ break;
+ case KeyPress:
+ (void) XLookupString(&event.xkey, buf, sizeof(buf), &keysym, NULL);
+ switch (keysym) {
+ case XK_Escape:
+ exit(EXIT_SUCCESS);
+ default:
+ break;
+ }
+ case ButtonPress:
+ prevx = event.xbutton.x;
+ prevy = event.xbutton.y;
+ break;
+ case MotionNotify:
+ deltax += (event.xbutton.x - prevx); prevx = event.xbutton.x;
+ deltay += (event.xbutton.y - prevy); prevy = event.xbutton.y;
+ break;
+ default:
+ break;
+ }
+ } while (XPending(dpy));
+
+ draw_scene(deltax, deltay);
+ glXSwapBuffers(dpy, win);
+}
+
+static void
+error(const char *prog, const char *msg) {
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(EXIT_FAILURE);
+}
+
+static int
+query_extension(char* extName) {
+ char *p = (char *) glGetString(GL_EXTENSIONS);
+ char *end = p + strlen(p);
+ while (p < end) {
+ int n = strcspn(p, " ");
+ if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0))
+ return GL_TRUE;
+ p += (n + 1);
+ }
+ return GL_FALSE;
+}
+
diff --git a/progs/xdemos/opencloseopen.c b/progs/xdemos/opencloseopen.c
new file mode 100644
index 00000000000..2e4de24c71d
--- /dev/null
+++ b/progs/xdemos/opencloseopen.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ * (C) Copyright IBM Corporation 2003
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+/** \file opencloseopen.c
+ * Simple test for Mesa bug #508473. Create a window and rendering context.
+ * Draw a single frame. Close the window, destroy the context, and close
+ * the display. Re-open the display, create a new window and context. This
+ * should work, but, at least as of Mesa 5.1, it segfaults. See the bug
+ * report for more details.
+ *
+ * Most of the code here was lifed from various other Mesa xdemos.
+ */
+
+static void
+draw(void)
+{
+ glViewport(0, 0, 300, 300);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.5, 0.5, 0.5, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* draw blue quad */
+ glLoadIdentity();
+ glColor3f(0.3, 0.3, 1.0);
+ glPushMatrix();
+ glRotatef(0, 0, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex2f(-0.5, -0.25);
+ glVertex2f( 0.5, -0.25);
+ glVertex2f( 0.5, 0.25);
+ glVertex2f(-0.5, 0.25);
+ glEnd();
+ glPopMatrix();}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( const char * dpyName, const char *name,
+ int x, int y, int width, int height,
+ Display **dpyRet, Window *winRet, GLXContext *ctxRet)
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+ Display *dpy;
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n", dpyName);
+ exit(1);
+ }
+
+ *dpyRet = dpy;
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+destroy_window( Display *dpy, Window win, GLXContext ctx )
+{
+ glXMakeCurrent(dpy, None, NULL);
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ char *dpyName = ":0";
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ }
+
+ printf("If this program segfaults, then Mesa bug #508473 is probably "
+ "back.\n");
+ make_window(dpyName, "Open-close-open", 0, 0, 300, 300, &dpy, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ draw();
+ glXSwapBuffers(dpy, win);
+ sleep(2);
+
+ destroy_window(dpy, win, ctx);
+
+ make_window(dpyName, "Open-close-open", 0, 0, 300, 300, &dpy, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+ destroy_window(dpy, win, ctx);
+
+ return 0;
+}
diff --git a/progs/xdemos/overlay.c b/progs/xdemos/overlay.c
new file mode 100644
index 00000000000..4c425b64d46
--- /dev/null
+++ b/progs/xdemos/overlay.c
@@ -0,0 +1,245 @@
+/*
+ * GLX overlay test/demo.
+ *
+ * Brian Paul
+ * 18 July 2005
+ */
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <X11/keysym.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int WinWidth = 300, WinHeight = 300;
+static Window NormalWindow = 0;
+static Window OverlayWindow = 0;
+static GLXContext NormalContext = 0;
+static GLXContext OverlayContext = 0;
+static GLboolean RGBOverlay = GL_FALSE;
+static GLfloat Angle = 0.0;
+
+
+static void
+RedrawNormal(Display *dpy)
+{
+ glXMakeCurrent(dpy, NormalWindow, NormalContext);
+ glViewport(0, 0, WinWidth, WinHeight);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glClearColor(0.5, 0.5, 0.5, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor3f(1.0, 1.0, 0.0);
+ glPushMatrix();
+ glRotatef(Angle, 0, 0, 1);
+ glRectf(-0.8, -0.8, 0.8, 0.8);
+ glPopMatrix();
+ glXSwapBuffers(dpy, NormalWindow);
+}
+
+
+static void
+RedrawOverlay(Display *dpy)
+{
+ glXMakeCurrent(dpy, OverlayWindow, OverlayContext);
+ glViewport(0, 0, WinWidth, WinHeight);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glClear(GL_COLOR_BUFFER_BIT);
+ if (RGBOverlay) {
+ glColor3f(0.0, 1.0, 1.0);
+ }
+ else {
+ glIndexi(2);
+ }
+ glBegin(GL_LINES);
+ glVertex2f(-1, -1);
+ glVertex2f(1, 1);
+ glVertex2f(1, -1);
+ glVertex2f(-1, 1);
+ glEnd();
+ glXSwapBuffers(dpy, OverlayWindow);
+}
+
+
+static Window
+MakeWindow(Display *dpy, XVisualInfo *visinfo, Window parent,
+ unsigned int width, unsigned int height)
+{
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+
+ scrnum = DefaultScreen(dpy);
+ root = RootWindow(dpy, scrnum);
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(dpy, parent, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+ return win;
+}
+
+
+static void
+MakeNormalWindow(Display *dpy)
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ Window root;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen(dpy);
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attrib);
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ NormalWindow = MakeWindow(dpy, visinfo, root, WinWidth, WinHeight);
+ assert(NormalWindow);
+
+ NormalContext = glXCreateContext(dpy, visinfo, NULL, True);
+ assert(NormalContext);
+}
+
+
+static void
+MakeOverlayWindow(Display *dpy)
+{
+ int rgbAttribs[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_LEVEL, 1,
+ None
+ };
+ int indexAttribs[] = {
+ /*GLX_RGBA, leave this out */
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_LEVEL, 1,
+ None
+ };
+ int scrnum;
+ Window root;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen(dpy);
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, rgbAttribs);
+ if (visinfo) {
+ printf("Found RGB overlay visual 0x%x\n", (int) visinfo->visualid);
+ RGBOverlay = GL_TRUE;
+ }
+ else {
+ visinfo = glXChooseVisual(dpy, scrnum, indexAttribs);
+ if (visinfo) {
+ printf("Found Color Index overlay visual 0x%x\n",
+ (int) visinfo->visualid);
+ /* XXX setup the colormap entries! */
+ }
+ else {
+ printf("Error: couldn't get an overlay visual!\n");
+ exit(1);
+ }
+ }
+
+ OverlayWindow = MakeWindow(dpy, visinfo, NormalWindow, WinWidth, WinHeight);
+ assert(OverlayWindow);
+
+ OverlayContext = glXCreateContext(dpy, visinfo, NULL, True);
+ assert(OverlayContext);
+}
+
+
+static void
+EventLoop(Display *dpy)
+{
+ XEvent event;
+
+ while (1) {
+ XNextEvent(dpy, &event);
+
+ switch (event.type) {
+ case Expose:
+ RedrawNormal(dpy);
+ RedrawOverlay(dpy);
+ break;
+ case ConfigureNotify:
+ WinWidth = event.xconfigure.width;
+ WinHeight = event.xconfigure.height;
+ if (event.xconfigure.window == NormalWindow)
+ XResizeWindow(dpy, OverlayWindow, WinWidth, WinHeight);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ else if (buffer[0] == ' ') {
+ Angle += 5.0;
+ RedrawNormal(dpy);
+ }
+ }
+ break;
+ default:
+ ; /* nothing */
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy = XOpenDisplay(NULL);
+
+ assert(dpy);
+
+ MakeNormalWindow(dpy);
+ MakeOverlayWindow(dpy);
+
+ XMapWindow(dpy, NormalWindow);
+ XMapWindow(dpy, OverlayWindow);
+
+ EventLoop(dpy);
+
+ glXDestroyContext(dpy, OverlayContext);
+ glXDestroyContext(dpy, NormalContext);
+ XDestroyWindow(dpy, OverlayWindow);
+ XDestroyWindow(dpy, NormalWindow);
+
+ return 0;
+}
diff --git a/progs/xdemos/pbdemo.c b/progs/xdemos/pbdemo.c
new file mode 100644
index 00000000000..efdfdfa4522
--- /dev/null
+++ b/progs/xdemos/pbdemo.c
@@ -0,0 +1,478 @@
+
+/*
+ * This program demonstrates how to do "off-screen" rendering using
+ * the GLX pixel buffer extension.
+ *
+ * Written by Brian Paul for the "OpenGL and Window System Integration"
+ * course presented at SIGGRAPH '97. Updated on 5 October 2002.
+ *
+ * Usage:
+ * pbuffers width height imgfile
+ * Where:
+ * width is the width, in pixels, of the image to generate.
+ * height is the height, in pixels, of the image to generate.
+ * imgfile is the name of the PPM image file to write.
+ *
+ *
+ * This demo draws 3-D boxes with random orientation. A pbuffer with
+ * a depth (Z) buffer is prefered but if such a pbuffer can't be created
+ * we use a non-depth-buffered config.
+ *
+ * On machines such as the SGI Indigo you may have to reconfigure your
+ * display/X server to enable pbuffers. Look in the /usr/gfx/ucode/MGRAS/vof/
+ * directory for display configurationswith the _pbuf suffix. Use
+ * setmon -x <vof> to configure your X server and display for pbuffers.
+ *
+ * O2 systems seem to support pbuffers well.
+ *
+ * IR systems (at least 1RM systems) don't have single-buffered, RGBA,
+ * Z-buffered pbuffer configs. BUT, they DO have DOUBLE-buffered, RGBA,
+ * Z-buffered pbuffers. Note how we try four different fbconfig attribute
+ * lists below!
+ */
+
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include "pbutil.h"
+
+
+/* Some ugly global vars */
+static Display *gDpy = NULL;
+static int gScreen = 0;
+static FBCONFIG gFBconfig = 0;
+static PBUFFER gPBuffer = 0;
+static int gWidth, gHeight;
+static GLXContext glCtx;
+
+
+
+/*
+ * Create the pbuffer and return a GLXPbuffer handle.
+ *
+ * We loop over a list of fbconfigs trying to create
+ * a pixel buffer. We return the first pixel buffer which we successfully
+ * create.
+ */
+static PBUFFER
+MakePbuffer( Display *dpy, int screen, int width, int height )
+{
+#define NUM_FB_CONFIGS 4
+ const char fbString[NUM_FB_CONFIGS][100] = {
+ "Single Buffered, depth buffer",
+ "Double Buffered, depth buffer",
+ "Single Buffered, no depth buffer",
+ "Double Buffered, no depth buffer"
+ };
+ int fbAttribs[NUM_FB_CONFIGS][100] = {
+ {
+ /* Single buffered, with depth buffer */
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 1,
+ GLX_DOUBLEBUFFER, 0,
+ GLX_STENCIL_SIZE, 0,
+ None
+ },
+ {
+ /* Double buffered, with depth buffer */
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 1,
+ GLX_DOUBLEBUFFER, 1,
+ GLX_STENCIL_SIZE, 0,
+ None
+ },
+ {
+ /* Single bufferd, without depth buffer */
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 0,
+ GLX_DOUBLEBUFFER, 0,
+ GLX_STENCIL_SIZE, 0,
+ None
+ },
+ {
+ /* Double bufferd, without depth buffer */
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 0,
+ GLX_DOUBLEBUFFER, 1,
+ GLX_STENCIL_SIZE, 0,
+ None
+ }
+ };
+ Bool largest = True;
+ Bool preserve = False;
+ FBCONFIG *fbConfigs;
+ PBUFFER pBuffer = None;
+ int nConfigs;
+ int i;
+ int attempt;
+
+ for (attempt=0; attempt<NUM_FB_CONFIGS; attempt++) {
+
+ /* Get list of possible frame buffer configurations */
+ fbConfigs = ChooseFBConfig(dpy, screen, fbAttribs[attempt], &nConfigs);
+ if (nConfigs==0 || !fbConfigs) {
+ printf("Error: glXChooseFBConfig failed\n");
+ XCloseDisplay(dpy);
+ return 0;
+ }
+
+#if 0 /*DEBUG*/
+ for (i=0;i<nConfigs;i++) {
+ printf("Config %d\n", i);
+ PrintFBConfigInfo(dpy, screen, fbConfigs[i], 0);
+ }
+#endif
+
+ /* Create the pbuffer using first fbConfig in the list that works. */
+ for (i=0;i<nConfigs;i++) {
+ pBuffer = CreatePbuffer(dpy, screen, fbConfigs[i], width, height, preserve, largest);
+ if (pBuffer) {
+ gFBconfig = fbConfigs[i];
+ gWidth = width;
+ gHeight = height;
+ break;
+ }
+ }
+
+ if (pBuffer!=None) {
+ break;
+ }
+ }
+
+ if (pBuffer) {
+ printf("Using: %s\n", fbString[attempt]);
+ }
+
+ XFree(fbConfigs);
+
+ return pBuffer;
+#undef NUM_FB_CONFIGS
+}
+
+
+
+/*
+ * Do all the X / GLX setup stuff.
+ */
+static int
+Setup(int width, int height)
+{
+ int pbSupport;
+ XVisualInfo *visInfo;
+
+ /* Open the X display */
+ gDpy = XOpenDisplay(NULL);
+ if (!gDpy) {
+ printf("Error: couldn't open default X display.\n");
+ return 0;
+ }
+
+ /* Get default screen */
+ gScreen = DefaultScreen(gDpy);
+
+ /* Test that pbuffers are available */
+ pbSupport = QueryPbuffers(gDpy, gScreen);
+ if (pbSupport == 1) {
+ printf("Using GLX 1.3 Pbuffers\n");
+ }
+ else if (pbSupport == 2) {
+ printf("Using SGIX Pbuffers\n");
+ }
+ else {
+ printf("Error: pbuffers not available on this screen\n");
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ /* Create Pbuffer */
+ gPBuffer = MakePbuffer( gDpy, gScreen, width, height );
+ if (gPBuffer==None) {
+ printf("Error: couldn't create pbuffer\n");
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ /* Get corresponding XVisualInfo */
+ visInfo = GetVisualFromFBConfig(gDpy, gScreen, gFBconfig);
+ if (!visInfo) {
+ printf("Error: can't get XVisualInfo from FBconfig\n");
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ /* Create GLX context */
+ glCtx = glXCreateContext(gDpy, visInfo, NULL, True);
+ if (!glCtx) {
+ /* try indirect */
+ glCtx = glXCreateContext(gDpy, visInfo, NULL, False);
+ if (!glCtx) {
+ printf("Error: Couldn't create GLXContext\n");
+ XFree(visInfo);
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+ else {
+ printf("Warning: using indirect GLXContext\n");
+ }
+ }
+
+ /* Bind context to pbuffer */
+ if (!glXMakeCurrent(gDpy, gPBuffer, glCtx)) {
+ printf("Error: glXMakeCurrent failed\n");
+ XFree(visInfo);
+ XCloseDisplay(gDpy);
+ return 0;
+ }
+
+ return 1; /* Success!! */
+}
+
+
+
+/* One-time GL setup */
+static void
+InitGL(void)
+{
+ static GLfloat pos[4] = {0.0, 0.0, 10.0, 0.0};
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_NORMALIZE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+
+ glViewport(0, 0, gWidth, gHeight);
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+/* Return random float in [0,1] */
+static float
+Random(void)
+{
+ int i = rand();
+ return (float) (i % 1000) / 1000.0;
+}
+
+
+static void
+RandomColor(void)
+{
+ GLfloat c[4];
+ c[0] = Random();
+ c[1] = Random();
+ c[2] = Random();
+ c[3] = 1.0;
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
+}
+
+
+/* This function borrowed from Mark Kilgard's GLUT */
+static void
+drawBox(GLfloat x0, GLfloat x1, GLfloat y0, GLfloat y1,
+ GLfloat z0, GLfloat z1, GLenum type)
+{
+ static GLfloat n[6][3] =
+ {
+ {-1.0, 0.0, 0.0},
+ {0.0, 1.0, 0.0},
+ {1.0, 0.0, 0.0},
+ {0.0, -1.0, 0.0},
+ {0.0, 0.0, 1.0},
+ {0.0, 0.0, -1.0}
+ };
+ static GLint faces[6][4] =
+ {
+ {0, 1, 2, 3},
+ {3, 2, 6, 7},
+ {7, 6, 5, 4},
+ {4, 5, 1, 0},
+ {5, 6, 2, 1},
+ {7, 4, 0, 3}
+ };
+ GLfloat v[8][3], tmp;
+ GLint i;
+
+ if (x0 > x1) {
+ tmp = x0;
+ x0 = x1;
+ x1 = tmp;
+ }
+ if (y0 > y1) {
+ tmp = y0;
+ y0 = y1;
+ y1 = tmp;
+ }
+ if (z0 > z1) {
+ tmp = z0;
+ z0 = z1;
+ z1 = tmp;
+ }
+ v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
+ v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
+ v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
+ v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
+ v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
+ v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
+
+ for (i = 0; i < 6; i++) {
+ glBegin(type);
+ glNormal3fv(&n[i][0]);
+ glVertex3fv(&v[faces[i][0]][0]);
+ glVertex3fv(&v[faces[i][1]][0]);
+ glVertex3fv(&v[faces[i][2]][0]);
+ glVertex3fv(&v[faces[i][3]][0]);
+ glEnd();
+ }
+}
+
+
+
+/* Render a scene */
+static void
+Render(void)
+{
+ int NumBoxes = 100;
+ int i;
+
+ glClearColor(0.2, 0.2, 0.9, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ for (i=0;i<NumBoxes;i++) {
+ float tx = -2.0 + 4.0 * Random();
+ float ty = -2.0 + 4.0 * Random();
+ float tz = 4.0 - 16.0 * Random();
+ float sx = 0.1 + Random() * 0.4;
+ float sy = 0.1 + Random() * 0.4;
+ float sz = 0.1 + Random() * 0.4;
+ float rx = Random();
+ float ry = Random();
+ float rz = Random();
+ float ra = Random() * 360.0;
+ glPushMatrix();
+ glTranslatef(tx, ty, tz);
+ glRotatef(ra, rx, ry, rz);
+ glScalef(sx, sy, sz);
+ RandomColor();
+ drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON);
+ glPopMatrix();
+ }
+
+ glFinish();
+}
+
+
+
+static void
+WriteFile(const char *filename)
+{
+ FILE *f;
+ GLubyte *image;
+ int i;
+
+ image = malloc(gWidth * gHeight * 3 * sizeof(GLubyte));
+ if (!image) {
+ printf("Error: couldn't allocate image buffer\n");
+ return;
+ }
+
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glReadPixels(0, 0, gWidth, gHeight, GL_RGB, GL_UNSIGNED_BYTE, image);
+
+ f = fopen(filename, "w");
+ if (!f) {
+ printf("Couldn't open image file: %s\n", filename);
+ return;
+ }
+ fprintf(f,"P6\n");
+ fprintf(f,"# ppm-file created by %s\n", "trdemo2");
+ fprintf(f,"%i %i\n", gWidth, gHeight);
+ fprintf(f,"255\n");
+ fclose(f);
+ f = fopen(filename, "ab"); /* now append binary data */
+ if (!f) {
+ printf("Couldn't append to image file: %s\n", filename);
+ return;
+ }
+
+ for (i=0;i<gHeight;i++) {
+ GLubyte *rowPtr;
+ /* Remember, OpenGL images are bottom to top. Have to reverse. */
+ rowPtr = image + (gHeight-1-i) * gWidth*3;
+ fwrite(rowPtr, 1, gWidth*3, f);
+ }
+
+ fclose(f);
+ free(image);
+
+ printf("Wrote %d by %d image file: %s\n", gWidth, gHeight, filename);
+}
+
+
+
+/*
+ * Print message describing command line parameters.
+ */
+static void
+Usage(const char *appName)
+{
+ printf("Usage:\n");
+ printf(" %s width height imgfile\n", appName);
+ printf("Where imgfile is a ppm file\n");
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+ if (argc!=4) {
+ Usage(argv[0]);
+ }
+ else {
+ int width = atoi(argv[1]);
+ int height = atoi(argv[2]);
+ char *fileName = argv[3];
+ if (width<=0) {
+ printf("Error: width parameter must be at least 1.\n");
+ return 1;
+ }
+ if (height<=0) {
+ printf("Error: height parameter must be at least 1.\n");
+ return 1;
+ }
+ if (!Setup(width, height)) {
+ return 1;
+ }
+ InitGL();
+ Render();
+ WriteFile(fileName);
+ DestroyPbuffer(gDpy, gScreen, gPBuffer);
+ }
+ return 0;
+}
+
diff --git a/progs/xdemos/pbinfo.c b/progs/xdemos/pbinfo.c
new file mode 100644
index 00000000000..88d93c8da62
--- /dev/null
+++ b/progs/xdemos/pbinfo.c
@@ -0,0 +1,106 @@
+
+/*
+ * Print list of fbconfigs and test each to see if a pbuffer can be created
+ * for that config.
+ *
+ * Brian Paul
+ * April 1997
+ * Updated on 5 October 2002.
+ */
+
+
+#include <X11/Xlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "pbutil.h"
+
+
+
+
+static void
+PrintConfigs(Display *dpy, int screen, Bool horizFormat)
+{
+ FBCONFIG *fbConfigs;
+ int nConfigs;
+ int i;
+
+ fbConfigs = GetAllFBConfigs(dpy, screen, &nConfigs);
+ if (!nConfigs || !fbConfigs) {
+ printf("Error: glxGetFBConfigs failed\n");
+ return;
+ }
+
+ printf("Number of fbconfigs: %d\n", nConfigs);
+
+ if (horizFormat) {
+ printf(" ID VisualType Depth Lvl RGB CI DB Stereo R G B A");
+ printf(" Z S AR AG AB AA MSbufs MSnum Pbuffer Float\n");
+ }
+
+ /* Print config info */
+ for (i = 0; i < nConfigs; i++) {
+ PrintFBConfigInfo(dpy, screen, fbConfigs[i], horizFormat);
+ }
+
+ /* free the list */
+ XFree(fbConfigs);
+}
+
+
+
+static void
+PrintUsage(void)
+{
+ printf("Options:\n");
+ printf(" -display <display-name> specify X display name\n");
+ printf(" -t print in tabular format\n");
+ printf(" -v print in verbose format\n");
+ printf(" -help print this information\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ int scrn;
+ char *dpyName = NULL;
+ Bool horizFormat = True;
+ int i;
+
+ for (i=1; i<argc; i++) {
+ if (strcmp(argv[i],"-display")==0) {
+ if (i+1<argc) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ }
+ else if (strcmp(argv[i],"-t")==0) {
+ /* tabular format */
+ horizFormat = True;
+ }
+ else if (strcmp(argv[i],"-v")==0) {
+ /* verbose format */
+ horizFormat = False;
+ }
+ else if (strcmp(argv[i],"-help")==0) {
+ PrintUsage();
+ return 0;
+ }
+ else {
+ printf("Unknown option: %s\n", argv[i]);
+ }
+ }
+
+ dpy = XOpenDisplay(dpyName);
+
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n", dpyName ? dpyName : ":0");
+ return 1;
+ }
+
+ scrn = DefaultScreen(dpy);
+ PrintConfigs(dpy, scrn, horizFormat);
+ XCloseDisplay(dpy);
+ return 0;
+}
diff --git a/progs/xdemos/pbutil.c b/progs/xdemos/pbutil.c
new file mode 100644
index 00000000000..d0bbd1b0fce
--- /dev/null
+++ b/progs/xdemos/pbutil.c
@@ -0,0 +1,426 @@
+
+/*
+ * OpenGL pbuffers utility functions.
+ *
+ * Brian Paul
+ * Original code: April 1997
+ * Updated on 5 October 2002
+ * Updated again on 3 January 2005 to use GLX 1.3 functions in preference
+ * to the GLX_SGIX_fbconfig/pbuffer extensions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "pbutil.h"
+
+
+/**
+ * Test if we pixel buffers are available for a particular X screen.
+ * Input: dpy - the X display
+ * screen - screen number
+ * Return: 0 = pixel buffers not available.
+ * 1 = pixel buffers are available via GLX 1.3.
+ * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer.
+ */
+int
+QueryPbuffers(Display *dpy, int screen)
+{
+#if defined(GLX_VERSION_1_3)
+ {
+ /* GLX 1.3 supports pbuffers */
+ int glxVersionMajor, glxVersionMinor;
+ if (!glXQueryVersion(dpy, &glxVersionMajor, &glxVersionMinor)) {
+ /* GLX not available! */
+ return 0;
+ }
+ if (glxVersionMajor * 100 + glxVersionMinor >= 103) {
+ return 1;
+ }
+ /* fall-through */
+ }
+#endif
+
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ /* Try the SGIX extensions */
+ {
+ char *extensions;
+ extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS);
+ if (!extensions ||
+ !strstr(extensions,"GLX_SGIX_fbconfig") ||
+ !strstr(extensions,"GLX_SGIX_pbuffer")) {
+ return 0;
+ }
+ return 2;
+ }
+#endif
+
+ return 0;
+}
+
+
+
+FBCONFIG *
+ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs)
+{
+ int pbSupport = QueryPbuffers(dpy, screen);
+#if defined(GLX_VERSION_1_3)
+ if (pbSupport == 1) {
+ return glXChooseFBConfig(dpy, screen, attribs, nConfigs);
+ }
+#endif
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ if (pbSupport == 2) {
+ return glXChooseFBConfigSGIX(dpy, screen, (int *) attribs, nConfigs);
+ }
+#endif
+ return NULL;
+}
+
+
+FBCONFIG *
+GetAllFBConfigs(Display *dpy, int screen, int *nConfigs)
+{
+ int pbSupport = QueryPbuffers(dpy, screen);
+#if defined(GLX_VERSION_1_3)
+ if (pbSupport == 1) {
+ return glXGetFBConfigs(dpy, screen, nConfigs);
+ }
+#endif
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ if (pbSupport == 2) {
+ /* The GLX_SGIX_fbconfig extensions says to pass NULL to get list
+ * of all available configurations.
+ */
+ return glXChooseFBConfigSGIX(dpy, screen, NULL, nConfigs);
+ }
+#endif
+ return NULL;
+}
+
+
+XVisualInfo *
+GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config)
+{
+ int pbSupport = QueryPbuffers(dpy, screen);
+#if defined(GLX_VERSION_1_3)
+ if (pbSupport == 1) {
+ return glXGetVisualFromFBConfig(dpy, config);
+ }
+#endif
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ if (pbSupport == 2) {
+ return glXGetVisualFromFBConfigSGIX(dpy, config);
+ }
+#endif
+ return NULL;
+}
+
+
+/**
+ * Either use glXGetFBConfigAttrib() or glXGetFBConfigAttribSGIX()
+ * to query an fbconfig attribute.
+ */
+static int
+GetFBConfigAttrib(Display *dpy, int screen,
+#if defined(GLX_VERSION_1_3)
+ const GLXFBConfig config,
+#elif defined(GLX_SGIX_fbconfig)
+ const GLXFBConfigSGIX config,
+#endif
+ int attrib
+ )
+{
+ int pbSupport = QueryPbuffers(dpy, screen);
+ int value = 0;
+
+#if defined(GLX_VERSION_1_3)
+ if (pbSupport == 1) {
+ /* ok */
+ if (glXGetFBConfigAttrib(dpy, config, attrib, &value) != 0) {
+ value = 0;
+ }
+ return value;
+ }
+ /* fall-through */
+#endif
+
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ if (pbSupport == 2) {
+ if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) {
+ value = 0;
+ }
+ return value;
+ }
+#endif
+
+ return value;
+}
+
+
+
+/**
+ * Print parameters for a GLXFBConfig to stdout.
+ * Input: dpy - the X display
+ * screen - the X screen number
+ * fbConfig - the fbconfig handle
+ * horizFormat - if true, print in horizontal format
+ */
+void
+PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat)
+{
+ PBUFFER pBuffer;
+ int width=2, height=2;
+ int bufferSize, level, doubleBuffer, stereo, auxBuffers;
+ int redSize, greenSize, blueSize, alphaSize;
+ int depthSize, stencilSize;
+ int accumRedSize, accumBlueSize, accumGreenSize, accumAlphaSize;
+ int sampleBuffers, samples;
+ int drawableType, renderType, xRenderable, xVisual, id;
+ int maxWidth, maxHeight, maxPixels;
+ int optWidth, optHeight;
+ int floatComponents = 0;
+
+ /* do queries using the GLX 1.3 tokens (same as the SGIX tokens) */
+ bufferSize = GetFBConfigAttrib(dpy, screen, config, GLX_BUFFER_SIZE);
+ level = GetFBConfigAttrib(dpy, screen, config, GLX_LEVEL);
+ doubleBuffer = GetFBConfigAttrib(dpy, screen, config, GLX_DOUBLEBUFFER);
+ stereo = GetFBConfigAttrib(dpy, screen, config, GLX_STEREO);
+ auxBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_AUX_BUFFERS);
+ redSize = GetFBConfigAttrib(dpy, screen, config, GLX_RED_SIZE);
+ greenSize = GetFBConfigAttrib(dpy, screen, config, GLX_GREEN_SIZE);
+ blueSize = GetFBConfigAttrib(dpy, screen, config, GLX_BLUE_SIZE);
+ alphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ALPHA_SIZE);
+ depthSize = GetFBConfigAttrib(dpy, screen, config, GLX_DEPTH_SIZE);
+ stencilSize = GetFBConfigAttrib(dpy, screen, config, GLX_STENCIL_SIZE);
+ accumRedSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_RED_SIZE);
+ accumGreenSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_GREEN_SIZE);
+ accumBlueSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_BLUE_SIZE);
+ accumAlphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_ALPHA_SIZE);
+ sampleBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLE_BUFFERS);
+ samples = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLES);
+ drawableType = GetFBConfigAttrib(dpy, screen, config, GLX_DRAWABLE_TYPE);
+ renderType = GetFBConfigAttrib(dpy, screen, config, GLX_RENDER_TYPE);
+ xRenderable = GetFBConfigAttrib(dpy, screen, config, GLX_X_RENDERABLE);
+ xVisual = GetFBConfigAttrib(dpy, screen, config, GLX_X_VISUAL_TYPE);
+ if (!xRenderable || !(drawableType & GLX_WINDOW_BIT_SGIX))
+ xVisual = -1;
+
+ id = GetFBConfigAttrib(dpy, screen, config, GLX_FBCONFIG_ID);
+ maxWidth = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_WIDTH);
+ maxHeight = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_HEIGHT);
+ maxPixels = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_PIXELS);
+#if defined(GLX_SGIX_pbuffer)
+ optWidth = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX);
+ optHeight = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX);
+#else
+ optWidth = optHeight = 0;
+#endif
+#if defined(GLX_NV_float_buffer)
+ floatComponents = GetFBConfigAttrib(dpy, screen, config, GLX_FLOAT_COMPONENTS_NV);
+#endif
+
+ /* See if we can create a pbuffer with this config */
+ pBuffer = CreatePbuffer(dpy, screen, config, width, height, False, False);
+
+ if (horizFormat) {
+ printf("0x%-9x ", id);
+ if (xVisual==GLX_STATIC_GRAY) printf("StaticGray ");
+ else if (xVisual==GLX_GRAY_SCALE) printf("GrayScale ");
+ else if (xVisual==GLX_STATIC_COLOR) printf("StaticColor ");
+ else if (xVisual==GLX_PSEUDO_COLOR) printf("PseudoColor ");
+ else if (xVisual==GLX_TRUE_COLOR) printf("TrueColor ");
+ else if (xVisual==GLX_DIRECT_COLOR) printf("DirectColor ");
+ else printf(" -none- ");
+ printf(" %3d %3d %s %s %s %2s ", bufferSize, level,
+ (renderType & GLX_RGBA_BIT_SGIX) ? "y" : ".",
+ (renderType & GLX_COLOR_INDEX_BIT_SGIX) ? "y" : ".",
+ doubleBuffer ? "y" : ".",
+ stereo ? "y" : ".");
+ printf("%2d %2d %2d %2d ", redSize, greenSize, blueSize, alphaSize);
+ printf("%2d %2d ", depthSize, stencilSize);
+ printf("%2d %2d %2d %2d", accumRedSize, accumGreenSize, accumBlueSize,
+ accumAlphaSize);
+ printf(" %2d %2d", sampleBuffers, samples);
+ printf(" %s %c", pBuffer ? "y" : ".",
+ ".y"[floatComponents]);
+ printf("\n");
+ }
+ else {
+ printf("Id 0x%x\n", id);
+ printf(" Buffer Size: %d\n", bufferSize);
+ printf(" Level: %d\n", level);
+ printf(" Double Buffer: %s\n", doubleBuffer ? "yes" : "no");
+ printf(" Stereo: %s\n", stereo ? "yes" : "no");
+ printf(" Aux Buffers: %d\n", auxBuffers);
+ printf(" Red Size: %d\n", redSize);
+ printf(" Green Size: %d\n", greenSize);
+ printf(" Blue Size: %d\n", blueSize);
+ printf(" Alpha Size: %d\n", alphaSize);
+ printf(" Depth Size: %d\n", depthSize);
+ printf(" Stencil Size: %d\n", stencilSize);
+ printf(" Accum Red Size: %d\n", accumRedSize);
+ printf(" Accum Green Size: %d\n", accumGreenSize);
+ printf(" Accum Blue Size: %d\n", accumBlueSize);
+ printf(" Accum Alpha Size: %d\n", accumAlphaSize);
+ printf(" Sample Buffers: %d\n", sampleBuffers);
+ printf(" Samples/Pixel: %d\n", samples);
+ printf(" Drawable Types: ");
+ if (drawableType & GLX_WINDOW_BIT) printf("Window ");
+ if (drawableType & GLX_PIXMAP_BIT) printf("Pixmap ");
+ if (drawableType & GLX_PBUFFER_BIT) printf("PBuffer");
+ printf("\n");
+ printf(" Render Types: ");
+ if (renderType & GLX_RGBA_BIT_SGIX) printf("RGBA ");
+ if (renderType & GLX_COLOR_INDEX_BIT_SGIX) printf("CI ");
+ printf("\n");
+ printf(" X Renderable: %s\n", xRenderable ? "yes" : "no");
+
+ printf(" Pbuffer: %s\n", pBuffer ? "yes" : "no");
+ printf(" Max Pbuffer width: %d\n", maxWidth);
+ printf(" Max Pbuffer height: %d\n", maxHeight);
+ printf(" Max Pbuffer pixels: %d\n", maxPixels);
+ printf(" Optimum Pbuffer width: %d\n", optWidth);
+ printf(" Optimum Pbuffer height: %d\n", optHeight);
+
+ printf(" Float Components: %s\n", floatComponents ? "yes" : "no");
+ }
+
+ if (pBuffer) {
+ DestroyPbuffer(dpy, screen, pBuffer);
+ }
+}
+
+
+
+GLXContext
+CreateContext(Display *dpy, int screen, FBCONFIG config)
+{
+ int pbSupport = QueryPbuffers(dpy, screen);
+#if defined(GLX_VERSION_1_3)
+ if (pbSupport == 1) {
+ /* GLX 1.3 */
+ GLXContext c;
+ c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, True);
+ if (!c) {
+ /* try indirect */
+ c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, False);
+ }
+ return c;
+ }
+#endif
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ if (pbSupport == 2) {
+ GLXContext c;
+ c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, True);
+ if (!c) {
+ c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, False);
+ }
+ return c;
+ }
+#endif
+ return 0;
+}
+
+
+void
+DestroyContext(Display *dpy, GLXContext ctx)
+{
+ glXDestroyContext(dpy, ctx);
+}
+
+
+/* This is only used by CreatePbuffer() */
+static int XErrorFlag = 0;
+static int HandleXError(Display *dpy, XErrorEvent *event)
+{
+ XErrorFlag = 1;
+ return 0;
+}
+
+
+/**
+ * Create a Pbuffer. Use an X error handler to deal with potential
+ * BadAlloc errors.
+ *
+ * Input: dpy - the X display
+ * fbConfig - an FBConfig as returned by glXChooseFBConfigSGIX().
+ * width, height - size of pixel buffer to request, in pixels.
+ * pbAttribs - list of optional pixel buffer attributes
+ * Return: a Pbuffer or None.
+ */
+PBUFFER
+CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
+ int width, int height, Bool largest, Bool preserve)
+{
+ int (*oldHandler)(Display *, XErrorEvent *);
+ PBUFFER pBuffer = None;
+ int pbSupport = QueryPbuffers(dpy, screen);
+
+ /* Catch X protocol errors with our own error handler */
+ oldHandler = XSetErrorHandler(HandleXError);
+ XErrorFlag = 0;
+
+#if defined(GLX_VERSION_1_3)
+ if (pbSupport == 1) {
+ /* GLX 1.3 */
+ int attribs[100], i = 0;
+ attribs[i++] = GLX_PBUFFER_WIDTH;
+ attribs[i++] = width;
+ attribs[i++] = GLX_PBUFFER_HEIGHT;
+ attribs[i++] = height;
+ attribs[i++] = GLX_PRESERVED_CONTENTS;
+ attribs[i++] = preserve;
+ attribs[i++] = GLX_LARGEST_PBUFFER;
+ attribs[i++] = largest;
+ attribs[i++] = 0;
+ pBuffer = glXCreatePbuffer(dpy, config, attribs);
+ }
+ else
+#endif
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ if (pbSupport == 2) {
+ int attribs[100], i = 0;
+ attribs[i++] = GLX_PRESERVED_CONTENTS;
+ attribs[i++] = preserve;
+ attribs[i++] = GLX_LARGEST_PBUFFER;
+ attribs[i++] = largest;
+ attribs[i++] = 0;
+ pBuffer = glXCreateGLXPbufferSGIX(dpy, config, width, height, attribs);
+ }
+ else
+#endif
+ {
+ pBuffer = None;
+ }
+
+ /* Restore original X error handler */
+ (void) XSetErrorHandler(oldHandler);
+
+ /* Return pbuffer (may be None) */
+ if (!XErrorFlag && pBuffer != None) {
+ /*printf("config %d worked!\n", i);*/
+ return pBuffer;
+ }
+ else {
+ return None;
+ }
+}
+
+
+void
+DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer)
+{
+ int pbSupport = QueryPbuffers(dpy, screen);
+#if defined(GLX_VERSION_1_3)
+ if (pbSupport == 1) {
+ glXDestroyPbuffer(dpy, pbuffer);
+ return;
+ }
+#endif
+#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+ if (pbSupport == 2) {
+ glXDestroyGLXPbufferSGIX(dpy, pbuffer);
+ return;
+ }
+#endif
+}
diff --git a/progs/xdemos/pbutil.h b/progs/xdemos/pbutil.h
new file mode 100644
index 00000000000..e95b2565a23
--- /dev/null
+++ b/progs/xdemos/pbutil.h
@@ -0,0 +1,66 @@
+/*
+ * OpenGL pbuffers utility functions.
+ *
+ * Brian Paul
+ * April 1997
+ */
+
+
+#ifndef PBUTIL_H
+#define PBUTIL_H
+
+
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/glx.h>
+
+
+#if defined(GLX_VERSION_1_3)
+#define PBUFFER GLXPbuffer
+#define FBCONFIG GLXFBConfig
+#elif defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
+#define PBUFFER GLXPbufferSGIX
+#define FBCONFIG GLXFBConfigSGIX
+#else
+#define PBUFFER int
+#define FBCONFIG int
+#endif
+
+
+extern int
+QueryPbuffers(Display *dpy, int screen);
+
+
+extern void
+PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat);
+
+
+extern FBCONFIG *
+ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs);
+
+
+extern FBCONFIG *
+GetAllFBConfigs(Display *dpy, int screen, int *nConfigs);
+
+
+extern XVisualInfo *
+GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config);
+
+
+extern GLXContext
+CreateContext(Display *dpy, int screen, FBCONFIG config);
+
+
+extern void
+DestroyContext(Display *dpy, GLXContext ctx);
+
+
+extern PBUFFER
+CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
+ int width, int height, Bool preserve, Bool largest);
+
+
+extern void
+DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer);
+
+
+#endif /*PBUTIL_H*/
diff --git a/progs/xdemos/shape.c b/progs/xdemos/shape.c
new file mode 100644
index 00000000000..dbbc0b4ff72
--- /dev/null
+++ b/progs/xdemos/shape.c
@@ -0,0 +1,394 @@
+
+/*
+ * Example of using the X "shape" extension with OpenGL: render a spinning
+ * cube inside of a non-rectangular window.
+ *
+ * Press ESC to exit. Press up/down to change window shape.
+ *
+ * To compile add "shape" to the PROGS list in Makefile.
+ *
+ * Brian Paul
+ * June 16, 1997
+ *
+ * This program is in the public domain.
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/extensions/shape.h>
+#include <GL/glx.h>
+
+#ifndef PI
+#define PI 3.1415926
+#endif
+
+
+static int Width=500, Height=500;
+
+static float Xangle = 0.0, Yangle = 0.0;
+static int Redraw = 0;
+static int Sides = 5;
+static int MinSides = 3;
+static int MaxSides = 20;
+
+
+/* return current time (in seconds) */
+static double
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+
+/*
+ * Draw the OpenGL stuff and do a SwapBuffers.
+ */
+static void display(Display *dpy, Window win)
+{
+ float scale = 1.7;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+
+ glScalef(scale, scale, scale);
+ glRotatef(Xangle, 1.0, 0.0, 0.0);
+ glRotatef(Yangle, 0.0, 1.0, 0.0);
+
+ /*
+ * wireframe box
+ */
+ glColor3f(1.0, 1.0, 1.0);
+ glBegin(GL_LINE_LOOP);
+ glVertex3f(-1.0, -1.0, -1.0);
+ glVertex3f( 1.0, -1.0, -1.0);
+ glVertex3f( 1.0, 1.0, -1.0);
+ glVertex3f(-1.0, 1.0, -1.0);
+ glEnd();
+
+ glBegin(GL_LINE_LOOP);
+ glVertex3f(-1.0, -1.0, 1.0);
+ glVertex3f( 1.0, -1.0, 1.0);
+ glVertex3f( 1.0, 1.0, 1.0);
+ glVertex3f(-1.0, 1.0, 1.0);
+ glEnd();
+
+ glBegin(GL_LINES);
+ glVertex3f(-1.0, -1.0, -1.0); glVertex3f(-1.0, -1.0, 1.0);
+ glVertex3f( 1.0, -1.0, -1.0); glVertex3f( 1.0, -1.0, 1.0);
+ glVertex3f( 1.0, 1.0, -1.0); glVertex3f( 1.0, 1.0, 1.0);
+ glVertex3f(-1.0, 1.0, -1.0); glVertex3f(-1.0, 1.0, 1.0);
+ glEnd();
+
+ /*
+ * Solid box
+ */
+ glPushMatrix();
+ glScalef(0.75, 0.75, 0.75);
+
+ glColor3f(1, 0, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(1, -1, -1);
+ glVertex3f(1, 1, -1);
+ glVertex3f(1, 1, 1);
+ glVertex3f(1, -1, 1);
+ glEnd();
+
+ glColor3f(0, 1, 1);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, -1);
+ glVertex3f(-1, 1, -1);
+ glVertex3f(-1, 1, 1);
+ glVertex3f(-1, -1, 1);
+ glEnd();
+
+ glColor3f(0, 1, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, 1, -1);
+ glVertex3f( 1, 1, -1);
+ glVertex3f( 1, 1, 1);
+ glVertex3f(-1, 1, 1);
+ glEnd();
+
+ glColor3f(1, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, -1);
+ glVertex3f( 1, -1, -1);
+ glVertex3f( 1, -1, 1);
+ glVertex3f(-1, -1, 1);
+ glEnd();
+
+ glColor3f(0, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, 1);
+ glVertex3f( 1, -1, 1);
+ glVertex3f( 1, 1, 1);
+ glVertex3f(-1, 1, 1);
+ glEnd();
+
+ glColor3f(1, 1, 0);
+ glBegin(GL_POLYGON);
+ glVertex3f(-1, -1, -1);
+ glVertex3f( 1, -1, -1);
+ glVertex3f( 1, 1, -1);
+ glVertex3f(-1, 1, -1);
+ glEnd();
+ glPopMatrix();
+
+
+ glPopMatrix();
+
+ glXSwapBuffers(dpy, win);
+}
+
+
+/*
+ * This is called when we have to recompute the window shape bitmask.
+ * We just generate an n-sided regular polygon here but any other shape
+ * would be possible.
+ */
+static void make_shape_mask(Display *dpy, Window win, int width, int height,
+ int sides)
+{
+ Pixmap shapeMask;
+ XGCValues xgcv;
+ GC gc;
+
+ /* allocate 1-bit deep pixmap and a GC */
+ shapeMask = XCreatePixmap(dpy, win, width, height, 1);
+ gc = XCreateGC(dpy, shapeMask, 0, &xgcv);
+
+ /* clear shapeMask to zeros */
+ XSetForeground(dpy, gc, 0);
+ XFillRectangle(dpy, shapeMask, gc, 0, 0, width, height);
+
+ /* draw mask */
+ XSetForeground(dpy, gc, 1);
+ {
+ int cx = width / 2;
+ int cy = height / 2;
+ float angle = 0.0;
+ float step = 2.0 * PI / sides;
+ float radius = width / 2;
+ int i;
+ XPoint points[100];
+ for (i=0;i<sides;i++) {
+ int x = cx + radius * sin(angle);
+ int y = cy - radius * cos(angle);
+ points[i].x = x;
+ points[i].y = y;
+ angle += step;
+ }
+ XFillPolygon(dpy, shapeMask, gc, points, sides, Convex, CoordModeOrigin);
+ }
+
+ /* This is the only SHAPE extension call- simple! */
+ XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, shapeMask, ShapeSet);
+
+ XFreeGC(dpy, gc);
+ XFreePixmap(dpy, shapeMask);
+}
+
+
+/*
+ * Called when window is resized. Do OpenGL viewport and projection stuff.
+ */
+static void reshape(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 3.0, 20.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -10.0);
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+
+/*
+ * Process X events.
+ */
+static void event_loop(Display *dpy, Window win)
+{
+ while (1) {
+ XEvent event;
+ if (XPending(dpy)) {
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ display(dpy, event.xexpose.window);
+ break;
+ case ConfigureNotify:
+ Width = event.xconfigure.width;
+ Height = event.xconfigure.height,
+ make_shape_mask(dpy, win, Width, Height, Sides);
+ reshape(Width, Height);
+ break;
+ case KeyPress:
+ {
+ char buf[100];
+ KeySym keySym;
+ XComposeStatus stat;
+ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
+ switch (keySym) {
+ case XK_Escape:
+ exit(0);
+ break;
+ case XK_Up:
+ Sides++;
+ if (Sides>MaxSides) Sides = MaxSides;
+ make_shape_mask(dpy, win, Width, Height, Sides);
+ break;
+ case XK_Down:
+ Sides--;
+ if (Sides<MinSides) Sides = MinSides;
+ make_shape_mask(dpy, win, Width, Height, Sides);
+ break;
+ }
+ }
+ break;
+ default:
+ ;;
+ }
+ }
+ else {
+ static double t0 = -1.0;
+ double dt, t = current_time();
+ if (t0 < 0.0)
+ t0 = t;
+ dt = t - t0;
+ Xangle += 90.0 * dt; /* 90 degrees per second */
+ Yangle += 70.0 * dt;
+ t0 = t;
+ display(dpy, win);
+ }
+ }
+}
+
+
+/*
+ * Allocate a "nice" colormap. This could be better (HP-CR support, etc).
+ */
+static Colormap alloc_colormap(Display *dpy, Window parent, Visual *vis)
+{
+ Screen *scr = DefaultScreenOfDisplay(dpy);
+ int scrnum = DefaultScreen(dpy);
+
+ if (MaxCmapsOfScreen(scr)==1 && vis==DefaultVisual(dpy, scrnum)) {
+ /* The window and root are of the same visual type so */
+ /* share the root colormap. */
+ return DefaultColormap(dpy, scrnum);
+ }
+ else {
+ return XCreateColormap(dpy, parent, vis, AllocNone);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ static int glAttribs[] = {
+ GLX_DOUBLEBUFFER,
+ GLX_RGBA,
+ GLX_DEPTH_SIZE, 1,
+ None
+ };
+ Display *dpy;
+ XVisualInfo *visInfo;
+ int scrn;
+ Window root;
+ Colormap cmap;
+ Window win;
+ XSetWindowAttributes winAttribs;
+ unsigned long winAttribsMask;
+ GLXContext glCtx;
+ int ignore;
+ const char *name = "OpenGL in a Shaped Window";
+
+ dpy = XOpenDisplay(NULL);
+ if (!dpy) {
+ fprintf(stderr, "Couldn't open default display\n");
+ return 1;
+ }
+
+ /* check that we can use the shape extension */
+ if (!XQueryExtension(dpy, "SHAPE", &ignore, &ignore, &ignore )) {
+ fprintf(stderr, "Display doesn't support shape extension\n");
+ return 1;
+ }
+
+ scrn = DefaultScreen(dpy);
+
+ root = RootWindow(dpy, scrn);
+
+ visInfo = glXChooseVisual(dpy, scrn, glAttribs);
+ if (!visInfo) {
+ fprintf(stderr, "Couldn't get RGB, DB, Z visual\n");
+ return 1;
+ }
+
+ glCtx = glXCreateContext(dpy, visInfo, 0, True);
+ if (!glCtx) {
+ fprintf(stderr, "Couldn't create GL context\n");
+ return 1;
+ }
+
+ cmap = alloc_colormap(dpy, root, visInfo->visual);
+ if (!cmap) {
+ fprintf(stderr, "Couln't create colormap\n");
+ return 1;
+ }
+
+ winAttribs.border_pixel = 0;
+ winAttribs.colormap = cmap;
+ winAttribs.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ winAttribsMask = CWBorderPixel | CWColormap | CWEventMask;
+ win = XCreateWindow(dpy, root, 0, 0, Width, Height, 0,
+ visInfo->depth, InputOutput,
+ visInfo->visual,
+ winAttribsMask, &winAttribs);
+
+ {
+ XSizeHints sizehints;
+ /*
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ */
+ sizehints.flags = 0;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ XMapWindow(dpy, win);
+
+ glXMakeCurrent(dpy, win, glCtx);
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("Press ESC to exit.\n");
+ printf("Press up/down to change window shape.\n");
+
+ event_loop(dpy, win);
+
+ return 0;
+}
diff --git a/progs/xdemos/vgears.c b/progs/xdemos/vgears.c
new file mode 100644
index 00000000000..13d030a8bef
--- /dev/null
+++ b/progs/xdemos/vgears.c
@@ -0,0 +1,282 @@
+/* $ID$ */
+
+/*
+ * Spinning gears demo for Linux SVGA/Mesa interface in 32K color mode.
+ *
+ * Compile with: gcc vgears.c -I../include -L../lib -lMesaGL -lX11 -lXext
+ * -lvga -lm -o vgears
+ *
+ * This program is in the public domain.
+ * Brian Paul, January 1996
+ */
+
+
+#include <vga.h>
+#include <math.h>
+#include "GL/svgamesa.h"
+#include "GL/gl.h"
+
+
+int width = 800, height = 600;
+
+SVGAMesaContext vmc;
+
+
+
+/*
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void gear( GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth )
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth/2.0;
+ r2 = outer_radius + tooth_depth/2.0;
+
+ da = 2.0*M_PI / teeth / 4.0;
+
+ glShadeModel( GL_FLAT );
+
+ glNormal3f( 0.0, 0.0, 1.0 );
+
+ /* draw front face */
+ glBegin( GL_QUAD_STRIP );
+ for (i=0;i<=teeth;i++) {
+ angle = i * 2.0*M_PI / teeth;
+ glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 );
+ glVertex3f( r1*cos(angle), r1*sin(angle), width*0.5 );
+ glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 );
+ glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 );
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin( GL_QUADS );
+ da = 2.0*M_PI / teeth / 4.0;
+ for (i=0;i<teeth;i++) {
+ angle = i * 2.0*M_PI / teeth;
+
+ glVertex3f( r1*cos(angle), r1*sin(angle), width*0.5 );
+ glVertex3f( r2*cos(angle+da), r2*sin(angle+da), width*0.5 );
+ glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5 );
+ glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 );
+ }
+ glEnd();
+
+
+ glNormal3f( 0.0, 0.0, -1.0 );
+
+ /* draw back face */
+ glBegin( GL_QUAD_STRIP );
+ for (i=0;i<=teeth;i++) {
+ angle = i * 2.0*M_PI / teeth;
+ glVertex3f( r1*cos(angle), r1*sin(angle), -width*0.5 );
+ glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 );
+ glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 );
+ glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 );
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin( GL_QUADS );
+ da = 2.0*M_PI / teeth / 4.0;
+ for (i=0;i<teeth;i++) {
+ angle = i * 2.0*M_PI / teeth;
+
+ glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 );
+ glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5 );
+ glVertex3f( r2*cos(angle+da), r2*sin(angle+da), -width*0.5 );
+ glVertex3f( r1*cos(angle), r1*sin(angle), -width*0.5 );
+ }
+ glEnd();
+
+
+ /* draw outward faces of teeth */
+ glBegin( GL_QUAD_STRIP );
+ for (i=0;i<teeth;i++) {
+ angle = i * 2.0*M_PI / teeth;
+
+ glVertex3f( r1*cos(angle), r1*sin(angle), width*0.5 );
+ glVertex3f( r1*cos(angle), r1*sin(angle), -width*0.5 );
+ u = r2*cos(angle+da) - r1*cos(angle);
+ v = r2*sin(angle+da) - r1*sin(angle);
+ len = sqrt( u*u + v*v );
+ u /= len;
+ v /= len;
+ glNormal3f( v, -u, 0.0 );
+ glVertex3f( r2*cos(angle+da), r2*sin(angle+da), width*0.5 );
+ glVertex3f( r2*cos(angle+da), r2*sin(angle+da), -width*0.5 );
+ glNormal3f( cos(angle), sin(angle), 0.0 );
+ glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5 );
+ glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5 );
+ u = r1*cos(angle+3*da) - r2*cos(angle+2*da);
+ v = r1*sin(angle+3*da) - r2*sin(angle+2*da);
+ glNormal3f( v, -u, 0.0 );
+ glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 );
+ glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 );
+ glNormal3f( cos(angle), sin(angle), 0.0 );
+ }
+
+ glVertex3f( r1*cos(0), r1*sin(0), width*0.5 );
+ glVertex3f( r1*cos(0), r1*sin(0), -width*0.5 );
+
+ glEnd();
+
+
+ glShadeModel( GL_SMOOTH );
+
+ /* draw inside radius cylinder */
+ glBegin( GL_QUAD_STRIP );
+ for (i=0;i<=teeth;i++) {
+ angle = i * 2.0*M_PI / teeth;
+ glNormal3f( -cos(angle), -sin(angle), 0.0 );
+ glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 );
+ glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 );
+ }
+ glEnd();
+
+}
+
+
+static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+
+static GLuint limit;
+static GLuint count = 1;
+
+
+static void draw( void )
+{
+ angle += 2.0;
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef( view_rotx, 1.0, 0.0, 0.0 );
+ glRotatef( view_roty, 0.0, 1.0, 0.0 );
+ glRotatef( view_rotz, 0.0, 0.0, 1.0 );
+
+ glPushMatrix();
+ glTranslatef( -3.0, -2.0, 0.0 );
+ glRotatef( angle, 0.0, 0.0, 1.0 );
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef( 3.1, -2.0, 0.0 );
+ glRotatef( -2.0*angle-9.0, 0.0, 0.0, 1.0 );
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef( -3.1, 4.2, 0.0 );
+ glRotatef( -2.0*angle-25.0, 0.0, 0.0, 1.0 );
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+
+ SVGAMesaSwapBuffers();
+}
+
+
+static void init( void )
+{
+ static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0 };
+ static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0 };
+
+ GLfloat w = (float) width / (float) height;
+ GLfloat h = 1.0;
+
+ glLightfv( GL_LIGHT0, GL_POSITION, pos );
+ glEnable( GL_CULL_FACE );
+ glEnable( GL_LIGHTING );
+ glEnable( GL_LIGHT0 );
+ glEnable( GL_DEPTH_TEST );
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red );
+ gear( 1.0, 4.0, 1.0, 20, 0.7 );
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green );
+ gear( 0.5, 2.0, 2.0, 10, 0.7 );
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue );
+ gear( 1.3, 2.0, 0.5, 10, 0.7 );
+ glEndList();
+
+ glEnable( GL_NORMALIZE );
+
+
+ glViewport( 0, 0, width, height );
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ if (width>height) {
+ GLfloat w = (GLfloat) width / (GLfloat) height;
+ glFrustum( -w, w, -1.0, 1.0, 5.0, 60.0 );
+ }
+ else {
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+ glFrustum( -1.0, 1.0, -h, h, 5.0, 60.0 );
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -40.0 );
+}
+
+void setup( void )
+{
+ vga_init();
+
+ vga_setmode(G800x600x32K);
+/* gl_setcontextvga(G800x600x32K);*/
+
+ vmc = SVGAMesaCreateContext(GL_TRUE);
+ SVGAMesaMakeCurrent( vmc );
+}
+
+
+void end( void )
+{
+ SVGAMesaDestroyContext( vmc );
+
+ vga_setmode( TEXT );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ int i;
+
+ setup();
+ init();
+ for (i=0;i<4;i++) {
+ draw(); /*SVGAMesaSwapBuffers();*/
+ }
+ end();
+ return 0;
+}
diff --git a/progs/xdemos/vindex.c b/progs/xdemos/vindex.c
new file mode 100644
index 00000000000..991fce2a591
--- /dev/null
+++ b/progs/xdemos/vindex.c
@@ -0,0 +1,65 @@
+
+/*
+ * Test Linux 8-bit SVGA/Mesa color index mode
+ *
+ * Compile with: gcc vindex.c -I../include -L../lib -lMesaGL -lX11 -lXext
+ * -lvga -lm -o vindex
+ *
+ * This program is in the public domain.
+ * Brian Paul, January 1996
+ */
+
+
+
+#include <vga.h>
+#include "GL/svgamesa.h"
+#include "GL/gl.h"
+
+
+
+static GLint width = 640, height = 480;
+
+
+
+static void display( void )
+{
+ int i, j;
+ int w, h;
+
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, (GLfloat) width, 0.0, (GLfloat) height, -1.0, 1.0 );
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ w = width / 16;
+ h = height / 16;
+ for (i=0;i<16;i++) {
+ for (j=0;j<16;j++) {
+ glIndexi( i*16+j );
+ glRecti( i*w, j*h, i*w+w, j*h+h );
+ }
+ }
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ SVGAMesaContext vmc;
+ int i;
+
+ vga_init();
+ vga_setmode( G640x480x256 );
+
+ vmc = SVGAMesaCreateContext( GL_FALSE );
+ SVGAMesaMakeCurrent( vmc );
+
+ display();
+ sleep(3);
+
+ SVGAMesaDestroyContext( vmc );
+ vga_setmode( TEXT );
+ return 0;
+}
diff --git a/progs/xdemos/vtest.c b/progs/xdemos/vtest.c
new file mode 100644
index 00000000000..e322fbc5c80
--- /dev/null
+++ b/progs/xdemos/vtest.c
@@ -0,0 +1,82 @@
+
+/*
+ * Test SVGA/Mesa interface in 32K color mode.
+ *
+ * Compile with: gcc vtest.c -I../include -L../lib -lMesaGL -lX11 -lXext
+ * -lvga -lm -o vtest
+ *
+ * This program is in the public domain.
+ * Brian Paul, January 1996
+ */
+
+
+
+#include <vga.h>
+#include "GL/svgamesa.h"
+#include "GL/gl.h"
+
+
+SVGAMesaContext vmc;
+
+
+
+void setup( void )
+{
+ vga_init();
+
+ vga_setmode(G800x600x32K);
+/* gl_setcontextvga(G800x600x32K);*/
+
+ vmc = SVGAMesaCreateContext( GL_FALSE ); /* single buffered */
+ SVGAMesaMakeCurrent( vmc );
+}
+
+
+void test( void )
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
+ glMatrixMode(GL_MODELVIEW);
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glBegin( GL_LINES );
+ glColor3f( 1.0, 0.0, 0.0 );
+ glVertex2f( -0.5, 0.5 );
+ glVertex2f( 0.5, 0.5 );
+ glColor3f( 0.0, 1.0, 0.0 );
+ glVertex2f( -0.5, 0.25 );
+ glVertex2f( 0.5, 0.25 );
+ glColor3f( 0.0, 0.0, 1.0 );
+ glVertex2f( -0.5, 0.0 );
+ glVertex2f( 0.5, 0.0 );
+ glEnd();
+
+ glBegin( GL_POLYGON );
+ glColor3f( 1.0, 0.0, 0.0 );
+ glVertex2f( 0.0, 0.7 );
+ glColor3f( 0.0, 1.0, 0.0 );
+ glVertex2f( -0.5, -0.5 );
+ glColor3f( 0.0, 0.0, 1.0 );
+ glVertex2f( 0.5, -0.5 );
+ glEnd();
+
+ sleep(3);
+}
+
+void end( void )
+{
+ SVGAMesaDestroyContext( vmc );
+
+ vga_setmode( TEXT );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ setup();
+ test();
+ end();
+ return 0;
+}
diff --git a/progs/xdemos/wincopy.c b/progs/xdemos/wincopy.c
new file mode 100644
index 00000000000..3ec67dc6724
--- /dev/null
+++ b/progs/xdemos/wincopy.c
@@ -0,0 +1,329 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * This program opens two GLX windows, renders into one and uses
+ * glCopyPixels to copy the image from the first window into the
+ * second by means of the GLX 1.3 function glxMakeContextCurrent().
+ * This function works just like the glXMakeCurrentReadSGI() function
+ * in the GLX_SGI_make_current_read extension.
+ */
+
+
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <X11/keysym.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#ifdef GLX_VERSION_1_3
+
+
+static Display *Dpy;
+static int ScrNum;
+static GLXContext Context;
+static Window Win[2]; /* Win[0] = source, Win[1] = dest */
+static GLint Width[2], Height[2];
+
+static GLfloat Angle = 0.0;
+
+static GLboolean DrawFront = GL_FALSE;
+
+PFNGLXMAKECURRENTREADSGIPROC make_context_current = NULL;
+
+static Window
+CreateWindow(Display *dpy, int scrnum, XVisualInfo *visinfo,
+ int xpos, int ypos, int width, int height,
+ const char *name)
+{
+ Window win;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+
+ root = RootWindow(dpy, scrnum);
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(dpy, root, xpos, ypos, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+ if (win) {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+
+ XMapWindow(dpy, win);
+ }
+ return win;
+}
+
+
+static void
+Redraw(void)
+{
+ /* make the first window the current one */
+ if (! (*make_context_current)(Dpy, Win[0], Win[0], Context)) {
+ printf("glXMakeContextCurrent failed in Redraw()\n");
+ return;
+ }
+
+ Angle += 1.0;
+
+ if (DrawFront) {
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+ }
+ else {
+ glDrawBuffer(GL_BACK);
+ glReadBuffer(GL_BACK);
+ }
+
+ glViewport(0, 0, Width[0], Height[0]);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.5, 0.5, 0.5, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* draw blue quad */
+ glColor3f(0.3, 0.3, 1.0);
+ glPushMatrix();
+ glRotatef(Angle, 0, 0, 1);
+ glBegin(GL_POLYGON);
+ glVertex2f(-0.5, -0.25);
+ glVertex2f( 0.5, -0.25);
+ glVertex2f( 0.5, 0.25);
+ glVertex2f(-0.5, 0.25);
+ glEnd();
+ glPopMatrix();
+
+ if (DrawFront)
+ glFinish();
+ else
+ glXSwapBuffers(Dpy, Win[0]);
+
+
+ /* copy image from window 0 to window 1 */
+ if (!(*make_context_current)(Dpy, Win[1], Win[0], Context)) {
+ printf("glXMakeContextCurrent failed in Redraw()\n");
+ return;
+ }
+
+ /* raster pos setup */
+ glViewport(0, 0, Width[1], Height[1]);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 1);
+ glRasterPos2f(-1, -1);
+
+ /* copy the image between windows */
+ glCopyPixels(0, 0, Width[0], Height[0], GL_COLOR);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ if (DrawFront)
+ glFinish();
+ else
+ glXSwapBuffers(Dpy, Win[1]);
+}
+
+
+
+static void
+Resize(Window win, unsigned int width, unsigned int height)
+{
+ int i;
+ if (win == Win[0]) {
+ i = 0;
+ }
+ else {
+ i = 1;
+ }
+ Width[i] = width;
+ Height[i] = height;
+ if (!glXMakeCurrent(Dpy, Win[i], Context)) {
+ printf("glXMakeCurrent failed in Resize()\n");
+ return;
+ }
+}
+
+
+
+static void
+EventLoop(void)
+{
+ XEvent event;
+ while (1) {
+ if (XPending(Dpy) > 0) {
+ XNextEvent( Dpy, &event );
+ switch (event.type) {
+ case Expose:
+ Redraw();
+ break;
+ case ConfigureNotify:
+ Resize(event.xany.window, event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buf[100];
+ KeySym keySym;
+ XComposeStatus stat;
+ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
+ if (keySym == XK_Escape) {
+ /* exit */
+ return;
+ }
+ else if (buf[0] == 'f') {
+ DrawFront = !DrawFront;
+ printf("Drawing to %s buffer\n",
+ DrawFront ? "GL_FRONT" : "GL_BACK");
+ }
+ }
+ break;
+ default:
+ /*no-op*/ ;
+ }
+ }
+ else {
+ /* animate */
+ Redraw();
+ }
+ }
+}
+
+
+static void
+Init(void)
+{
+ XVisualInfo *visinfo;
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int major, minor;
+
+ Dpy = XOpenDisplay(NULL);
+ if (!Dpy) {
+ printf("Couldn't open default display!\n");
+ exit(1);
+ }
+
+ ScrNum = DefaultScreen(Dpy);
+
+ glXQueryVersion(Dpy, &major, &minor);
+
+ if (major * 100 + minor >= 103) {
+ make_context_current = (PFNGLXMAKECURRENTREADSGIPROC)
+ glXGetProcAddressARB( (GLubyte *) "glXMakeContextCurrent" );
+ }
+ else {
+ const char * const glxExtensions = glXQueryExtensionsString(Dpy, ScrNum);
+ const char * ext = strstr( glxExtensions, "GLX_SGI_make_current_read" );
+ const size_t len = strlen( "GLX_SGI_make_current_read" );
+
+ if ( (ext != NULL)
+ && ((ext[len] == ' ') || (ext[len] == '\0')) ) {
+ make_context_current = (PFNGLXMAKECURRENTREADSGIPROC)
+ glXGetProcAddressARB( (GLubyte *) "glXMakeCurrentReadSGI" );
+ }
+ }
+
+ if (make_context_current == NULL) {
+ fprintf(stderr, "Sorry, this program requires either GLX 1.3 "
+ "or GLX_SGI_make_current_read.\n");
+ exit(1);
+ }
+
+ visinfo = glXChooseVisual(Dpy, ScrNum, attrib);
+ if (!visinfo) {
+ printf("Unable to find RGB, double-buffered visual\n");
+ exit(1);
+ }
+
+ Context = glXCreateContext(Dpy, visinfo, NULL, True);
+ if (!Context) {
+ printf("Couldn't create GLX context\n");
+ exit(1);
+ }
+
+
+ Win[0] = CreateWindow(Dpy, ScrNum, visinfo,
+ 0, 0, 300, 300, "source window");
+
+ Win[1] = CreateWindow(Dpy, ScrNum, visinfo,
+ 350, 0, 300, 300, "dest window");
+
+ printf("Press Esc to exit\n");
+ printf("Press 'f' to toggle front/back buffer drawing\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Init();
+ EventLoop();
+ return 0;
+}
+
+
+#else
+
+
+int
+main(int argc, char *argv[])
+{
+ printf("This program requires GLX 1.3!\n");
+ return 0;
+}
+
+
+#endif /* GLX_VERSION_1_3 */
diff --git a/progs/xdemos/xdemo.c b/progs/xdemos/xdemo.c
new file mode 100644
index 00000000000..52039cb6424
--- /dev/null
+++ b/progs/xdemos/xdemo.c
@@ -0,0 +1,334 @@
+
+/*
+ * Very simple demo of how to use the Mesa/X11 interface instead of the
+ * glx, tk or aux toolkits. I highly recommend using the GLX interface
+ * instead of the X/Mesa interface, however.
+ *
+ * This program is in the public domain.
+ *
+ * Brian Paul
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "GL/xmesa.h"
+#include "GL/gl.h"
+
+
+
+static GLint Black, Red, Green, Blue;
+
+
+
+static void make_window( char *title, int color_flag )
+{
+ int x = 10, y = 10, width = 400, height = 300;
+ Display *dpy;
+ int scr;
+ Window root, win;
+ Colormap cmap;
+ XColor xcolor;
+ int attr_flags;
+ XVisualInfo *visinfo;
+ XSetWindowAttributes attr;
+ XTextProperty tp;
+ XSizeHints sh;
+ XEvent e;
+ XMesaContext context;
+ XMesaVisual visual;
+ XMesaBuffer buffer;
+
+
+ /*
+ * Do the usual X things to make a window.
+ */
+
+ dpy = XOpenDisplay(NULL);
+ if (!dpy) {
+ printf("Couldn't open default display!\n");
+ exit(1);
+ }
+
+ scr = DefaultScreen(dpy);
+ root = RootWindow(dpy, scr);
+
+ /* alloc visinfo struct */
+ visinfo = (XVisualInfo *) malloc( sizeof(XVisualInfo) );
+
+ /* Get a visual and colormap */
+ if (color_flag) {
+ /* Open TrueColor window */
+
+/*
+ if (!XMatchVisualInfo( dpy, scr, 24, TrueColor, visinfo )) {
+ printf("Couldn't get 24-bit TrueColor visual!\n");
+ exit(1);
+ }
+*/
+ if (!XMatchVisualInfo( dpy, scr, 8, PseudoColor, visinfo )) {
+ printf("Couldn't get 8-bit PseudoColor visual!\n");
+ exit(1);
+ }
+
+ cmap = XCreateColormap( dpy, root, visinfo->visual, AllocNone );
+ Black = Red = Green = Blue = 0;
+ }
+ else {
+ /* Open color index window */
+
+ if (!XMatchVisualInfo( dpy, scr, 8, PseudoColor, visinfo )) {
+ printf("Couldn't get 8-bit PseudoColor visual\n");
+ exit(1);
+ }
+
+ cmap = XCreateColormap( dpy, root, visinfo->visual, AllocNone );
+
+ /* Allocate colors */
+ xcolor.red = 0x0;
+ xcolor.green = 0x0;
+ xcolor.blue = 0x0;
+ xcolor.flags = DoRed | DoGreen | DoBlue;
+ if (!XAllocColor( dpy, cmap, &xcolor )) {
+ printf("Couldn't allocate black!\n");
+ exit(1);
+ }
+ Black = xcolor.pixel;
+
+ xcolor.red = 0xffff;
+ xcolor.green = 0x0;
+ xcolor.blue = 0x0;
+ xcolor.flags = DoRed | DoGreen | DoBlue;
+ if (!XAllocColor( dpy, cmap, &xcolor )) {
+ printf("Couldn't allocate red!\n");
+ exit(1);
+ }
+ Red = xcolor.pixel;
+
+ xcolor.red = 0x0;
+ xcolor.green = 0xffff;
+ xcolor.blue = 0x0;
+ xcolor.flags = DoRed | DoGreen | DoBlue;
+ if (!XAllocColor( dpy, cmap, &xcolor )) {
+ printf("Couldn't allocate green!\n");
+ exit(1);
+ }
+ Green = xcolor.pixel;
+
+ xcolor.red = 0x0;
+ xcolor.green = 0x0;
+ xcolor.blue = 0xffff;
+ xcolor.flags = DoRed | DoGreen | DoBlue;
+ if (!XAllocColor( dpy, cmap, &xcolor )) {
+ printf("Couldn't allocate blue!\n");
+ exit(1);
+ }
+ Blue = xcolor.pixel;
+ }
+
+ /* set window attributes */
+ attr.colormap = cmap;
+ attr.event_mask = ExposureMask | StructureNotifyMask;
+ attr.border_pixel = BlackPixel( dpy, scr );
+ attr.background_pixel = BlackPixel( dpy, scr );
+ attr_flags = CWColormap | CWEventMask | CWBorderPixel | CWBackPixel;
+
+ /* Create the window */
+ win = XCreateWindow( dpy, root, x,y, width, height, 0,
+ visinfo->depth, InputOutput,
+ visinfo->visual,
+ attr_flags, &attr);
+ if (!win) {
+ printf("Couldn't open window!\n");
+ exit(1);
+ }
+
+ XStringListToTextProperty(&title, 1, &tp);
+ sh.flags = USPosition | USSize;
+ XSetWMProperties(dpy, win, &tp, &tp, 0, 0, &sh, 0, 0);
+ XMapWindow(dpy, win);
+ while (1) {
+ XNextEvent( dpy, &e );
+ if (e.type == MapNotify && e.xmap.window == win) {
+ break;
+ }
+ }
+
+
+ /*
+ * Now do the special Mesa/Xlib stuff!
+ */
+
+ visual = XMesaCreateVisual( dpy, visinfo,
+ (GLboolean) color_flag,
+ GL_FALSE, /* alpha_flag */
+ GL_FALSE, /* db_flag */
+ GL_FALSE, /* stereo flag */
+ GL_FALSE, /* ximage_flag */
+ 0, /* depth size */
+ 0, /* stencil size */
+ 0,0,0,0, /* accum_size */
+ 0, /* num samples */
+ 0, /* level */
+ 0 /* caveat */
+ );
+ if (!visual) {
+ printf("Couldn't create Mesa/X visual!\n");
+ exit(1);
+ }
+
+ /* Create a Mesa rendering context */
+ context = XMesaCreateContext( visual,
+ NULL /* share_list */
+ );
+ if (!context) {
+ printf("Couldn't create Mesa/X context!\n");
+ exit(1);
+ }
+
+ buffer = XMesaCreateWindowBuffer( visual, win );
+ if (!buffer) {
+ printf("Couldn't create Mesa/X buffer!\n");
+ exit(1);
+ }
+
+
+ XMesaMakeCurrent( context, buffer );
+
+ /* Ready to render! */
+}
+
+
+
+static void draw_cube( void )
+{
+ /* X faces */
+ glIndexi( Red );
+ glColor3f( 1.0, 0.0, 0.0 );
+ glBegin( GL_POLYGON );
+ glVertex3f( 1.0, 1.0, 1.0 );
+ glVertex3f( 1.0, -1.0, 1.0 );
+ glVertex3f( 1.0, -1.0, -1.0 );
+ glVertex3f( 1.0, 1.0, -1.0 );
+ glEnd();
+
+ glBegin( GL_POLYGON );
+ glVertex3f( -1.0, 1.0, 1.0 );
+ glVertex3f( -1.0, 1.0, -1.0 );
+ glVertex3f( -1.0, -1.0, -1.0 );
+ glVertex3f( -1.0, -1.0, 1.0 );
+ glEnd();
+
+ /* Y faces */
+ glIndexi( Green );
+ glColor3f( 0.0, 1.0, 0.0 );
+ glBegin( GL_POLYGON );
+ glVertex3f( 1.0, 1.0, 1.0 );
+ glVertex3f( 1.0, 1.0, -1.0 );
+ glVertex3f( -1.0, 1.0, -1.0 );
+ glVertex3f( -1.0, 1.0, 1.0 );
+ glEnd();
+
+ glBegin( GL_POLYGON );
+ glVertex3f( 1.0, -1.0, 1.0 );
+ glVertex3f( -1.0, -1.0, 1.0 );
+ glVertex3f( -1.0, -1.0, -1.0 );
+ glVertex3f( 1.0, -1.0, -1.0 );
+ glEnd();
+
+ /* Z faces */
+ glIndexi( Blue );
+ glColor3f( 0.0, 0.0, 1.0 );
+ glBegin( GL_POLYGON );
+ glVertex3f( 1.0, 1.0, 1.0 );
+ glVertex3f( -1.0, 1.0, 1.0 );
+ glVertex3f( -1.0, -1.0, 1.0 );
+ glVertex3f( 1.0, -1.0, 1.0 );
+ glEnd();
+
+ glBegin( GL_POLYGON );
+ glVertex3f( 1.0, 1.0, -1.0 );
+ glVertex3f( 1.0,-1.0, -1.0 );
+ glVertex3f( -1.0,-1.0, -1.0 );
+ glVertex3f( -1.0, 1.0, -1.0 );
+ glEnd();
+}
+
+
+
+
+static void display_loop( void )
+{
+ GLfloat xrot, yrot, zrot;
+
+ xrot = yrot = zrot = 0.0;
+
+ glClearColor( 0.0, 0.0, 0.0, 0.0 );
+ glClearIndex( Black );
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 10.0 );
+ glTranslatef( 0.0, 0.0, -5.0 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glCullFace( GL_BACK );
+ glEnable( GL_CULL_FACE );
+
+ glShadeModel( GL_FLAT );
+
+ while (1) {
+ glClear( GL_COLOR_BUFFER_BIT );
+ glPushMatrix();
+ glRotatef( xrot, 1.0, 0.0, 0.0 );
+ glRotatef( yrot, 0.0, 1.0, 0.0 );
+ glRotatef( zrot, 0.0, 0.0, 1.0 );
+
+ draw_cube();
+
+ glPopMatrix();
+ glFinish();
+
+ xrot += 10.0;
+ yrot += 7.0;
+ zrot -= 3.0;
+ }
+
+}
+
+
+
+
+int main( int argc, char *argv[] )
+{
+ int mode = 0;
+
+ if (argc >= 2)
+ {
+ if (strcmp(argv[1],"-ci")==0)
+ mode = 0;
+ else if (strcmp(argv[1],"-rgb")==0)
+ mode = 1;
+ else
+ {
+ printf("Bad flag: %s\n", argv[1]);
+ printf("Specify -ci for 8-bit color index or -rgb for RGB mode\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ printf("Specify -ci for 8-bit color index or -rgb for RGB mode\n");
+ printf("Defaulting to 8-bit color index\n");
+ }
+
+ make_window( argv[0], mode );
+
+ display_loop();
+ return 0;
+}
+
diff --git a/progs/xdemos/xfont.c b/progs/xdemos/xfont.c
new file mode 100644
index 00000000000..2585aa6447c
--- /dev/null
+++ b/progs/xdemos/xfont.c
@@ -0,0 +1,206 @@
+
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Example of using glXUseXFont().
+ * 5 November 1999
+ * Brian Paul
+ */
+
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static const char *ProgramName = "xfont";
+
+static const char *FontName = "fixed";
+
+static GLuint FontBase = 0;
+
+
+
+static void redraw( Display *dpy, Window w )
+{
+ static const char *text = "This is glXUseXFont()";
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ /* triangle */
+ glColor3f( 0.2, 0.2, 1.0 );
+ glBegin(GL_TRIANGLES);
+ glVertex2f( 0, 0.8 );
+ glVertex2f( -0.8, -0.7 );
+ glVertex2f( 0.8, -0.7 );
+ glEnd();
+
+ /* text */
+ glColor3f( 1, 1, 1 );
+ glRasterPos2f(-0.8, 0);
+ glListBase(FontBase);
+ glCallLists(strlen(text), GL_UNSIGNED_BYTE, (GLubyte *) text);
+
+ glXSwapBuffers( dpy, w );
+}
+
+
+
+static void resize( unsigned int width, unsigned int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
+}
+
+
+
+static void setup_font( Display *dpy )
+{
+ XFontStruct *fontInfo;
+ Font id;
+ unsigned int first, last;
+
+ fontInfo = XLoadQueryFont(dpy, FontName);
+ if (!fontInfo) {
+ printf("Error: font %s not found\n", FontName);
+ exit(0);
+ }
+
+ id = fontInfo->fid;
+ first = fontInfo->min_char_or_byte2;
+ last = fontInfo->max_char_or_byte2;
+
+ FontBase = glGenLists((GLuint) last + 1);
+ if (!FontBase) {
+ printf("Error: unable to allocate display lists\n");
+ exit(0);
+ }
+ glXUseXFont(id, first, last - first + 1, FontBase + first);
+}
+
+static Window make_rgb_db_window( Display *dpy, int xpos, int ypos,
+ unsigned int width, unsigned int height )
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, ProgramName, ProgramName,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+
+ glXMakeCurrent( dpy, win, ctx );
+
+ return win;
+}
+
+
+static void event_loop( Display *dpy )
+{
+ XEvent event;
+
+ while (1) {
+ XNextEvent( dpy, &event );
+
+ switch (event.type) {
+ case Expose:
+ redraw( dpy, event.xany.window );
+ break;
+ case ConfigureNotify:
+ resize( event.xconfigure.width, event.xconfigure.height );
+ break;
+ case KeyPress:
+ exit(0);
+ default:
+ ; /* no-op */
+ }
+ }
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ Display *dpy;
+ Window win;
+
+ dpy = XOpenDisplay(NULL);
+
+ win = make_rgb_db_window( dpy, 0, 0, 300, 300 );
+ setup_font( dpy );
+
+ glShadeModel( GL_FLAT );
+ glClearColor( 0.5, 0.5, 1.0, 1.0 );
+
+ XMapWindow( dpy, win );
+
+ event_loop( dpy );
+ return 0;
+}
diff --git a/progs/xdemos/xrotfontdemo.c b/progs/xdemos/xrotfontdemo.c
new file mode 100644
index 00000000000..58cd0286cc6
--- /dev/null
+++ b/progs/xdemos/xrotfontdemo.c
@@ -0,0 +1,220 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Example of using glXUseRotatedXFontMESA().
+ * 24 Jan 2004
+ * Brian Paul
+ */
+
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xuserotfont.h"
+
+
+static const char *ProgramName = "xfont";
+
+static const char *FontName = "fixed";
+
+static GLuint FontBase[4];
+
+
+static void redraw( Display *dpy, Window w )
+{
+ static const char *text = " Rotated bitmap text";
+ int i;
+
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ /* triangle */
+ glColor3f( 0.2, 0.2, 1.0 );
+ glBegin(GL_TRIANGLES);
+ glVertex2f( -0.8, 0.7 );
+ glVertex2f( -0.8, -0.7 );
+ glVertex2f( 0.8, 0.0 );
+ glEnd();
+
+ /* marker */
+ glColor3f( 0, 1, 0 );
+ glBegin(GL_POINTS);
+ glVertex2f(0, 0);
+ glEnd();
+
+ /* text */
+ glColor3f( 1, 1, 1 );
+
+ for (i = 0; i < 4; i++) {
+ glRasterPos2f(0, 0);
+ glListBase(FontBase[i]);
+ glCallLists(strlen(text), GL_UNSIGNED_BYTE, (GLubyte *) text);
+ }
+
+ glXSwapBuffers( dpy, w );
+}
+
+
+
+static void resize( unsigned int width, unsigned int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
+}
+
+
+
+static void setup_font( Display *dpy )
+{
+ XFontStruct *fontInfo;
+ Font id;
+ unsigned int first, last;
+ int i;
+
+ fontInfo = XLoadQueryFont(dpy, FontName);
+ if (!fontInfo) {
+ printf("Error: font %s not found\n", FontName);
+ exit(0);
+ }
+
+ id = fontInfo->fid;
+ first = fontInfo->min_char_or_byte2;
+ last = fontInfo->max_char_or_byte2;
+
+ for (i = 0; i < 4; i++) {
+ FontBase[i] = glGenLists((GLuint) last + 1);
+ if (!FontBase[i]) {
+ printf("Error: unable to allocate display lists\n");
+ exit(0);
+ }
+ glXUseRotatedXFontMESA(id, first, last - first + 1, FontBase[i] + first,
+ i * 90);
+ }
+}
+
+
+static Window make_rgb_db_window( Display *dpy, int xpos, int ypos,
+ unsigned int width, unsigned int height )
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ {
+ XSizeHints sizehints;
+ sizehints.x = xpos;
+ sizehints.y = ypos;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, ProgramName, ProgramName,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+
+ glXMakeCurrent( dpy, win, ctx );
+
+ return win;
+}
+
+
+static void event_loop( Display *dpy )
+{
+ XEvent event;
+
+ while (1) {
+ XNextEvent( dpy, &event );
+
+ switch (event.type) {
+ case Expose:
+ redraw( dpy, event.xany.window );
+ break;
+ case ConfigureNotify:
+ resize( event.xconfigure.width, event.xconfigure.height );
+ break;
+ case KeyPress:
+ exit(0);
+ default:
+ ; /* no-op */
+ }
+ }
+}
+
+
+
+int main( int argc, char *argv[] )
+{
+ Display *dpy;
+ Window win;
+
+ dpy = XOpenDisplay(NULL);
+
+ win = make_rgb_db_window( dpy, 0, 0, 300, 300 );
+ setup_font( dpy );
+
+ glShadeModel( GL_FLAT );
+ glClearColor( 0.5, 0.5, 1.0, 1.0 );
+
+ XMapWindow( dpy, win );
+
+ event_loop( dpy );
+ return 0;
+}
diff --git a/progs/xdemos/xuserotfont.c b/progs/xdemos/xuserotfont.c
new file mode 100644
index 00000000000..adb849511d8
--- /dev/null
+++ b/progs/xdemos/xuserotfont.c
@@ -0,0 +1,399 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/* \file xuserotfont.c
+ *
+ * A function like glXUseXFont() but takes a 0, 90, 180 or 270 degree
+ * rotation angle for rotated text display.
+ *
+ * Based on Mesa's glXUseXFont implementation written by Thorsten Ohl.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <GL/glx.h>
+#include "xuserotfont.h"
+
+
+/**
+ * Generate OpenGL-compatible bitmap by drawing an X character glyph
+ * to an off-screen pixmap, then getting the image and testing pixels.
+ * \param width bitmap width in pixels
+ * \param height bitmap height in pixels
+ */
+static void
+fill_bitmap(Display *dpy, Pixmap pixmap, GC gc,
+ unsigned int bitmapWidth, unsigned int bitmapHeight,
+ unsigned int charWidth, unsigned int charHeight,
+ int xPos, int yPos, unsigned int c, GLubyte * bitmap,
+ int rotation)
+{
+ const int bytesPerRow = (bitmapWidth + 7) / 8;
+ XImage *image;
+ XChar2b char2b;
+
+ /* clear pixmap to 0 */
+ XSetForeground(dpy, gc, 0);
+ XFillRectangle(dpy, pixmap, gc, 0, 0, charWidth, charHeight);
+
+ /* The glyph is drawn snug up against the left/top edges of the pixmap */
+ XSetForeground(dpy, gc, 1);
+ char2b.byte1 = (c >> 8) & 0xff;
+ char2b.byte2 = (c & 0xff);
+ XDrawString16(dpy, pixmap, gc, xPos, yPos, &char2b, 1);
+
+ /* initialize GL bitmap */
+ memset(bitmap, 0, bytesPerRow * bitmapHeight);
+
+ image = XGetImage(dpy, pixmap, 0, 0, charWidth, charHeight, 1, XYPixmap);
+ if (image) {
+ /* Set appropriate bits in the GL bitmap.
+ * Note: X11 and OpenGL are upside down wrt each other).
+ */
+ unsigned int x, y;
+ if (rotation == 0) {
+ for (y = 0; y < charHeight; y++) {
+ for (x = 0; x < charWidth; x++) {
+ if (XGetPixel(image, x, y)) {
+ int y2 = bitmapHeight - y - 1;
+ bitmap[bytesPerRow * y2 + x / 8] |= (1 << (7 - (x % 8)));
+ }
+ }
+ }
+ }
+ else if (rotation == 90) {
+ for (y = 0; y < charHeight; y++) {
+ for (x = 0; x < charWidth; x++) {
+ if (XGetPixel(image, x, y)) {
+ int x2 = y;
+ int y2 = x;
+ bitmap[bytesPerRow * y2 + x2 / 8] |= (1 << (7 - (x2 % 8)));
+ }
+ }
+ }
+ }
+ else if (rotation == 180) {
+ for (y = 0; y < charHeight; y++) {
+ for (x = 0; x < charWidth; x++) {
+ if (XGetPixel(image, x, y)) {
+ int x2 = charWidth - x - 1;
+ bitmap[bytesPerRow * y + x2 / 8] |= (1 << (7 - (x2 % 8)));
+ }
+ }
+ }
+ }
+ else {
+ assert(rotation == 270);
+ for (y = 0; y < charHeight; y++) {
+ for (x = 0; x < charWidth; x++) {
+ if (XGetPixel(image, x, y)) {
+ int x2 = charHeight - y - 1;
+ int y2 = charWidth - x - 1;
+ bitmap[bytesPerRow * y2 + x2 / 8] |= (1 << (7 - (x2 % 8)));
+ }
+ }
+ }
+ }
+ XDestroyImage(image);
+ }
+}
+
+
+/*
+ * Determine if a given glyph is valid and return the
+ * corresponding XCharStruct.
+ */
+static const XCharStruct *
+isvalid(const XFontStruct * fs, unsigned int which)
+{
+ unsigned int rows, pages;
+ unsigned int byte1 = 0, byte2 = 0;
+ int i, valid = 1;
+
+ rows = fs->max_byte1 - fs->min_byte1 + 1;
+ pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
+
+ if (rows == 1) {
+ /* "linear" fonts */
+ if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
+ valid = 0;
+ }
+ else {
+ /* "matrix" fonts */
+ byte2 = which & 0xff;
+ byte1 = which >> 8;
+ if ((fs->min_char_or_byte2 > byte2) ||
+ (fs->max_char_or_byte2 < byte2) ||
+ (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
+ valid = 0;
+ }
+
+ if (valid) {
+ if (fs->per_char) {
+ if (rows == 1) {
+ /* "linear" fonts */
+ return fs->per_char + (which - fs->min_char_or_byte2);
+ }
+ else {
+ /* "matrix" fonts */
+ i = ((byte1 - fs->min_byte1) * pages) +
+ (byte2 - fs->min_char_or_byte2);
+ return fs->per_char + i;
+ }
+ }
+ else {
+ return &fs->min_bounds;
+ }
+ }
+ return NULL;
+}
+
+
+void
+glXUseRotatedXFontMESA(Font font, int first, int count, int listbase,
+ int rotation)
+{
+ Display *dpy;
+ Window win;
+ Pixmap pixmap;
+ GC gc;
+ XFontStruct *fs;
+ GLint swapbytes, lsbfirst, rowlength;
+ GLint skiprows, skippixels, alignment;
+ unsigned int maxCharWidth, maxCharHeight;
+ GLubyte *bm;
+ int i;
+
+ if (rotation != 0 &&
+ rotation != 90 &&
+ rotation != 180 &&
+ rotation != 270)
+ return;
+
+ dpy = glXGetCurrentDisplay();
+ if (!dpy)
+ return; /* I guess glXMakeCurrent wasn't called */
+ win = RootWindow(dpy, DefaultScreen(dpy));
+
+ fs = XQueryFont(dpy, font);
+ if (!fs) {
+ /*
+ _mesa_error(NULL, GL_INVALID_VALUE,
+ "Couldn't get font structure information");
+ */
+ return;
+ }
+
+ /* Allocate a GL bitmap that can fit any character */
+ maxCharWidth = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
+ maxCharHeight = fs->max_bounds.ascent + fs->max_bounds.descent;
+ /* use max, in case we're rotating */
+ if (rotation == 90 || rotation == 270) {
+ /* swap width/height */
+ bm = (GLubyte *) malloc((maxCharHeight + 7) / 8 * maxCharWidth);
+ }
+ else {
+ /* normal or upside down */
+ bm = (GLubyte *) malloc((maxCharWidth + 7) / 8 * maxCharHeight);
+ }
+ if (!bm) {
+ XFreeFontInfo(NULL, fs, 1);
+ /*
+ _mesa_error(NULL, GL_OUT_OF_MEMORY,
+ "Couldn't allocate bitmap in glXUseXFont()");
+ */
+ return;
+ }
+
+#if 0
+ /* get the page info */
+ pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
+ firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
+ lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
+ rows = fs->max_byte1 - fs->min_byte1 + 1;
+ unsigned int first_char, last_char, pages, rows;
+#endif
+
+ /* Save the current packing mode for bitmaps. */
+ glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
+ glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
+ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
+ glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
+ glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+
+ /* Enforce a standard packing mode which is compatible with
+ fill_bitmap() from above. This is actually the default mode,
+ except for the (non)alignment. */
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ /* Create pixmap and GC */
+ pixmap = XCreatePixmap(dpy, win, maxCharWidth, maxCharHeight, 1);
+ {
+ XGCValues values;
+ unsigned long valuemask;
+ values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
+ values.background = WhitePixel(dpy, DefaultScreen(dpy));
+ values.font = fs->fid;
+ valuemask = GCForeground | GCBackground | GCFont;
+ gc = XCreateGC(dpy, pixmap, valuemask, &values);
+ }
+
+#ifdef DEBUG_XROT
+ if (debug_xfonts)
+ dump_font_struct(fs);
+#endif
+
+ for (i = 0; i < count; i++) {
+ const unsigned int c = first + i;
+ const int list = listbase + i;
+ unsigned int charWidth, charHeight;
+ unsigned int bitmapWidth = 0, bitmapHeight = 0;
+ GLfloat xOrig, yOrig, xStep, yStep, dtemp;
+ const XCharStruct *ch;
+ int xPos, yPos;
+ int valid;
+
+ /* check on index validity and get the bounds */
+ ch = isvalid(fs, c);
+ if (!ch) {
+ ch = &fs->max_bounds;
+ valid = 0;
+ }
+ else {
+ valid = 1;
+ }
+
+#ifdef DEBUG_XROT
+ if (debug_xfonts) {
+ char s[7];
+ sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
+ dump_char_struct(ch, s);
+ }
+#endif
+
+ /* glBitmap()' parameters:
+ straight from the glXUseXFont(3) manpage. */
+ charWidth = ch->rbearing - ch->lbearing;
+ charHeight = ch->ascent + ch->descent;
+ xOrig = -ch->lbearing;
+ yOrig = ch->descent;
+ xStep = ch->width;
+ yStep = 0;
+
+ /* X11's starting point. */
+ xPos = -ch->lbearing;
+ yPos = ch->ascent;
+
+ /* Apply rotation */
+ switch (rotation) {
+ case 0:
+ /* nothing */
+ bitmapWidth = charWidth;
+ bitmapHeight = charHeight;
+ break;
+ case 90:
+ /* xStep, yStep */
+ dtemp = xStep;
+ xStep = -yStep;
+ yStep = dtemp;
+ /* xOrig, yOrig */
+ yOrig = xOrig;
+ xOrig = charHeight - (charHeight - yPos);
+ /* width, height */
+ bitmapWidth = charHeight;
+ bitmapHeight = charWidth;
+ break;
+ case 180:
+ /* xStep, yStep */
+ xStep = -xStep;
+ yStep = -yStep;
+ /* xOrig, yOrig */
+ xOrig = charWidth - xOrig - 1;
+ yOrig = charHeight - yOrig - 1;
+ bitmapWidth = charWidth;
+ bitmapHeight = charHeight;
+ break;
+ case 270:
+ /* xStep, yStep */
+ dtemp = xStep;
+ xStep = yStep;
+ yStep = -dtemp;
+ /* xOrig, yOrig */
+ dtemp = yOrig;
+ yOrig = charWidth - xOrig;
+ xOrig = dtemp;
+ /* width, height */
+ bitmapWidth = charHeight;
+ bitmapHeight = charWidth;
+ break;
+ default:
+ /* should never get here */
+ ;
+ }
+
+ glNewList(list, GL_COMPILE);
+ if (valid && bitmapWidth > 0 && bitmapHeight > 0) {
+
+ fill_bitmap(dpy, pixmap, gc, bitmapWidth, bitmapHeight,
+ charWidth, charHeight,
+ xPos, yPos, c, bm, rotation);
+
+ glBitmap(bitmapWidth, bitmapHeight, xOrig, yOrig, xStep, yStep, bm);
+
+#ifdef DEBUG_XROT
+ if (debug_xfonts) {
+ printf("width/height = %u/%u\n", bitmapWidth, bitmapHeight);
+ dump_bitmap(bitmapWidth, bitmapHeight, bm);
+ }
+#endif
+ }
+ else {
+ glBitmap(0, 0, 0.0, 0.0, xStep, yStep, NULL);
+ }
+ glEndList();
+ }
+
+ free(bm);
+ XFreeFontInfo(NULL, fs, 1);
+ XFreePixmap(dpy, pixmap);
+ XFreeGC(dpy, gc);
+
+ /* Restore saved packing modes. */
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+}
+
+
diff --git a/progs/xdemos/xuserotfont.h b/progs/xdemos/xuserotfont.h
new file mode 100644
index 00000000000..ea49203b7b9
--- /dev/null
+++ b/progs/xdemos/xuserotfont.h
@@ -0,0 +1,12 @@
+#ifndef XUSEROTFONT_H
+#define XUSEROTFONT_H
+
+#include <X11/Xlib.h>
+
+
+extern void
+glXUseRotatedXFontMESA(Font font, int first, int count, int listbase,
+ int rotation);
+
+
+#endif
diff --git a/progs/xdemos/yuvrect_client.c b/progs/xdemos/yuvrect_client.c
new file mode 100644
index 00000000000..48f82cb7599
--- /dev/null
+++ b/progs/xdemos/yuvrect_client.c
@@ -0,0 +1,326 @@
+/*
+ * Test the GL_NV_texture_rectangle and GL_MESA_ycrcb_texture extensions and GLX_MESA_allocate-memory
+ *
+ * Dave Airlie - Feb 2005
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glx.h>
+
+#include "../util/readtex.c" /* I know, this is a hack. */
+
+#define TEXTURE_FILE "../images/girl2.rgb"
+
+static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
+static GLint ImgWidth, ImgHeight;
+static GLushort *ImageYUV = NULL;
+static void *glx_memory;
+
+static void DrawObject(void)
+{
+ glBegin(GL_QUADS);
+
+ glTexCoord2f(0, 0);
+ glVertex2f(-1.0, -1.0);
+
+ glTexCoord2f(ImgWidth, 0);
+ glVertex2f(1.0, -1.0);
+
+ glTexCoord2f(ImgWidth, ImgHeight);
+ glVertex2f(1.0, 1.0);
+
+ glTexCoord2f(0, ImgHeight);
+ glVertex2f(-1.0, 1.0);
+
+ glEnd();
+}
+
+
+static void scr_Display( void )
+{
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ glPushMatrix();
+ glRotatef(Xrot, 1.0, 0.0, 0.0);
+ glRotatef(Yrot, 0.0, 1.0, 0.0);
+ glRotatef(Zrot, 0.0, 0.0, 1.0);
+ DrawObject();
+ glPopMatrix();
+
+}
+
+
+static void Reshape( int width, int height )
+{
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+static int queryClient(Display *dpy, int screen)
+{
+#ifdef GLX_MESA_allocate_memory
+ char *extensions;
+
+ extensions = (char *)glXQueryExtensionsString(dpy, screen);
+ if (!extensions || !strstr(extensions,"GLX_MESA_allocate_memory")) {
+ return 0;
+ }
+
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+static int
+query_extension(char* extName) {
+ char *p = (char *) glGetString(GL_EXTENSIONS);
+ char *end = p + strlen(p);
+ while (p < end) {
+ int n = strcspn(p, " ");
+ if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0))
+ return GL_TRUE;
+ p += (n + 1);
+ }
+ return GL_FALSE;
+}
+
+static void Init( int argc, char *argv[] , Display *dpy, int screen, Window win)
+{
+ GLuint texObj = 100;
+ const char *file;
+ void *glx_memory;
+
+ if (!query_extension("GL_NV_texture_rectangle")) {
+ printf("Sorry, GL_NV_texture_rectangle is required\n");
+ exit(0);
+ }
+
+ if (!query_extension("GL_MESA_ycbcr_texture")) {
+ printf("Sorry, GL_MESA_ycbcr_texture is required\n");
+ exit(0);
+ }
+
+ if (!queryClient(dpy, screen)) {
+ printf("Sorry, GLX_MESA_allocate_memory is required\n");
+ exit(0);
+ }
+
+ glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, 1);
+ glBindTexture(GL_TEXTURE_RECTANGLE_NV, texObj);
+#ifdef LINEAR_FILTER
+ /* linear filtering looks much nicer but is much slower for Mesa */
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#else
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#endif
+
+ if (argc > 1)
+ file = argv[1];
+ else
+ file = TEXTURE_FILE;
+
+ ImageYUV = LoadYUVImage(file, &ImgWidth, &ImgHeight);
+ if (!ImageYUV) {
+ printf("Couldn't read %s\n", TEXTURE_FILE);
+ exit(0);
+ }
+
+ glx_memory = glXAllocateMemoryMESA(dpy, screen, ImgWidth * ImgHeight * 2, 0, 0 ,0);
+ if (!glx_memory)
+ {
+ fprintf(stderr,"Failed to allocate MESA memory\n");
+ exit(-1);
+ }
+
+ memcpy(glx_memory, ImageYUV, ImgWidth * ImgHeight * 2);
+
+ printf("Image: %dx%d\n", ImgWidth, ImgHeight);
+
+ glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0,
+ GL_YCBCR_MESA, ImgWidth, ImgHeight, 0,
+ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_APPLE, glx_memory);
+
+ assert(glGetError() == GL_NO_ERROR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glEnable(GL_TEXTURE_RECTANGLE_NV);
+
+ glShadeModel(GL_FLAT);
+ glClearColor(0.3, 0.3, 0.4, 1.0);
+
+}
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet)
+{
+ int attribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attribs );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ attr.override_redirect = 0;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win)
+{
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ Reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+
+ }
+ }
+ }
+ }
+
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ char *dpyName = NULL;
+ GLboolean printInfo = GL_FALSE;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ else
+ printf("Warrning: unknown parameter: %s\n", argv[i]);
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n",
+ dpyName ? dpyName : getenv("DISPLAY"));
+ return -1;
+ }
+
+ make_window(dpy, "yuvrect_client", 0, 0, 300, 300, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+ Init(argc, argv, dpy, DefaultScreen(dpy), win);
+
+ scr_Display();
+ glXSwapBuffers(dpy, win);
+ event_loop(dpy, win);
+
+ glXFreeMemoryMESA(dpy, DefaultScreen(dpy), glx_memory);
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}