From 1f75542012f665a5ee9659fa78574977266b900d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 12 Apr 2010 02:26:42 +0200 Subject: grub-bin: set same section as grub --- package/grub-bin/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'package') diff --git a/package/grub-bin/Makefile b/package/grub-bin/Makefile index f7ae5c08b..df8a0d9d3 100644 --- a/package/grub-bin/Makefile +++ b/package/grub-bin/Makefile @@ -10,7 +10,7 @@ PKG_VERSION:= 1.97.1 PKG_RELEASE:= 1 PKG_MD5SUM:= 24961a39e63d8ec16d765aad3a301cda PKG_DESCR:= GRUB bootloader -PKG_SECTION:= sys +PKG_SECTION:= base PKG_SITES:= http://openadk.org/distfiles/ PKG_TARGET_DEPENDS:= x86 x86_64 -- cgit v1.2.3 From e1e56a0d326e753654a224e012d2d38142107cbc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 12 Apr 2010 23:19:08 +0200 Subject: asterisk: default astdatadir to /usr/lib/asterisk This is needed in order for asterisk to find the sound files we provide (and I found adding a symlink from the sounds dir to /var/lib/asterisk/ being just too ugly). As it changes only the default configuration, I guess this is fine without increasing PKG_RELEASE. --- package/asterisk/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'package') diff --git a/package/asterisk/Makefile b/package/asterisk/Makefile index c35e686a5..c7ec0c0fa 100644 --- a/package/asterisk/Makefile +++ b/package/asterisk/Makefile @@ -174,6 +174,7 @@ do-install: ${SUB_INSTALLS-m} ${SUB_INSTALLS-y} rm -f gtalk.conf ; \ rm -f skinny.conf ; \ rm -f dundi.conf ; \ + echo -e '/^astdatadir =/s/var/usr/\nwq\n' | ed asterisk.conf ; \ ) ${INSTALL_DATA} ./files/modules.conf $(IDIR_ASTERISK)/etc/asterisk/ $(SED) 's|/var/lib/asterisk|/usr/lib/asterisk|g' \ -- cgit v1.2.3 From ed46beee877b0f659fa83049ecb0e50885a41257 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 12 Apr 2010 23:37:17 +0200 Subject: asterisk-sounds: do not install useless files Still leave that sounds.xml in there, as I'm not sure what it is for. And besides, with 5k of plain text size it shouldn't hurt too much if you already have space for the sounds package. :) --- package/asterisk/Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'package') diff --git a/package/asterisk/Makefile b/package/asterisk/Makefile index c7ec0c0fa..a6b3ef4a6 100644 --- a/package/asterisk/Makefile +++ b/package/asterisk/Makefile @@ -192,8 +192,11 @@ asterisk-sounds-install: ${INSTALL_DIR} $(IDIR_ASTERISK_SOUNDS)/usr/lib/asterisk/sounds $(CP) $(WRKBUILD)/sounds/* \ $(IDIR_ASTERISK_SOUNDS)/usr/lib/asterisk/sounds/ - rm -f $(IDIR_ASTERISK_SOUNDS)/usr/lib/asterisk/sounds/*.mp3 - rm -f $(IDIR_ASTERISK_SOUNDS)/usr/lib/asterisk/sounds/vm-* + (cd $(IDIR_ASTERISK_SOUNDS)/usr/lib/asterisk/sounds; \ + rm -f *.mp3 vm-*; \ + rm -f CHANGES* CREDITS* LICENSE* *.txt ; \ + rm -f *.tar.gz Makefile ; \ + ) asterisk-voicemail-install: ${INSTALL_DIR} $(IDIR_ASTERISK_VOICEMAIL)/etc/asterisk -- cgit v1.2.3 From 1d99bed8cd4a9c1fa942bbb094259ffd0ea6985b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 6 Jun 2010 02:43:40 +0200 Subject: xinit: fix dependency, xinit needs xauth --- package/xinit/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'package') diff --git a/package/xinit/Makefile b/package/xinit/Makefile index a5180511a..9574024d9 100644 --- a/package/xinit/Makefile +++ b/package/xinit/Makefile @@ -9,7 +9,7 @@ PKG_RELEASE:= 1 PKG_MD5SUM:= 7ad82221ebd6600a8d33712ec3b62efb PKG_DESCR:= X Window System initializer PKG_SECTION:= x11 -PKG_DEPENDS:= xorg-server mcookie +PKG_DEPENDS:= xorg-server mcookie xauth PKG_BUILDDEP+= xorg-server PKG_URL:= http://xorg.freedesktop.org PKG_SITES:= http://xorg.freedesktop.org/archive/individual/app/ -- cgit v1.2.3 From 6753dd303c33fcd2e7ecf35e5d1c785c4726105b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 20 Jun 2010 14:13:50 +0200 Subject: libXaw: fix PKG_template invocation For the sake of simplicity, we should stick to ${PKG_NAME} here, not the hard-coded lower-case variant of it. This way one has to stick to the original casing of the package name when specifying as dependency, but that's in fact more straight forward than always having to lookup the PKG_template invocation in question. --- package/libXaw/Makefile | 2 +- package/xorg-server/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'package') diff --git a/package/libXaw/Makefile b/package/libXaw/Makefile index 9b6481da8..16930e11d 100644 --- a/package/libXaw/Makefile +++ b/package/libXaw/Makefile @@ -14,7 +14,7 @@ PKG_SITES:= ${MASTER_SITE_XORG} include $(TOPDIR)/mk/package.mk -$(eval $(call PKG_template,LIBXAW,libxaw,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) +$(eval $(call PKG_template,LIBXAW,${PKG_NAME},$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) CONFIGURE_ARGS+= --disable-docs diff --git a/package/xorg-server/Makefile b/package/xorg-server/Makefile index 5ec3e3aff..17ad6e8b9 100644 --- a/package/xorg-server/Makefile +++ b/package/xorg-server/Makefile @@ -10,7 +10,7 @@ PKG_MD5SUM:= ba0360b4ec1f6e541b264e45906bf5f2 PKG_DESCR:= Xorg server PKG_SECTION:= x11 PKG_DEPENDS:= libopenssl libxfont pixman libpciaccess libxkbfile \ - libfontenc xkeyboard-config xkbcomp libxau libxaw \ + libfontenc xkeyboard-config xkbcomp libxau libXaw \ libxmu libxpm libxrender libxt libxxf86dga libxext \ libxdmcp libxv libsm libice libx11 PKG_BUILDDEP+= libX11 randrproto renderproto fixesproto damageproto \ -- cgit v1.2.3 From df58b9c606edf2c33abb87595fd3c7d4b7ee1ee5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 7 Jun 2010 18:22:20 +0200 Subject: port xterm --- package/Config.in | 1 + package/xterm/Makefile | 30 ++++++++++++++++++++++++++++++ package/xterm/patches/patch-Makefile_in | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 package/xterm/Makefile create mode 100644 package/xterm/patches/patch-Makefile_in (limited to 'package') diff --git a/package/Config.in b/package/Config.in index 2f7aecaa4..000403d56 100644 --- a/package/Config.in +++ b/package/Config.in @@ -633,6 +633,7 @@ source "package/twm/Config.in" source "package/xauth/Config.in" source "package/xinit/Config.in" source "package/xlsfonts/Config.in" +source "package/xterm/Config.in" endmenu menu "X fonts" diff --git a/package/xterm/Makefile b/package/xterm/Makefile new file mode 100644 index 000000000..720516586 --- /dev/null +++ b/package/xterm/Makefile @@ -0,0 +1,30 @@ +# This file is part of the OpenADK project. OpenADK is copyrighted +# material, please see the LICENCE file in the top-level directory. + +include $(TOPDIR)/rules.mk + +PKG_NAME:= xterm +PKG_VERSION:= 259 +PKG_RELEASE:= 1 +PKG_MD5SUM:= 22037e1b794d749072310cb142800f05 +PKG_DESCR:= Terminal Emulator for X Windows +PKG_SECTION:= x11 +PKG_DEPENDS:= xorg-server libXaw +PKG_URL:= http://invisible-island.net/xterm/xterm.html +PKG_SITES:= ftp://invisible-island.net/xterm/ + +DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tgz + +include $(TOPDIR)/mk/package.mk + +$(eval $(call PKG_template,XTERM,$(PKG_NAME),$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) + +post-install: + $(INSTALL_DIR) $(IDIR_XTERM)/usr/bin + $(INSTALL_BIN) $(WRKINST)/usr/bin/{koi8rxterm,resize,uxterm,xterm} \ + $(IDIR_XTERM)/usr/bin/ + $(INSTALL_DIR) $(IDIR_XTERM)/usr/lib/X11/app-defaults + $(INSTALL_DATA) ${WRKINST}/usr/lib/X11/app-defaults/{KOI8RXTerm,KOI8RXTerm-color,UXTerm,UXTerm-color,XTerm,XTerm-color} \ + ${IDIR_XTERM}/usr/lib/X11/app-defaults/ + +include ${TOPDIR}/mk/pkg-bottom.mk diff --git a/package/xterm/patches/patch-Makefile_in b/package/xterm/patches/patch-Makefile_in new file mode 100644 index 000000000..1282767e2 --- /dev/null +++ b/package/xterm/patches/patch-Makefile_in @@ -0,0 +1,22 @@ + Fix shell compatibility problem. Note: this is rather hacky, as it + changes the actual semantics of the code - instead of evaluating the + shell statement when being used as parameter to a command, now the + $(shell) function is being used and therefore the result computed at + variable assignment stage. +--- xterm-259.orig/Makefile.in 2010-04-05 00:41:32.000000000 +0200 ++++ xterm-259/Makefile.in 2010-06-06 22:35:13.384934404 +0200 +@@ -175,10 +175,10 @@ resize$x : $(OBJS2) + + charproc$o : main.h @CHARPROC_DEPS@ + ################################################################################ +-actual_xterm = `echo xterm| sed '$(transform)'` +-actual_resize = `echo resize| sed '$(transform)'` +-actual_uxterm = `echo uxterm| sed '$(transform)'` +-actual_k8term = `echo koi8rxterm| sed '$(transform)'` ++actual_xterm = $(shell echo xterm| sed '$(transform)') ++actual_resize = $(shell echo resize| sed '$(transform)') ++actual_uxterm = $(shell echo uxterm| sed '$(transform)') ++actual_k8term = $(shell echo koi8rxterm| sed '$(transform)') + + binary_xterm = $(actual_xterm)$x + binary_resize = $(actual_resize)$x -- cgit v1.2.3 From 2d9d093cdedc57643f3ef2c1a6a5b20d96f7e080 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Jun 2010 22:26:25 +0200 Subject: libXaw: fix wildcard ('?' must be non-empty) --- package/libXaw/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'package') diff --git a/package/libXaw/Makefile b/package/libXaw/Makefile index 16930e11d..8bf3fbb35 100644 --- a/package/libXaw/Makefile +++ b/package/libXaw/Makefile @@ -20,6 +20,6 @@ CONFIGURE_ARGS+= --disable-docs post-install: ${INSTALL_DIR} ${IDIR_LIBXAW}/usr/lib - ${CP} ${WRKINST}/usr/lib/libXaw?.so* ${IDIR_LIBXAW}/usr/lib/ + ${CP} ${WRKINST}/usr/lib/libXaw*.so* ${IDIR_LIBXAW}/usr/lib/ include ${TOPDIR}/mk/pkg-bottom.mk -- cgit v1.2.3 From 0549414af010737828696592acec9b263cd0513a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 12 Jun 2010 19:15:14 +0200 Subject: MesaLib: enable for lemote No render support for siliconmotion, so use swraster driver. Also the obligatory SAREA fix is needed here. --- package/MesaLib/Makefile | 19 +++++++++++++++++-- .../MesaLib/patches/patch-include_GL_internal_sarea_h | 12 ++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 package/MesaLib/patches/patch-include_GL_internal_sarea_h (limited to 'package') diff --git a/package/MesaLib/Makefile b/package/MesaLib/Makefile index 0a4ff3b9a..a5f624374 100644 --- a/package/MesaLib/Makefile +++ b/package/MesaLib/Makefile @@ -23,11 +23,22 @@ include $(TOPDIR)/mk/package.mk $(eval $(call PKG_template,MESALIB,mesalib,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) +ifeq (${ADK_LINUX_X86_IBMX40},y) +DRI_DRIVERS:=i810 +endif + +# Lemote's SMI712 is not directly supported by Mesa, +# and at least some SIS driver fails to build when +# keeping the driver auto-selection intact. +ifeq (${ADK_LINUX_MIPS64_LEMOTE},y) +DRI_DRIVERS:=swrast +endif + CONFIGURE_ARGS+= --disable-static \ --disable-gallium \ --disable-glw \ --with-driver=dri \ - --with-dri-drivers=i810 \ + --with-dri-drivers=${DRI_DRIVERS} \ --without-demos XAKE_FLAGS+= APP_CC=${HOSTCC} HOST_CC=${HOSTCC} @@ -48,8 +59,12 @@ pre-configure: ${MAKE} -C ${WRKBUILD}/src/glsl clean post-install: - $(INSTALL_DIR) $(IDIR_MESALIB)/usr/lib + $(INSTALL_DIR) $(IDIR_MESALIB)/usr/lib/dri $(CP) $(WRKINST)/usr/lib/libGL*.so* \ $(IDIR_MESALIB)/usr/lib +ifeq (${ADK_LINUX_MIPS64_LEMOTE},y) + $(INSTALL_BIN) $(WRKINST)/usr/lib/dri/swrast_dri.so \ + ${IDIR_MESALIB}/usr/lib/dri/ +endif include ${TOPDIR}/mk/pkg-bottom.mk diff --git a/package/MesaLib/patches/patch-include_GL_internal_sarea_h b/package/MesaLib/patches/patch-include_GL_internal_sarea_h new file mode 100644 index 000000000..7de643397 --- /dev/null +++ b/package/MesaLib/patches/patch-include_GL_internal_sarea_h @@ -0,0 +1,12 @@ + fix for loongson +--- Mesa-7.8.1.orig/include/GL/internal/sarea.h 2010-02-05 01:10:39.000000000 +0100 ++++ Mesa-7.8.1/include/GL/internal/sarea.h 2010-06-12 19:13:41.417809541 +0200 +@@ -42,6 +42,8 @@ + /* SAREA area needs to be at least a page */ + #if defined(__alpha__) + #define SAREA_MAX 0x2000 ++#elif defined(__mips__) ++#define SAREA_MAX 0x4000 + #elif defined(__ia64__) + #define SAREA_MAX 0x10000 /* 64kB */ + #else -- cgit v1.2.3 From 48ad3e135426d7f0116e4ad8efc85d20aad64910 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 15 Jun 2010 22:28:54 +0200 Subject: MesaLib: add glxinfo and glxgears subpackages As these xdemos reside in their own package but without the necessary infrastructure (this config thingy), I've created a patch from the addon-package. --- package/MesaLib/Makefile | 17 +- package/MesaLib/patches/000-mesalib-xdemos.patch | 14774 +++++++++++++++++++++ 2 files changed, 14789 insertions(+), 2 deletions(-) create mode 100644 package/MesaLib/patches/000-mesalib-xdemos.patch (limited to 'package') diff --git a/package/MesaLib/Makefile b/package/MesaLib/Makefile index a5f624374..5836f994f 100644 --- a/package/MesaLib/Makefile +++ b/package/MesaLib/Makefile @@ -15,6 +15,11 @@ PKG_BUILDDEP+= dri2proto glproto expat PKG_URL:= http://www.mesa3d.org/ PKG_SITES:= ftp://ftp.freedesktop.org/pub/mesa/7.8.1/ +PKG_DESCR_GLXINFO:= Display various GLX information +PKG_SECT_GLXINFO:= x11 +PKG_DESCR_GLXGEARS:= Nice little OpenGL demo application +PKG_SECT_GLXGEARS:= x11 + WRKDIST= ${WRKDIR}/Mesa-${PKG_VERSION} PKG_TARGET_DEPENDS:= ibmx40 lemote @@ -22,6 +27,8 @@ PKG_TARGET_DEPENDS:= ibmx40 lemote include $(TOPDIR)/mk/package.mk $(eval $(call PKG_template,MESALIB,mesalib,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) +$(eval $(call PKG_template,GLXINFO,glxinfo,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR_GLXINFO},${PKG_SECT_GLXINFO})) +$(eval $(call PKG_template,GLXGEARS,glxgears,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR_GLXGEARS},${PKG_SECT_GLXGEARS})) ifeq (${ADK_LINUX_X86_IBMX40},y) DRI_DRIVERS:=i810 @@ -39,7 +46,7 @@ CONFIGURE_ARGS+= --disable-static \ --disable-glw \ --with-driver=dri \ --with-dri-drivers=${DRI_DRIVERS} \ - --without-demos + --with-demos=xdemos XAKE_FLAGS+= APP_CC=${HOSTCC} HOST_CC=${HOSTCC} @@ -50,7 +57,7 @@ pre-configure: --disable-glw \ --disable-gallium \ --with-driver=xlib \ - --without-demos \ + --with-demos=xdemos \ ); ${MAKE} -C ${WRKBUILD}/src/glsl ${MAKE} -C ${WRKBUILD}/src/glsl/apps @@ -66,5 +73,11 @@ ifeq (${ADK_LINUX_MIPS64_LEMOTE},y) $(INSTALL_BIN) $(WRKINST)/usr/lib/dri/swrast_dri.so \ ${IDIR_MESALIB}/usr/lib/dri/ endif + ${INSTALL_DIR} ${IDIR_GLXINFO}/usr/bin + ${INSTALL_BIN} ${WRKBUILD}/progs/xdemos/glxinfo \ + ${IDIR_GLXINFO}/usr/bin/ + ${INSTALL_DIR} ${IDIR_GLXGEARS}/usr/bin + ${INSTALL_BIN} ${WRKBUILD}/progs/xdemos/glxgears \ + ${IDIR_GLXGEARS}/usr/bin/ include ${TOPDIR}/mk/pkg-bottom.mk diff --git a/package/MesaLib/patches/000-mesalib-xdemos.patch b/package/MesaLib/patches/000-mesalib-xdemos.patch new file mode 100644 index 000000000..866e68c2e --- /dev/null +++ b/package/MesaLib/patches/000-mesalib-xdemos.patch @@ -0,0 +1,14774 @@ +diff -Naurp Mesa-7.8.1/progs/xdemos/corender.c Mesa-7.8.1.patched/progs/xdemos/corender.c +--- Mesa-7.8.1/progs/xdemos/corender.c 1970-01-01 01:00:00.000000000 +0100 ++++ Mesa-7.8.1.patched/progs/xdemos/corender.c 2010-06-13 13:45:06.789793146 +0200 +@@ -0,0 +1,400 @@ ++/** ++ * Example of cooperative rendering into one window by two processes. ++ * The first instance of the program creates the GLX window. ++ * The second instance of the program gets the window ID from the first ++ * and draws into it. ++ * Socket IPC is used for synchronization. ++ * ++ * Usage: ++ * 1. run 'corender &' ++ * 2. run 'corender 2' (any arg will do) ++ * ++ * Brian Paul ++ * 11 Oct 2007 ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ipc.h" ++ ++ ++#ifndef M_PI ++#define M_PI 3.14159265358979323846 ++#endif ++ ++static int MyID = 0; /* 0 or 1 */ ++static int WindowID = 0; ++static GLXContext Context = 0; ++static int Width = 700, Height = 350; ++static int Rot = 0; ++static int Sock = 0; ++ ++static GLfloat Red[4] = {1.0, 0.2, 0.2, 1.0}; ++static GLfloat Blue[4] = {0.2, 0.2, 1.0, 1.0}; ++ ++static int Sync = 1; /** synchronized rendering? */ ++ ++ ++static void ++setup_ipc(void) ++{ ++ int k, port = 10001; ++ ++ if (MyID == 0) { ++ /* I'm the first one, wait for connection from second */ ++ k = CreatePort(&port); ++ assert(k != -1); ++ ++ printf("Waiting for connection from another 'corender'\n"); ++ Sock = AcceptConnection(k); ++ assert(Sock != -1); ++ ++ printf("Got connection, sending windowID\n"); ++ ++ /* send windowID */ ++ SendData(Sock, &WindowID, sizeof(WindowID)); ++ } ++ else { ++ /* I'm the second one, connect to first */ ++ char hostname[1000]; ++ ++ MyHostName(hostname, 1000); ++ Sock = Connect(hostname, port); ++ assert(Sock != -1); ++ ++ /* get windowID */ ++ ReceiveData(Sock, &WindowID, sizeof(WindowID)); ++ printf("Contacted first 'corender', getting WindowID\n"); ++ } ++} ++ ++ ++ ++/** from GLUT */ ++static void ++doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings) ++{ ++ int i, j; ++ GLfloat theta, phi, theta1; ++ GLfloat cosTheta, sinTheta; ++ GLfloat cosTheta1, sinTheta1; ++ GLfloat ringDelta, sideDelta; ++ ++ ringDelta = 2.0 * M_PI / rings; ++ sideDelta = 2.0 * M_PI / nsides; ++ ++ theta = 0.0; ++ cosTheta = 1.0; ++ sinTheta = 0.0; ++ for (i = rings - 1; i >= 0; i--) { ++ theta1 = theta + ringDelta; ++ cosTheta1 = cos(theta1); ++ sinTheta1 = sin(theta1); ++ glBegin(GL_QUAD_STRIP); ++ phi = 0.0; ++ for (j = nsides; j >= 0; j--) { ++ GLfloat cosPhi, sinPhi, dist; ++ ++ phi += sideDelta; ++ cosPhi = cos(phi); ++ sinPhi = sin(phi); ++ dist = R + r * cosPhi; ++ ++ glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); ++ glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi); ++ glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); ++ glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi); ++ } ++ glEnd(); ++ theta = theta1; ++ cosTheta = cosTheta1; ++ sinTheta = sinTheta1; ++ } ++} ++ ++ ++static void ++redraw(Display *dpy) ++{ ++ int dbg = 0; ++ ++ glXMakeCurrent(dpy, WindowID, Context); ++ glEnable(GL_LIGHTING); ++ glEnable(GL_LIGHT0); ++ glEnable(GL_DEPTH_TEST); ++ glClearColor(0.5, 0.5, 0.5, 0.0); ++ ++ if (MyID == 0) { ++ /* First process */ ++ ++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ++ ++ glPushMatrix(); ++ glTranslatef(-1, 0, 0); ++ glRotatef(Rot, 1, 0, 0); ++ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red); ++ doughnut(0.5, 2.0, 20, 30); ++ glPopMatrix(); ++ ++ glFinish(); ++ if (!Sync) { ++ usleep(1000*10); ++ } ++ ++ /* signal second process to render */ ++ if (Sync) { ++ int code = 1; ++ if (dbg) printf("0: send signal\n"); ++ SendData(Sock, &code, sizeof(code)); ++ SendData(Sock, &Rot, sizeof(Rot)); ++ } ++ ++ /* wait for second process to finish rendering */ ++ if (Sync) { ++ int code = 0; ++ if (dbg) printf("0: wait signal\n"); ++ ReceiveData(Sock, &code, sizeof(code)); ++ if (dbg) printf("0: got signal\n"); ++ assert(code == 2); ++ } ++ ++ } ++ else { ++ /* Second process */ ++ ++ /* wait for first process's signal for me to render */ ++ if (Sync) { ++ int code = 0; ++ if (dbg) printf("1: wait signal\n"); ++ ReceiveData(Sock, &code, sizeof(code)); ++ ReceiveData(Sock, &Rot, sizeof(Rot)); ++ ++ if (dbg) printf("1: got signal\n"); ++ assert(code == 1); ++ } ++ ++ /* XXX this clear should not be here, but for some reason, it ++ * makes things _mostly_ work correctly w/ NVIDIA's driver. ++ * There's only occasional glitches. ++ * Without this glClear(), depth buffer for the second process ++ * is pretty much broken. ++ */ ++ /* glClear(GL_DEPTH_BUFFER_BIT); */ ++ ++ glPushMatrix(); ++ glTranslatef(1, 0, 0); ++ glRotatef(Rot + 90 , 1, 0, 0); ++ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue); ++ doughnut(0.5, 2.0, 20, 30); ++ glPopMatrix(); ++ glFinish(); ++ ++ glXSwapBuffers(dpy, WindowID); ++ usleep(1000*10); ++ ++ /* signal first process that I'm done rendering */ ++ if (Sync) { ++ int code = 2; ++ if (dbg) printf("1: send signal\n"); ++ SendData(Sock, &code, sizeof(code)); ++ } ++ } ++} ++ ++ ++static void ++resize(Display *dpy, int width, int height) ++{ ++ float ar = (float) width / height; ++ ++ glXMakeCurrent(dpy, WindowID, Context); ++ ++ glViewport(0, 0, width, height); ++ glMatrixMode(GL_PROJECTION); ++ glLoadIdentity(); ++ glFrustum(-ar, ar, 1.0, -1.0, 5.0, 200.0); ++ glMatrixMode(GL_MODELVIEW); ++ glLoadIdentity(); ++ glTranslatef(0, 0, -15); ++ ++ Width = width; ++ Height = height; ++} ++ ++ ++ ++static void ++set_window_title(Display *dpy, Window win, const char *title) ++{ ++ XSizeHints sizehints; ++ sizehints.flags = 0; ++ XSetStandardProperties(dpy, win, title, title, ++ None, (char **)NULL, 0, &sizehints); ++} ++ ++ ++static Window ++make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height) ++{ ++ int scrnum; ++ XSetWindowAttributes attr; ++ unsigned long mask; ++ Window root; ++ Window win; ++ int x = 0, y = 0; ++ char *name = NULL; ++ ++ 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, 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); ++ } ++ ++ return win; ++} ++ ++ ++static void ++set_event_mask(Display *dpy, Window win) ++{ ++ XSetWindowAttributes attr; ++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; ++ XChangeWindowAttributes(dpy, win, CWEventMask, &attr); ++} ++ ++ ++static void ++event_loop(Display *dpy) ++{ ++ while (1) { ++ while (XPending(dpy) > 0) { ++ XEvent event; ++ XNextEvent(dpy, &event); ++ ++ switch (event.type) { ++ case Expose: ++ redraw(dpy); ++ break; ++ case ConfigureNotify: ++ resize(dpy, event.xconfigure.width, event.xconfigure.height); ++ break; ++ case KeyPress: ++ { ++ char buffer[10]; ++ int r, code; ++ code = XLookupKeysym(&event.xkey, 0); ++ if (code == XK_Left) { ++ } ++ else { ++ r = XLookupString(&event.xkey, buffer, sizeof(buffer), ++ NULL, NULL); ++ if (buffer[0] == 27) { ++ exit(0); ++ } ++ } ++ } ++ default: ++ /* nothing */ ++ ; ++ } ++ } ++ ++ if (MyID == 0 || !Sync) ++ Rot += 1; ++ redraw(dpy); ++ } ++} ++ ++ ++static XVisualInfo * ++choose_visual(Display *dpy) ++{ ++ 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 = DefaultScreen( dpy ); ++ return glXChooseVisual(dpy, scrnum, attribs); ++} ++ ++ ++static void ++parse_opts(int argc, char *argv[]) ++{ ++ if (argc > 1) { ++ MyID = 1; ++ } ++} ++ ++ ++int ++main( int argc, char *argv[] ) ++{ ++ Display *dpy; ++ XVisualInfo *visinfo; ++ ++ parse_opts(argc, argv); ++ ++ dpy = XOpenDisplay(NULL); ++ ++ visinfo = choose_visual(dpy); ++ ++ Context = glXCreateContext( dpy, visinfo, NULL, True ); ++ if (!Context) { ++ printf("Error: glXCreateContext failed\n"); ++ exit(1); ++ } ++ ++ if (MyID == 0) { ++ WindowID = make_gl_window(dpy, visinfo, Width, Height); ++ set_window_title(dpy, WindowID, "corender"); ++ XMapWindow(dpy, WindowID); ++ /*printf("WindowID 0x%x\n", (int) WindowID);*/ ++ } ++ ++ /* do ipc hand-shake here */ ++ setup_ipc(); ++ assert(Sock); ++ assert(WindowID); ++ ++ if (MyID == 1) { ++ set_event_mask(dpy, WindowID); ++ } ++ ++ resize(dpy, Width, Height); ++ ++ event_loop(dpy); ++ ++ return 0; ++} +diff -Naurp Mesa-7.8.1/progs/xdemos/glsync.c Mesa-7.8.1.patched/progs/xdemos/glsync.c +--- Mesa-7.8.1/progs/xdemos/glsync.c 1970-01-01 01:00:00.000000000 +0100 ++++ Mesa-7.8.1.patched/progs/xdemos/glsync.c 2010-06-13 13:45:06.789793146 +0200 +@@ -0,0 +1,295 @@ ++/* ++ * Copyright © 2007 Intel Corporation ++ * ++ * 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 (including the next ++ * paragraph) 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 ++ * THE AUTHORS OR COPYRIGHT HOLDERS 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. ++ * ++ * Authors: ++ * Jesse Barnes ++ * ++ */ ++ ++/** @file glsync.c ++ * The program is simple: it paints a window alternating colors (red & ++ * white) either as fast as possible or synchronized to vblank events ++ * ++ * If run normally, the program should display a window that exhibits ++ * significant tearing between red and white colors (e.g. you might get ++ * a "waterfall" effect of red and white horizontal bars). ++ * ++ * If run with the '-s b' option, the program should synchronize the ++ * window color changes with the vertical blank period, resulting in a ++ * window that looks orangish with a high frequency flicker (which may ++ * be invisible). If the window is moved to another screen, this ++ * property should be preserved. If the window spans two screens, it ++ * shouldn't tear on whichever screen most of the window is on; the ++ * portion on the other screen may show some tearing (like the ++ * waterfall effect above). ++ * ++ * Other options include '-w ' and '-h ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void (*video_sync_get)(); ++void (*video_sync)(); ++void (*swap_interval)(); ++ ++static int GLXExtensionSupported(Display *dpy, const char *extension) ++{ ++ const char *extensionsString, *pos; ++ ++ extensionsString = glXQueryExtensionsString(dpy, DefaultScreen(dpy)); ++ ++ pos = strstr(extensionsString, extension); ++ ++ if (pos != NULL && (pos == extensionsString || pos[-1] == ' ') && ++ (pos[strlen(extension)] == ' ' || pos[strlen(extension)] == '\0')) ++ return 1; ++ ++ return 0; ++} ++ ++extern char *optarg; ++extern int optind, opterr, optopt; ++static char optstr[] = "w:h:s:vi:"; ++ ++enum sync_type { ++ none = 0, ++ sgi_video_sync, ++ buffer_swap ++}; ++ ++static void usage(char *name) ++{ ++ printf("usage: %s [-w ] [-h ] [-s] " ++ "[-v]\n", name); ++ printf("\t-s:\n"); ++ printf("\t\tn: none\n"); ++ printf("\t\ts: SGI video sync extension\n"); ++ printf("\t\tb: buffer swap\n"); ++ printf("\t-i\n"); ++ printf("\t-v: verbose (print count)\n"); ++ exit(-1); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ Display *disp; ++ XVisualInfo *pvi; ++ XSetWindowAttributes swa; ++ GLint last_val = -1, count = 0; ++ Window winGL; ++ GLXContext context; ++ int dummy; ++ Atom wmDelete; ++ enum sync_type waitforsync = none; ++ int width = 500, height = 500, verbose = 0, interval = 1; ++ int c, i = 1; ++ int ret; ++ int attribs[] = { GLX_RGBA, ++ GLX_RED_SIZE, 1, ++ GLX_GREEN_SIZE, 1, ++ GLX_BLUE_SIZE, 1, ++ None }; ++ int db_attribs[] = { GLX_RGBA, ++ GLX_RED_SIZE, 1, ++ GLX_GREEN_SIZE, 1, ++ GLX_BLUE_SIZE, 1, ++ GLX_DOUBLEBUFFER, ++ GLX_DEPTH_SIZE, 1, ++ None }; ++ XSizeHints sizehints; ++ ++ opterr = 0; ++ while ((c = getopt(argc, argv, optstr)) != -1) { ++ switch (c) { ++ case 'w': ++ width = atoi(optarg); ++ break; ++ case 'h': ++ height = atoi(optarg); ++ break; ++ case 's': ++ switch (optarg[0]) { ++ case 'n': ++ waitforsync = none; ++ break; ++ case 's': ++ waitforsync = sgi_video_sync; ++ break; ++ case 'b': ++ waitforsync = buffer_swap; ++ break; ++ default: ++ usage(argv[0]); ++ break; ++ } ++ break; ++ case 'v': ++ verbose = 1; ++ break; ++ case 'i': ++ interval = atoi(optarg); ++ break; ++ default: ++ usage(argv[0]); ++ break; ++ } ++ } ++ ++ disp = XOpenDisplay(NULL); ++ if (!disp) { ++ fprintf(stderr, "failed to open display\n"); ++ return -1; ++ } ++ ++ if (!glXQueryExtension(disp, &dummy, &dummy)) { ++ fprintf(stderr, "glXQueryExtension failed\n"); ++ return -1; ++ } ++ ++ if (!GLXExtensionSupported(disp, "GLX_SGI_video_sync")) { ++ fprintf(stderr, "GLX_SGI_video_sync not supported, exiting\n"); ++ return -1; ++ } ++ ++ if (waitforsync != buffer_swap) { ++ pvi = glXChooseVisual(disp, DefaultScreen(disp), attribs); ++ } else { ++ pvi = glXChooseVisual(disp, DefaultScreen(disp), db_attribs); ++ } ++ ++ if (!pvi) { ++ fprintf(stderr, "failed to choose visual, exiting\n"); ++ return -1; ++ } ++ ++ pvi->screen = DefaultScreen(disp); ++ ++ swa.colormap = XCreateColormap(disp, RootWindow(disp, pvi->screen), ++ pvi->visual, AllocNone); ++ swa.border_pixel = 0; ++ swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | ++ StructureNotifyMask; ++ winGL = XCreateWindow(disp, RootWindow(disp, pvi->screen), ++ 0, 0, ++ width, height, ++ 0, pvi->depth, InputOutput, pvi->visual, ++ CWBorderPixel | CWColormap | CWEventMask, &swa); ++ if (!winGL) { ++ fprintf(stderr, "window creation failed\n"); ++ return -1; ++ } ++ wmDelete = XInternAtom(disp, "WM_DELETE_WINDOW", True); ++ XSetWMProtocols(disp, winGL, &wmDelete, 1); ++ ++ sizehints.x = 0; ++ sizehints.y = 0; ++ sizehints.width = width; ++ sizehints.height = height; ++ sizehints.flags = USSize | USPosition; ++ ++ XSetNormalHints(disp, winGL, &sizehints); ++ XSetStandardProperties(disp, winGL, "glsync test", "glsync text", ++ None, NULL, 0, &sizehints); ++ ++ context = glXCreateContext(disp, pvi, NULL, GL_TRUE); ++ if (!context) { ++ fprintf(stderr, "failed to create glx context\n"); ++ return -1; ++ } ++ ++ XMapWindow(disp, winGL); ++ ret = glXMakeCurrent(disp, winGL, context); ++ if (!ret) { ++ fprintf(stderr, "failed to make context current: %d\n", ret); ++ } ++ ++ video_sync_get = glXGetProcAddress((unsigned char *)"glXGetVideoSyncSGI"); ++ video_sync = glXGetProcAddress((unsigned char *)"glXWaitVideoSyncSGI"); ++ ++ swap_interval = glXGetProcAddress((unsigned char *)"glXSwapIntervalSGI"); ++ ++ if (!video_sync_get || !video_sync || !swap_interval) { ++ fprintf(stderr, "failed to get sync functions\n"); ++ return -1; ++ } ++ ++ if (waitforsync == buffer_swap) { ++ swap_interval(interval); ++ fprintf(stderr, "set swap interval to %d\n", interval); ++ } ++ video_sync_get(&count); ++ count++; ++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ++ while (i++) { ++ /* Alternate colors to make tearing obvious */ ++ if (i & 1) { ++ glClearColor(1.0f, 1.0f, 1.0f, 1.0f); ++ glColor3f(1.0f, 1.0f, 1.0f); ++ } else { ++ glClearColor(1.0f, 0.0f, 0.0f, 0.0f); ++ glColor3f(1.0f, 0.0f, 0.0f); ++ } ++ ++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ++ glRectf(0, 0, width, height); ++ ++ /* Wait for vsync */ ++ if (waitforsync == sgi_video_sync) { ++ if (verbose) ++ fprintf(stderr, "waiting on count %d\n", count); ++ video_sync(2, (count + 1) % 2, &count); ++ if (count < last_val) ++ fprintf(stderr, "error: vblank count went backwards: %d -> %d\n", last_val, count); ++ if (count == last_val) ++ fprintf(stderr, "error: count didn't change: %d\n", count); ++ last_val = count; ++ glFlush(); ++ } else if (waitforsync == buffer_swap) { ++ glXSwapBuffers(disp, winGL); ++ } else { ++ video_sync_get(&count); ++ sleep(1); ++ glFinish(); ++ } ++ ++ if (verbose) { ++ video_sync_get(&count); ++ fprintf(stderr, "current count: %d\n", count); ++ } ++ } ++ ++ XDestroyWindow(disp, winGL); ++ glXDestroyContext(disp, context); ++ XCloseDisplay(disp); ++ ++ return 0; ++} +diff -Naurp Mesa-7.8.1/progs/xdemos/glthreads.c Mesa-7.8.1.patched/progs/xdemos/glthreads.c +--- Mesa-7.8.1/progs/xdemos/glthreads.c 1970-01-01 01:00:00.000000000 +0100 ++++ Mesa-7.8.1.patched/progs/xdemos/glthreads.c 2010-06-13 13:45:06.789793146 +0200 +@@ -0,0 +1,716 @@ ++/* ++ * 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 ++ * -l Enable application-side locking ++ * -n Number of threads to create (default is 2) ++ * -display Specify X display (default is $DISPLAY) ++ * -t Use texture mapping ++ * ++ * Brian Paul 20 July 2000 ++ */ ++ ++ ++/* ++ * Notes: ++ * - Each thread gets its own GLX context. ++ * ++ * - The GLX contexts share texture objects. ++ * ++ * - When 't' is pressed to update the texture image, the window/thread which ++ * has input focus is signalled to change the texture. The other threads ++ * should see the updated texture the next time they call glBindTexture. ++ */ ++ ++ ++#if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ++ * Each window/thread/context: ++ */ ++struct winthread { ++ Display *Dpy; ++ int Index; ++ pthread_t Thread; ++ Window Win; ++ GLXContext Context; ++ float Angle; ++ int WinWidth, WinHeight; ++ GLboolean NewSize; ++ GLboolean Initialized; ++ GLboolean MakeNewTexture; ++}; ++ ++ ++#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 GLboolean Texture = GL_FALSE; ++static GLuint TexObj = 12; ++static GLboolean Animate = GL_TRUE; ++ ++static pthread_mutex_t Mutex; ++static pthread_cond_t CondVar; ++static pthread_mutex_t CondMutex; ++ ++ ++static void ++Error(const char *msg) ++{ ++ fprintf(stderr, "Error: %s\n", msg); ++ exit(1); ++} ++ ++ ++static void ++signal_redraw(void) ++{ ++ pthread_mutex_lock(&CondMutex); ++ pthread_cond_broadcast(&CondVar); ++ pthread_mutex_unlock(&CondMutex); ++} ++ ++ ++static void ++MakeNewTexture(struct winthread *wt) ++{ ++#define TEX_SIZE 128 ++ static float step = 0.0; ++ GLfloat image[TEX_SIZE][TEX_SIZE][4]; ++ GLint width; ++ int i, j; ++ ++ for (j = 0; j < TEX_SIZE; j++) { ++ for (i = 0; i < TEX_SIZE; i++) { ++ float dt = 5.0 * (j - 0.5 * TEX_SIZE) / TEX_SIZE; ++ float ds = 5.0 * (i - 0.5 * TEX_SIZE) / TEX_SIZE; ++ float r = dt * dt + ds * ds + step; ++ image[j][i][0] = ++ image[j][i][1] = ++ image[j][i][2] = 0.75 + 0.25 * cos(r); ++ image[j][i][3] = 1.0; ++ } ++ } ++ ++ step += 0.5; ++ ++ glBindTexture(GL_TEXTURE_2D, TexObj); ++ ++ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); ++ if (width) { ++ assert(width == TEX_SIZE); ++ /* sub-tex replace */ ++ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE, ++ GL_RGBA, GL_FLOAT, image); ++ } ++ else { ++ /* create new */ ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ++ ++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, ++ GL_RGBA, GL_FLOAT, image); ++ } ++} ++ ++ ++ ++/* draw a colored cube */ ++static void ++draw_object(void) ++{ ++ glPushMatrix(); ++ glScalef(0.75, 0.75, 0.75); ++ ++ glColor3f(1, 0, 0); ++ ++ if (Texture) { ++ glBindTexture(GL_TEXTURE_2D, TexObj); ++ glEnable(GL_TEXTURE_2D); ++ } ++ else { ++ glDisable(GL_TEXTURE_2D); ++ } ++ ++ glBegin(GL_QUADS); ++ ++ /* -X */ ++ glColor3f(0, 1, 1); ++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); ++ glTexCoord2f(1, 0); glVertex3f(-1, 1, -1); ++ glTexCoord2f(1, 1); glVertex3f(-1, 1, 1); ++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); ++ ++ /* +X */ ++ glColor3f(1, 0, 0); ++ glTexCoord2f(0, 0); glVertex3f(1, -1, -1); ++ glTexCoord2f(1, 0); glVertex3f(1, 1, -1); ++ glTexCoord2f(1, 1); glVertex3f(1, 1, 1); ++ glTexCoord2f(0, 1); glVertex3f(1, -1, 1); ++ ++ /* -Y */ ++ glColor3f(1, 0, 1); ++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); ++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1); ++ glTexCoord2f(1, 1); glVertex3f( 1, -1, 1); ++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); ++ ++ /* +Y */ ++ glColor3f(0, 1, 0); ++ glTexCoord2f(0, 0); glVertex3f(-1, 1, -1); ++ glTexCoord2f(1, 0); glVertex3f( 1, 1, -1); ++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1); ++ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1); ++ ++ /* -Z */ ++ glColor3f(1, 1, 0); ++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); ++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1); ++ glTexCoord2f(1, 1); glVertex3f( 1, 1, -1); ++ glTexCoord2f(0, 1); glVertex3f(-1, 1, -1); ++ ++ /* +Y */ ++ glColor3f(0, 0, 1); ++ glTexCoord2f(0, 0); glVertex3f(-1, -1, 1); ++ glTexCoord2f(1, 0); glVertex3f( 1, -1, 1); ++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1); ++ glTexCoord2f(0, 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; ++ if (!Animate) ++ signal_redraw(); ++} ++ ++ ++/* ++ * We have an instance of this for each thread. ++ */ ++static void ++draw_loop(struct winthread *wt) ++{ ++ while (!ExitFlag) { ++ ++ if (Locking) ++ pthread_mutex_lock(&Mutex); ++ ++ glXMakeCurrent(wt->Dpy, wt->Win, wt->Context); ++ if (!wt->Initialized) { ++ printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index, ++ (char *) glGetString(GL_RENDERER)); ++ if (Texture /*&& wt->Index == 0*/) { ++ MakeNewTexture(wt); ++ } ++ wt->Initialized = GL_TRUE; ++ } ++ ++ 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; ++ } ++ ++ if (wt->MakeNewTexture) { ++ MakeNewTexture(wt); ++ wt->MakeNewTexture = GL_FALSE; ++ } ++ ++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ++ ++ glPushMatrix(); ++ glRotatef(wt->Angle, 0, 1, 0); ++ 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); ++ ++ if (Animate) { ++ usleep(5000); ++ } ++ else { ++ /* wait for signal to draw */ ++ pthread_mutex_lock(&CondMutex); ++ pthread_cond_wait(&CondVar, &CondMutex); ++ pthread_mutex_unlock(&CondMutex); ++ } ++ wt->Angle += 1.0; ++ } ++} ++ ++ ++static void ++keypress(XEvent *event, struct winthread *wt) ++{ ++ char buf[100]; ++ KeySym keySym; ++ XComposeStatus stat; ++ ++ XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat); ++ ++ switch (keySym) { ++ case XK_Escape: ++ /* tell all threads to exit */ ++ if (!Animate) { ++ signal_redraw(); ++ } ++ ExitFlag = GL_TRUE; ++ /*printf("exit draw_loop %d\n", wt->Index);*/ ++ return; ++ case XK_t: ++ case XK_T: ++ if (Texture) { ++ wt->MakeNewTexture = GL_TRUE; ++ if (!Animate) ++ signal_redraw(); ++ } ++ break; ++ case XK_a: ++ case XK_A: ++ Animate = !Animate; ++ if (Animate) /* yes, prev Animate state! */ ++ signal_redraw(); ++ break; ++ case XK_s: ++ case XK_S: ++ if (!Animate) ++ signal_redraw(); ++ break; ++ default: ++ ; /* nop */ ++ } ++} ++ ++ ++/* ++ * 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: ++ for (i = 0; i < NumWinThreads; i++) { ++ struct winthread *wt = &WinThreads[i]; ++ if (event.xkey.window == wt->Win) { ++ keypress(&event, wt); ++ break; ++ } ++ } ++ break; ++ 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: ++ keypress(&event, wt); ++ break; ++ default: ++ ; /* nop */ ++ } ++ } ++ 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, GLXContext shareCtx) ++{ ++ 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 = 160, height = 160; ++ int xpos = (wt->Index % 8) * (width + 10); ++ int ypos = (wt->Index / 8) * (width + 20); ++ ++ 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, shareCtx, 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); ++ } ++} ++ ++ ++static void ++usage(void) ++{ ++ printf("glthreads: test of GL thread safety (any key = exit)\n"); ++ printf("Usage:\n"); ++ printf(" glthreads [options]\n"); ++ printf("Options:\n"); ++ printf(" -display DISPLAYNAME Specify display string\n"); ++ printf(" -n NUMTHREADS Number of threads to create\n"); ++ printf(" -p Use a separate display connection for each thread\n"); ++ printf(" -l Use application-side locking\n"); ++ printf(" -t Enable texturing\n"); ++ printf("Keyboard:\n"); ++ printf(" Esc Exit\n"); ++ printf(" t Change texture image (requires -t option)\n"); ++ printf(" a Toggle animation\n"); ++ printf(" s Step rotation (when not animating)\n"); ++} ++ ++ ++int ++main(int argc, char *argv[]) ++{ ++ char *displayName = NULL; ++ int numThreads = 2; ++ Display *dpy = NULL; ++ int i; ++ Status threadStat; ++ ++ if (argc == 1) { ++ usage(); ++ } ++ 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], "-t") == 0) { ++ Texture = 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 { ++ usage(); ++ exit(1); ++ } ++ } ++ } ++ ++ if (Locking) ++ printf("glthreads: Using explicit 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", XDisplayName(displayName)); ++ return -1; ++ } ++ } ++ ++ pthread_mutex_init(&Mutex, NULL); ++ pthread_mutex_init(&CondMutex, NULL); ++ pthread_cond_init(&CondVar, NULL); ++ ++ printf("glthreads: creating windows\n"); ++ ++ NumWinThreads = numThreads; ++ ++ /* Create the GLX windows and contexts */ ++ for (i = 0; i < numThreads; i++) { ++ GLXContext share; ++ ++ if (MultiDisplays) { ++ WinThreads[i].Dpy = XOpenDisplay(displayName); ++ assert(WinThreads[i].Dpy); ++ } ++ else { ++ WinThreads[i].Dpy = dpy; ++ } ++ WinThreads[i].Index = i; ++ WinThreads[i].Initialized = GL_FALSE; ++ ++ share = (Texture && i > 0) ? WinThreads[0].Context : 0; ++ ++ create_window(&WinThreads[i], share); ++ } ++ ++ 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 %p\n", (void *) 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 ++ ++int ++main(int argc, char *argv[]) ++{ ++ printf("Sorry, this program wasn't compiled with PTHREADS defined.\n"); ++ return 0; ++} ++ ++ ++#endif /* PTHREADS */ +diff -Naurp Mesa-7.8.1/progs/xdemos/glxcontexts.c Mesa-7.8.1.patched/progs/xdemos/glxcontexts.c +--- Mesa-7.8.1/progs/xdemos/glxcontexts.c 1970-01-01 01:00:00.000000000 +0100 ++++ Mesa-7.8.1.patched/progs/xdemos/glxcontexts.c 2010-06-13 13:45:06.789793146 +0200 +@@ -0,0 +1,548 @@ ++/* ++ * 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. ++ */ ++ ++/* ++ * Version of glxgears that creates/destroys the rendering context for each ++ * frame. Also periodically destroy/recreate the window. ++ * Good for finding memory leaks, etc. ++ * ++ * Command line options: ++ * -info print GL implementation information ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define BENCHMARK ++ ++#ifdef BENCHMARK ++ ++/* XXX this probably isn't very portable */ ++ ++#include ++#include ++ ++/* 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 XVisualInfo *visinfo = NULL; ++static int 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 ++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); ++ ++ { ++ 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(); ++ ++ reshape(WinWidth, WinHeight); ++ ++ do_draw(); ++ ++ glDeleteLists(gear1, 1); ++ glDeleteLists(gear2, 1); ++ glDeleteLists(gear3, 1); ++ ++ 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 scrnum; ++