diff options
author | Thierry Reding <[email protected]> | 2006-10-14 03:46:41 +0000 |
---|---|---|
committer | Thierry Reding <[email protected]> | 2006-10-14 03:46:41 +0000 |
commit | 1ddf606332a188e46a47607cd41eb5d81bdf4c8a (patch) | |
tree | 8cb51078803106d87aedeae7bbd7a762a0d369d1 /progs/xdemos |
Import Mesa 6.5.1 (MesaLib, MesaDemos, MesaGLUT).
Diffstat (limited to 'progs/xdemos')
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; +} |