summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java37
-rw-r--r--src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java16
-rw-r--r--src/jogl/classes/jogamp/opengl/GLContextImpl.java7
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java12
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java7
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java21
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java25
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java55
8 files changed, 147 insertions, 33 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java
index b1bc8828b..7b5e6b8f1 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java
@@ -363,8 +363,40 @@ public class GLRendererQuirks {
*/
public static final int NoPBufferWithAccum = 19;
+ /**
+ * Need GL objects (VBO, ..) to be synchronized when utilized
+ * concurrently from multiple threads via a shared GL context,
+ * otherwise driver crashes the VM.
+ * <p>
+ * Usually synchronization should not be required, if the shared GL objects
+ * are created and immutable before concurrent usage.<br>
+ * However, using drivers exposing this issue always require the user to
+ * synchronize access of shared GL objects.
+ * </p>
+ * <p>
+ * Synchronization can be avoided if accessing the shared GL objects
+ * exclusively via a queue or {@link com.jogamp.common.util.Ringbuffer Ringbuffer}, see GLMediaPlayerImpl as an example.
+ * </p>
+ * <p>
+ * Appears on:
+ * <ul>
+ * <li>Platform OSX
+ * <ul>
+ * <li>detected on OSX 10.9.5 first</li>
+ * <li>any driver</li>
+ * <li>enabled for all OSX versions</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </p>
+ * <p>
+ * See Bug 1088 - https://jogamp.org/bugzilla/show_bug.cgi?id=1088
+ * </p>
+ */
+ public static final int NeedSharedObjectSync = 20;
+
/** Return the number of known quirks. */
- public static final int getCount() { return 20; }
+ public static final int getCount() { return 21; }
private static final String[] _names = new String[] { "NoDoubleBufferedPBuffer", "NoDoubleBufferedBitmap", "NoSetSwapInterval",
"NoOffscreenBitmap", "NoSetSwapIntervalPostRetarget", "GLSLBuggyDiscard",
@@ -372,7 +404,8 @@ public class GLRendererQuirks {
"NeedCurrCtx4ARBPixFmtQueries", "NeedCurrCtx4ARBCreateContext",
"NoFullFBOSupport", "GLSLNonCompliant", "GL4NeedsGL3Request",
"GLSharedContextBuggy", "GLES3ViaEGLES2Config", "SingletonEGLDisplayOnly",
- "NoMultiSamplingBuffers", "BuggyColorRenderbuffer", "NoPBufferWithAccum"
+ "NoMultiSamplingBuffers", "BuggyColorRenderbuffer", "NoPBufferWithAccum",
+ "NeedSharedObjectSync"
};
private static final IdentityHashMap<String, GLRendererQuirks> stickyDeviceQuirks = new IdentityHashMap<String, GLRendererQuirks>();
diff --git a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java
index 526967d69..b8aef126b 100644
--- a/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java
+++ b/src/jogl/classes/javax/media/opengl/GLSharedContextSetter.java
@@ -28,6 +28,8 @@
package javax.media.opengl;
+import com.jogamp.opengl.GLRendererQuirks;
+
/**
* Adds capabilities to set a shared {@link GLContext} directly or via an {@link GLAutoDrawable}.
* <p>
@@ -88,6 +90,20 @@ package javax.media.opengl;
glad.setVisible(true); // GLWindow creation ..
* </pre>
* </p>
+ * <h5><a name="synchronization">GL Object Synchronization</a></h5>
+ * <p>
+ * Usually synchronization of shared GL objects should not be required, if the shared GL objects
+ * are created and immutable before concurrent usage.
+ * </p>
+ * <p>
+ * However, using drivers exposing {@link GLRendererQuirks#NeedSharedObjectSync} always
+ * require the user to synchronize access of shared GL objects.
+ * </p>
+ * <p>
+ * Synchronization can be avoided if accessing the shared GL objects
+ * exclusively via a queue or {@link com.jogamp.common.util.Ringbuffer Ringbuffer}, see GLMediaPlayerImpl as an example.
+ * </p>
+ * </p>
* <h5><a name="driverissues">Known Driver Issues</a></h5>
* <h7><a name="intelmesa">Intel's Mesa >= 9.1.2 Backend for [Sandybridge/Ivybridge] on GNU/Linux</a></h7>
* <p>
diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
index bc8d3b7e4..45a4f2426 100644
--- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
@@ -1785,6 +1785,13 @@ public abstract class GLContextImpl extends GLContext {
}
quirks.addQuirk( quirk );
}
+ {
+ final int quirk = GLRendererQuirks.NeedSharedObjectSync;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType());
+ }
+ quirks.addQuirk( quirk );
+ }
if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Mavericks) >= 0 && 3==reqMajor && 4==major ) {
final int quirk = GLRendererQuirks.GL4NeedsGL3Request;
if(DEBUG) {
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java
index a66aaf9d8..8d040222a 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java
@@ -107,12 +107,13 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase {
animator.start();
final GearsES2 g1 = new GearsES2(0);
+ g1.setSyncObjects(g1); // this is master, since rendered we must use it as sync
final GLWindow f1 = createGLWindow(0, 0, g1);
animator.add(f1);
final InsetsImmutable insets = f1.getInsets();
final GearsES2 g2 = new GearsES2(0);
- g2.setSharedGears(g1);
+ g2.setSharedGears(g1); // also uses master g1 as sync, if required
final GLWindow f2 = createGLWindow(f1.getX()+width+insets.getTotalWidth(),
f1.getY()+0, g2);
f2.setSharedAutoDrawable(f1);
@@ -120,7 +121,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase {
f2.setVisible(true);
final GearsES2 g3 = new GearsES2(0);
- g3.setSharedGears(g1);
+ g3.setSharedGears(g1); // also uses master g1 as sync, if required
final GLWindow f3 = createGLWindow(f1.getX()+0,
f1.getY()+height+insets.getTotalHeight(), g3);
f3.setSharedAutoDrawable(f1);
@@ -222,6 +223,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase {
public void asyncEachAnimator(final boolean destroyCleanOrder) throws InterruptedException {
final Animator a1 = new Animator();
final GearsES2 g1 = new GearsES2(0);
+ g1.setSyncObjects(g1); // this is master, since rendered we must use it as sync
final GLWindow f1 = createGLWindow(0, 0, g1);
a1.add(f1);
a1.start();
@@ -230,7 +232,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase {
final Animator a2 = new Animator();
final GearsES2 g2 = new GearsES2(0);
- g2.setSharedGears(g1);
+ g2.setSharedGears(g1); // also uses master g1 as sync, if required
final GLWindow f2 = createGLWindow(f1.getX()+width+insets.getTotalWidth(),
f1.getY()+0, g2);
f2.setSharedAutoDrawable(f1);
@@ -240,7 +242,7 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase {
final Animator a3 = new Animator();
final GearsES2 g3 = new GearsES2(0);
- g3.setSharedGears(g1);
+ g3.setSharedGears(g1); // also uses master g1 as sync, if required
final GLWindow f3 = createGLWindow(f1.getX()+0,
f1.getY()+height+insets.getTotalHeight(), g3);
f3.setSharedAutoDrawable(f1);
@@ -336,8 +338,10 @@ public class TestSharedContextVBOES2NEWT2 extends UITestCase {
}
static long duration = 1000; // ms
+ static boolean mainRun = false;
public static void main(final String args[]) {
+ mainRun = true;
for(int i=0; i<args.length; i++) {
if(args[i].equals("-time")) {
i++;
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java
index 852b7193e..a0d111c4d 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT3.java
@@ -248,6 +248,7 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase {
public void asyncEachAnimator(final boolean destroyCleanOrder, final boolean useMappedBuffers) throws InterruptedException {
final Animator a1 = new Animator();
final GearsES2 g1 = new GearsES2(0);
+ g1.setSyncObjects(g1); // this is master, since rendered we must use it as sync
g1.setUseMappedBuffers(useMappedBuffers);
g1.setValidateBuffers(true);
final GLWindow f1 = createGLWindow(0, 0, g1);
@@ -258,7 +259,7 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase {
final Animator a2 = new Animator();
final GearsES2 g2 = new GearsES2(0);
- g2.setSharedGears(g1);
+ g2.setSharedGears(g1); // also uses master g1 as sync, if required
final GLWindow f2 = createGLWindow(f1.getX()+width+insets.getTotalWidth(),
f1.getY()+0, g2);
f2.setSharedAutoDrawable(f1);
@@ -288,7 +289,7 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase {
final Animator a3 = new Animator();
final GearsES2 g3 = new GearsES2(0);
- g3.setSharedGears(g1);
+ g3.setSharedGears(g1); // also uses master g1 as sync, if required
final GLWindow f3 = createGLWindow(f1.getX()+0,
f1.getY()+height+insets.getTotalHeight(), g3);
f3.setSharedAutoDrawable(f1);
@@ -374,8 +375,10 @@ public class TestSharedContextVBOES2NEWT3 extends UITestCase {
static long duration = 1000; // ms
static long durationPostDestroy = 1000; // ms - ~60 frames post destroy
+ static boolean mainRun = false;
public static void main(final String args[]) {
+ mainRun = true;
for(int i=0; i<args.length; i++) {
if(args[i].equals("-time")) {
i++;
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java
index 78242944f..9d20495a0 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java
@@ -41,6 +41,7 @@ import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
+import com.jogamp.opengl.GLRendererQuirks;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.test.junit.jogl.demos.GearsObject;
import com.jogamp.opengl.util.glsl.fixedfunc.FixedFuncUtil;
@@ -65,6 +66,7 @@ public class GearsES1 implements GLEventListener {
private GearsObject gear1=null, gear2=null, gear3=null;
private FloatBuffer gear1Color=GearsObject.red, gear2Color=GearsObject.green, gear3Color=GearsObject.blue;
private GearsES1 sharedGears;
+ private Object syncObjects;
private volatile boolean usesSharedGears = false;
private boolean useMappedBuffers = false;
private boolean validateBuffers = false;
@@ -180,6 +182,13 @@ public class GearsES1 implements GLEventListener {
System.err.println("gear1 reuse: "+gear1);
System.err.println("gear2 reuse: "+gear2);
System.err.println("gear3 reuse: "+gear3);
+ if( gl.getContext().hasRendererQuirk(GLRendererQuirks.NeedSharedObjectSync) ) {
+ syncObjects = sharedGears;
+ System.err.println("Shared GearsES1: Synchronized Objects due to quirk "+GLRendererQuirks.toString(GLRendererQuirks.NeedSharedObjectSync));
+ } else {
+ syncObjects = new Object();
+ System.err.println("Shared GearsES1: Unsynchronized Objects");
+ }
} else {
gear1 = new GearsObjectES1(gl, useMappedBuffers, gear1Color, 1.0f, 4.0f, 1.0f, 20, 0.7f, validateBuffers);
System.err.println("gear1 created: "+gear1);
@@ -189,6 +198,8 @@ public class GearsES1 implements GLEventListener {
gear3 = new GearsObjectES1(gl, useMappedBuffers, gear3Color, 1.3f, 2.0f, 0.5f, 10, 0.7f, validateBuffers);
System.err.println("gear3 created: "+gear3);
+
+ syncObjects = new Object();
}
gl.glEnable(GLLightingFunc.GL_NORMALIZE);
@@ -249,6 +260,8 @@ public class GearsES1 implements GLEventListener {
gear2 = null;
gear3.destroy(gl);
gear3 = null;
+ sharedGears = null;
+ syncObjects = null;
System.err.println(Thread.currentThread()+" GearsES1.dispose FIN");
}
@@ -294,9 +307,11 @@ public class GearsES1 implements GLEventListener {
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
- gear1.draw(gl, -3.0f, -2.0f, angle);
- gear2.draw(gl, 3.1f, -2.0f, -2.0f * angle - 9.0f);
- gear3.draw(gl, -3.1f, 4.2f, -2.0f * angle - 25.0f);
+ synchronized ( syncObjects ) {
+ gear1.draw(gl, -3.0f, -2.0f, angle);
+ gear2.draw(gl, 3.1f, -2.0f, -2.0f * angle - 9.0f);
+ gear3.draw(gl, -3.1f, 4.2f, -2.0f * angle - 25.0f);
+ }
// Remember that every push needs a pop; this one is paired with
// rotating the entire gear assembly
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
index 0f63566a2..a548d4ccf 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
@@ -30,6 +30,7 @@ import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.event.PinchToZoomGesture;
import com.jogamp.newt.event.GestureHandler.GestureEvent;
+import com.jogamp.opengl.GLRendererQuirks;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.Quaternion;
@@ -75,6 +76,7 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
private float panX = 0.0f, panY = 0.0f, panZ=0.0f;
private volatile GearsObjectES2 gear1=null, gear2=null, gear3=null;
private GearsES2 sharedGears = null;
+ private Object syncObjects = null;
private boolean useMappedBuffers = false;
private boolean validateBuffers = false;
private volatile boolean usesSharedGears = false;
@@ -146,6 +148,10 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
sharedGears = shared;
}
+ public void setSyncObjects(final Object sync) {
+ syncObjects = sync;
+ }
+
/**
* @return gear1
*/
@@ -247,6 +253,13 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
System.err.println("gear2 "+sid()+" created w/ share: "+sharedGears.getGear2()+" -> "+gear2);
System.err.println("gear3 "+sid()+" created w/ share: "+sharedGears.getGear3()+" -> "+gear3);
}
+ if( gl.getContext().hasRendererQuirk(GLRendererQuirks.NeedSharedObjectSync) ) {
+ syncObjects = sharedGears;
+ System.err.println("Shared GearsES2: Synchronized Objects due to quirk "+GLRendererQuirks.toString(GLRendererQuirks.NeedSharedObjectSync));
+ } else if( null == syncObjects ) {
+ syncObjects = new Object();
+ System.err.println("Shared GearsES2: Unsynchronized Objects");
+ }
} else {
gear1 = new GearsObjectES2(gl, useMappedBuffers, st, gear1Color, 1.0f, 4.0f, 1.0f, 20, 0.7f, pmvMatrix, pmvMatrixUniform, colorU, validateBuffers);
if(verbose) {
@@ -262,6 +275,8 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
if(verbose) {
System.err.println("gear3 "+sid()+" created: "+gear2);
}
+ if( null == syncObjects ) {
+ syncObjects = new Object();
}
}
@@ -461,6 +476,8 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
colorU = null;
st.destroy(gl);
st = null;
+ sharedGears = null;
+ syncObjects = null;
if(verbose) {
System.err.println(Thread.currentThread()+" GearsES2.dispose "+sid()+" FIN");
@@ -534,9 +551,11 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
pmvMatrix.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
pmvMatrix.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
- gear1.draw(gl, -3.0f, -2.0f, 1f * angle - 0f);
- gear2.draw(gl, 3.1f, -2.0f, -2f * angle - 9.0f);
- gear3.draw(gl, -3.1f, 4.2f, -2f * angle - 25.0f);
+ synchronized ( syncObjects ) {
+ gear1.draw(gl, -3.0f, -2.0f, 1f * angle - 0f);
+ gear2.draw(gl, 3.1f, -2.0f, -2f * angle - 9.0f);
+ gear3.draw(gl, -3.1f, 4.2f, -2f * angle - 25.0f);
+ }
pmvMatrix.glPopMatrix();
st.useProgram(gl, false);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java
index 6683f0fbf..28328fcd2 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java
@@ -20,6 +20,7 @@ import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.event.awt.AWTKeyAdapter;
import com.jogamp.newt.event.awt.AWTMouseAdapter;
+import com.jogamp.opengl.GLRendererQuirks;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.util.TileRendererBase;
@@ -33,6 +34,8 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList
private float view_rotx = 20.0f, view_roty = 30.0f;
private final float view_rotz = 0.0f;
private int gear1=0, gear2=0, gear3=0;
+ private Gears sharedGears = null;
+ private Object syncObjects = null;
private float angle = 0.0f;
private boolean doRotate = true;
private final int swapInterval;
@@ -42,6 +45,7 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList
private boolean doRotateBeforePrinting;
private boolean verbose = true;
private boolean flipVerticalInGLOrientation = false;
+ private volatile boolean isInit = false;
// private boolean mouseRButtonDown = false;
private int prevMouseX, prevMouseY;
@@ -182,6 +186,13 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList
System.err.println("gear1 list reused: "+gear1);
System.err.println("gear2 list reused: "+gear2);
System.err.println("gear3 list reused: "+gear3);
+ if( gl.getContext().hasRendererQuirk(GLRendererQuirks.NeedSharedObjectSync) ) {
+ syncObjects = sharedGears;
+ System.err.println("Shared Gears: Synchronized Objects due to quirk "+GLRendererQuirks.toString(GLRendererQuirks.NeedSharedObjectSync));
+ } else {
+ syncObjects = new Object();
+ System.err.println("Shared Gears: Unsynchronized Objects");
+ }
} else {
gear1 = gl.glGenLists(1);
gl.glNewList(gear1, GL2.GL_COMPILE);
@@ -203,6 +214,8 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList
gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f);
gl.glEndList();
System.err.println("gear3 list created: "+gear3);
+
+ syncObjects = new Object();
}
enableStates(gl, false);
@@ -295,6 +308,8 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList
gear1 = 0;
gear2 = 0;
gear3 = 0;
+ sharedGears = null;
+ syncObjects = null;
}
@Override
@@ -355,25 +370,27 @@ public class Gears implements GLEventListener, TileRendererBase.TileRendererList
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
// Place the first gear and call its display list
- gl.glPushMatrix();
- gl.glTranslatef(-3.0f, -2.0f, 0.0f);
- gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
- gl.glCallList(gear1);
- gl.glPopMatrix();
-
- // Place the second gear and call its display list
- gl.glPushMatrix();
- gl.glTranslatef(3.1f, -2.0f, 0.0f);
- gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
- gl.glCallList(gear2);
- gl.glPopMatrix();
-
- // Place the third gear and call its display list
- gl.glPushMatrix();
- gl.glTranslatef(-3.1f, 4.2f, 0.0f);
- gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
- gl.glCallList(gear3);
- gl.glPopMatrix();
+ synchronized ( syncObjects ) {
+ gl.glPushMatrix();
+ gl.glTranslatef(-3.0f, -2.0f, 0.0f);
+ gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
+ gl.glCallList(gear1);
+ gl.glPopMatrix();
+
+ // Place the second gear and call its display list
+ gl.glPushMatrix();
+ gl.glTranslatef(3.1f, -2.0f, 0.0f);
+ gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
+ gl.glCallList(gear2);
+ gl.glPopMatrix();
+
+ // Place the third gear and call its display list
+ gl.glPushMatrix();
+ gl.glTranslatef(-3.1f, 4.2f, 0.0f);
+ gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
+ gl.glCallList(gear3);
+ gl.glPopMatrix();
+ }
// Remember that every push needs a pop; this one is paired with
// rotating the entire gear assembly