JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
TestSingleGLInJSliderNewtAWT.java
Go to the documentation of this file.
1/**
2 * Copyright 2011-2023 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opengl.test.junit.jogl.acore;
30
31import java.awt.Component;
32import java.awt.Dimension;
33import java.awt.event.WindowAdapter;
34import java.awt.event.WindowEvent;
35import java.io.IOException;
36import java.lang.reflect.InvocationTargetException;
37import java.nio.FloatBuffer;
38import java.nio.IntBuffer;
39import java.util.HashSet;
40import java.util.Set;
41import java.util.concurrent.Semaphore;
42import java.util.concurrent.TimeUnit;
43
44import com.jogamp.opengl.GL;
45import com.jogamp.opengl.GL2;
46import com.jogamp.opengl.GLAutoDrawable;
47import com.jogamp.opengl.GLCapabilities;
48import com.jogamp.opengl.GLEventListener;
49import com.jogamp.opengl.GLProfile;
50import com.jogamp.opengl.awt.GLCanvas;
51import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
52import com.jogamp.opengl.fixedfunc.GLPointerFunc;
53import com.jogamp.opengl.glu.GLU;
54import javax.swing.Box;
55import javax.swing.BoxLayout;
56import javax.swing.JFrame;
57import javax.swing.JLabel;
58import javax.swing.JPanel;
59import javax.swing.JSlider;
60import javax.swing.SwingConstants;
61import javax.swing.SwingUtilities;
62import javax.swing.event.ChangeEvent;
63import javax.swing.event.ChangeListener;
64
65import org.junit.Assert;
66import org.junit.BeforeClass;
67import org.junit.Test;
68import org.junit.FixMethodOrder;
69import org.junit.runners.MethodSorters;
70
71import com.jogamp.common.ExceptionUtils;
72import com.jogamp.common.nio.Buffers;
73import com.jogamp.newt.awt.NewtCanvasAWT;
74import com.jogamp.newt.opengl.GLWindow;
75import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
76import com.jogamp.opengl.test.junit.util.TestUtil;
77import com.jogamp.opengl.test.junit.util.UITestCase;
78import com.jogamp.opengl.util.Animator;
79
80
81/**
82 * TestSingleGLInJSliderNewtAWT
83 *
84 * Opens a single JFrame with one OpenGL widget and sliders to adjust the view orientation.
85 *
86 * The OpenGL widget renders a red triangle and a blue triangle.
87 *
88 * If static useNewt is true, then those OpenGL widgets are GLWindow objects in a NewtCanvasAWT.
89 * If static useNewt is false, then those OpenGL widgets are GLCanvas objects.
90 */
91@FixMethodOrder(MethodSorters.NAME_ASCENDING)
93
94 static long durationPerTest = 1000;
95
96 // This semaphore is released once each time a GLEventListener destroy method is called.
97 // The main thread waits twice on this semaphore to ensure both canvases have finished cleaning up.
98 private static Semaphore disposalCompleteSemaphore = new Semaphore(0);
99
100 @BeforeClass
101 public static void initClass() {
103 setTestSupported(false);
104 }
105 }
106
107 // inner class that implements the event listener
108 static class TwoTriangles implements GLEventListener {
109
110 int canvasWidth;
111 int canvasHeight;
112 private static final float boundsRadius = 2f;
113 private float viewDistance;
114 private static float viewDistanceFactor = 1.0f;
115 private float xAxisRotation;
116 private float yAxisRotation;
117 private static final float viewFovDegrees = 15f;
118
119 // Buffer objects can be shared across canvas instances, if those canvases are initialized with the same GLContext.
120 // If we run with sharedBufferObjects true, then the tests will use these shared buffer objects.
121 // If we run with sharedBufferObjects false, then each event listener allocates its own buffer objects.
122 private final int [] privateVertexBufferObjects = {0};
123 private final int [] privateIndexBufferObjects = {0};
124
125 public static int createVertexBuffer(final GL2 gl2) {
126 final FloatBuffer vertexBuffer = Buffers.newDirectFloatBuffer(18);
127 vertexBuffer.put(new float[]{
128 1.0f, -0.5f, 0f, // vertex 1
129 0f, 0f, 1f, // normal 1
130 1.5f, -0.5f, 0f, // vertex 2
131 0f, 0f, 1f, // normal 2
132 1.0f, 0.5f, 0f, // vertex 3
133 0f, 0f, 1f // normal 3
134 });
135 vertexBuffer.position(0);
136
137 final int[] vbo = { 0 };
138 gl2.glGenBuffers(1, vbo, 0);
139 gl2.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo[0]);
140 gl2.glBufferData(GL.GL_ARRAY_BUFFER, vertexBuffer.capacity() * Buffers.SIZEOF_FLOAT, vertexBuffer, GL.GL_STATIC_DRAW);
142 return vbo[0];
143 }
144 public static int createVertexIndexBuffer(final GL2 gl2) {
145 final IntBuffer indexBuffer = Buffers.newDirectIntBuffer(3);
146 indexBuffer.put(new int[]{0, 1, 2});
147 indexBuffer.position(0);
148
149 final int[] vbo = { 0 };
150 gl2.glGenBuffers(1, vbo, 0);
151 gl2.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, vbo[0]);
152 gl2.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * Buffers.SIZEOF_INT, indexBuffer, GL.GL_STATIC_DRAW);
153 gl2.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
154 return vbo[0];
155 }
156
157 TwoTriangles (final int canvasWidth, final int canvasHeight) {
158 // instanceNum = instanceCounter++;
159 this.canvasWidth = canvasWidth;
160 this.canvasHeight = canvasHeight;
161 }
162
163 public void setXAxisRotation(final float xRot) {
164 xAxisRotation = xRot;
165 }
166
167 public void setYAxisRotation(final float yRot) {
168 yAxisRotation = yRot;
169 }
170
171 public void setViewDistanceFactor(final float factor) {
172 viewDistanceFactor = factor;
173 }
174
175
176 @Override
177 public void init(final GLAutoDrawable drawable) {
178 final GL2 gl2 = drawable.getGL().getGL2();
179
180 System.err.println("INIT GL IS: " + gl2.getClass().getName());
181
182 // Disable VSync
183 gl2.setSwapInterval(0);
184
185 // Setup the drawing area and shading mode
186 gl2.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
187
188 // the first instance of TwoTriangles initializes the shared buffer objects;
189 // synchronizing to deal with potential liveness issues if the data is initialized from one thread and used on another
190 synchronized (this) {
191 // use either the shared or private vertex buffers, as
192 System.err.println("Using local VBOs on slave 0x"+Integer.toHexString(hashCode()));
193 final int [] vertexBufferObjects = privateVertexBufferObjects;
194 final int [] indexBufferObjects = privateIndexBufferObjects;
195
196 System.err.println("Creating vertex VBO on slave 0x"+Integer.toHexString(hashCode()));
197 vertexBufferObjects[0] = createVertexBuffer(gl2);
198
199 // A check in the case that buffer sharing is enabled but context sharing is not enabled -- in that
200 // case, the buffer objects are not shareable, and the blue triangle cannot be rendereds.
201 // Furthermore, although the calls to bind and draw elements do not cause an error from glGetError
202 // when this check is removed, true blue triangle is not rendered anyways, and more importantly,
203 // I found that with my system glDrawElements causes a runtime exception 50% of the time. Executing the binds
204 // to unshareable buffers sets up glDrawElements for unpredictable crashes -- sometimes it does, sometimes not.
205 if (gl2.glIsBuffer(vertexBufferObjects[0])) {
206 gl2.glBindBuffer(GL.GL_ARRAY_BUFFER, vertexBufferObjects[0]);
207 //
208 gl2.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
209 gl2.glVertexPointer(3, GL.GL_FLOAT, 6 * Buffers.SIZEOF_FLOAT, 0);
210 //
211 gl2.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
212 gl2.glNormalPointer(GL.GL_FLOAT, 6 * Buffers.SIZEOF_FLOAT, 3 * Buffers.SIZEOF_FLOAT);
213 } else {
214 System.err.println("Vertex VBO is not a buffer on slave 0x"+Integer.toHexString(hashCode()));
215 }
216
217 System.err.println("Creating index VBO on slave 0x"+Integer.toHexString(hashCode()));
218 indexBufferObjects[0] = createVertexIndexBuffer(gl2);
219
220 // again, a check in the case that buffer sharing is enabled but context sharing is not enabled
221 if (gl2.glIsBuffer(indexBufferObjects[0])) {
222 gl2.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]);
223 } else {
224 System.err.println("Index VBO is not a buffer on slave 0x"+Integer.toHexString(hashCode()));
225 }
226
227 gl2.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
228 gl2.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
229 gl2.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
230 gl2.glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
231 } // synchronized (this)
232 }
233
234 @Override
235 public void dispose(final GLAutoDrawable drawable) {
236
237 synchronized (this) {
238 final GL2 gl2 = drawable.getGL().getGL2();
239
240 // release shared resources
241 {
242 // use either the shared or private vertex buffers, as
243 int [] vertexBufferObjects;
244 int [] indexBufferObjects;
245 vertexBufferObjects = privateVertexBufferObjects;
246 indexBufferObjects = privateIndexBufferObjects;
247
248 gl2.glDeleteBuffers(1, vertexBufferObjects, 0);
249 logAnyErrorCodes(this, gl2, "dispose.2");
250 gl2.glDeleteBuffers(1, indexBufferObjects, 0);
251 logAnyErrorCodes(this, gl2, "dispose.3");
252 vertexBufferObjects[0] = 0;
253 indexBufferObjects[0] = 0;
254 }
255
256 // release the main thread once for each disposal
257 disposalCompleteSemaphore.release();
258 } // synchronized (this)
259 }
260
261 @Override
262 public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
263 System.err.println("reshape: "+canvasWidth+"x"+canvasHeight+" -> "+width+"x"+height+", [drawable pixel "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+"]");
264 canvasWidth = width;
265 canvasHeight = height;
266 final GL2 gl2 = drawable.getGL().getGL2();
267 viewDistance = setupViewFrustum(gl2, canvasWidth, canvasHeight, boundsRadius, 1.0f, viewFovDegrees);
268 }
269
270 @Override
271 public void display(final GLAutoDrawable drawable) {
272 final GL2 gl2 = drawable.getGL().getGL2();
273 final GLU glu = new GLU();
274
275 logAnyErrorCodes(this, gl2, "display.0");
276
277 // Clear the drawing area
278 gl2.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
279
280 gl2.glViewport(0, 0, canvasWidth, canvasHeight);
281 gl2.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
282 gl2.glLoadIdentity();
283 glu.gluPerspective(viewFovDegrees, (float)canvasWidth/(float)canvasHeight,
284 viewDistance*viewDistanceFactor-boundsRadius, viewDistance*viewDistanceFactor+boundsRadius);
285
286 // Reset the current matrix to the "identity"
287 gl2.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
288 gl2.glLoadIdentity();
289
290 // draw the scene
291 gl2.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS);
292 gl2.glPushMatrix();
293
294 glu.gluLookAt(0, 0, 0 + viewDistance*viewDistanceFactor, 0, 0, 0, 0, 1, 0);
295 gl2.glRotatef(xAxisRotation, 1, 0, 0);
296 gl2.glRotatef(yAxisRotation, 0, 1, 0);
297
298 gl2.glDisable(GL.GL_CULL_FACE);
299 gl2.glEnable(GL.GL_DEPTH_TEST);
300
301 logAnyErrorCodes(this, gl2, "display.1");
302
303 // draw the triangles
304 drawTwoTriangles(gl2);
305
306 gl2.glPopMatrix();
307 gl2.glPopAttrib();
308
309 // Flush all drawing operations to the graphics card
310 gl2.glFlush();
311
312 logAnyErrorCodes(this, gl2, "display.X");
313 }
314
315 public void drawTwoTriangles(final GL2 gl2) {
316
317 // draw a red triangle the old fashioned way
318 gl2.glColor3f(1f, 0f, 0f);
319 gl2.glBegin(GL.GL_TRIANGLES);
320 gl2.glVertex3d(-1.5, -0.5, 0);
321 gl2.glNormal3d(0, 0, 1);
322 gl2.glVertex3d(-0.5, -0.5, 0);
323 gl2.glNormal3d(0, 0, 1);
324 gl2.glVertex3d(-0.75, 0.5, 0);
325 gl2.glNormal3d(0, 0, 1);
326 gl2.glEnd();
327
328 logAnyErrorCodes(this, gl2, "drawTwoTriangles.1");
329
330 // draw the blue triangle using a vertex array object, sharing the vertex and index buffer objects across
331 // contexts; if context sharing is not initialized, then one window will simply have to live without a blue triangle
332 //
333 // synchronizing to deal with potential liveness issues if the data is initialized from one
334 // thread and used on another
335 boolean vboBound = false;
336 // use either the shared or private vertex buffers, as
337 int [] vertexBufferObjects;
338 int [] indexBufferObjects;
339 synchronized (this) {
340 vertexBufferObjects = privateVertexBufferObjects;
341 indexBufferObjects = privateIndexBufferObjects;
342 } // synchronized (this)
343
344 // A check in the case that buffer sharing is enabled but context sharing is not enabled -- in that
345 // case, the buffer objects are not shareable, and the blue triangle cannot be rendereds.
346 // Furthermore, although the calls to bind and draw elements do not cause an error from glGetError
347 // when this check is removed, true blue triangle is not rendered anyways, and more importantly,
348 // I found that with my system glDrawElements causes a runtime exception 50% of the time. Executing the binds
349 // to unshareable buffers sets up glDrawElements for unpredictable crashes -- sometimes it does, sometimes not.
350 final boolean isVBO1 = gl2.glIsBuffer(indexBufferObjects[0]);
351 final boolean isVBO2 = gl2.glIsBuffer(vertexBufferObjects[0]);
352 final boolean useVBO = isVBO1 && isVBO2;
353 if ( useVBO ) {
354 gl2.glBindBuffer(GL.GL_ARRAY_BUFFER, vertexBufferObjects[0]);
355 gl2.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]);
356
357 gl2.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
358 // gl2.glVertexPointer(3, GL2.GL_FLOAT, 6 * GLBuffers.SIZEOF_FLOAT, 0);
359 gl2.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
360 // gl2.glNormalPointer(GL2.GL_FLOAT, 6 * GLBuffers.SIZEOF_FLOAT, 3 * GLBuffers.SIZEOF_FLOAT);
361 vboBound = true;
362 }
363 // System.err.println("XXX VBO bound "+vboBound+"[ vbo1 "+isVBO1+", vbo2 "+isVBO2+"]");
364
365 logAnyErrorCodes(this, gl2, "drawTwoTriangles.2");
366
367 if (vboBound) {
368 gl2.glColor3f(0f, 0f, 1f);
369 gl2.glDrawElements(GL.GL_TRIANGLES, 3, GL.GL_UNSIGNED_INT, 0);
370 gl2.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
371 gl2.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
372 gl2.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
373 gl2.glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
374 }
375
376 logAnyErrorCodes(this, gl2, "drawTwoTriangles.3");
377 }
378
379 public void displayChanged(final GLAutoDrawable drawable, final boolean modeChanged, final boolean deviceChanged) {
380 }
381
382 } // inner class TwoTriangles
383
384 private static final Set<String> errorSet = new HashSet<String>();
385
386 public static void logAnyErrorCodes(final Object obj, final GL gl, final String prefix) {
387 final int glError = gl.glGetError();
388 if(glError != GL.GL_NO_ERROR) {
389 final String errStr = "GL-Error: "+prefix + " on obj 0x"+Integer.toHexString(obj.hashCode())+", OpenGL error: 0x" + Integer.toHexString(glError);
390 if( errorSet.add(errStr) ) {
391 System.err.println(errStr);
392 ExceptionUtils.dumpStack(System.err);
393 }
394 }
395 final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER);
396 if (status != GL.GL_FRAMEBUFFER_COMPLETE) {
397 final String errStr = "GL-Error: "+prefix + " on obj 0x"+Integer.toHexString(obj.hashCode())+", glCheckFramebufferStatus: 0x" + Integer.toHexString(status);
398 if( errorSet.add(errStr) ) {
399 System.err.println(errStr);
400 ExceptionUtils.dumpStack(System.err);
401 }
402 }
403 }
404
405 /**
406 * Sets the OpenGL projection matrix and front and back clipping planes for
407 * a viewport and returns the distance the camera should be placed from
408 * the center of the scene's bounding sphere such that the geometry is
409 * centered in the view frustum.
410 *
411 * @param gl2 current OpenGL context
412 * @param width width of GLDrawable
413 * @param height height of GLDrawable
414 * @param boundsRadius radius of a minimal bounding sphere of objects to be
415 * rendered in the viewport
416 * @param zoomFactor affects how far away the camera is placed from the scene; changing the
417 * zoom from 1.0 to 0.5 would make the scene appear half the size
418 * @param viewFovDegrees the desired field of vision for the viewport,
419 * higher is more fish-eye
420 * @return the distance the camera should be from the center of the scenes
421 * bounding sphere
422 */
423 public static float setupViewFrustum(final GL2 gl2, final int width, final int height, final float boundsRadius, final float zoomFactor, final float viewFovDegrees) {
424 assert boundsRadius > 0.0f;
425 assert zoomFactor > 0.0f;
426 assert viewFovDegrees > 0.0f;
427
428 final GLU glu = new GLU();
429
430 final float aspectRatio = (float) width / (float) height;
431 final float boundRadiusAdjusted = boundsRadius / zoomFactor;
432 final float lowestFov = aspectRatio > 1.0f ? viewFovDegrees : aspectRatio * viewFovDegrees;
433 final float viewDist = (float) (boundRadiusAdjusted / Math.sin( (lowestFov / 2.0) * (Math.PI / 180.0) ));
434
436 gl2.glLoadIdentity();
437 glu.gluPerspective(viewFovDegrees, aspectRatio, 0.1*viewDist, viewDist + boundRadiusAdjusted);
438
439 return viewDist;
440 }
441
442 @Test
443 public void test01UseAWTNotShared() throws InterruptedException, InvocationTargetException {
444 testCreateVisibleDestroy(false);
445 }
446
447 @Test
448 public void test10UseNEWTNotShared() throws InterruptedException, InvocationTargetException {
449 testCreateVisibleDestroy(true);
450 }
451
452 /**
453 * Assemble the user interface and start the animator.
454 * It waits until the window is closed an then attempts orderly shutdown and resource deallocation.
455 */
456 public void testCreateVisibleDestroy(final boolean useNewt) throws InterruptedException, InvocationTargetException {
457 final JFrame frame = new JFrame("JSlider with "+(useNewt?"NEWT":"AWT")+"-OpenGL Widget");
458 final TestUtil.WindowClosingListener awtClosingListener = AWTRobotUtil.addClosingListener(frame);
459
460 //
461 // GLDrawableFactory factory = GLDrawableFactory.getFactory(GLProfile.get(GLProfile.GL2));
462 // GLContext sharedContext = factory.getOrCreateSharedContext(factory.getDefaultDevice());
463 //
464 final GLCapabilities glCapabilities = new GLCapabilities(GLProfile.get(GLProfile.GL2));
465 glCapabilities.setSampleBuffers(true);
466 glCapabilities.setNumSamples(4);
467
468 final TwoTriangles eventListener1 = new TwoTriangles(480, 480);
469
470 final Component openGLComponent1;
471 final GLAutoDrawable openGLAutoDrawable1;
472
473 if (useNewt) {
474 final GLWindow glWindow1 = GLWindow.create(glCapabilities);
475 final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1);
476 newtCanvasAWT1.setPreferredSize(new Dimension(eventListener1.canvasWidth, eventListener1.canvasHeight));
477 glWindow1.addGLEventListener(eventListener1);
478 //
479 openGLComponent1 = newtCanvasAWT1;
480 openGLAutoDrawable1 = glWindow1;
481 } else {
482 // Implementation using two GLCanvas instances; for GLCanvas context sharing to work, you must pass it in
483 // through the constructor; if you set it after it has no effect -- it does no harm if you initialized the ctor
484 // with the shared context, but if you didn't, it also doesn't trigger sharing
485 final GLCanvas canvas1;
486
487 canvas1 = new GLCanvas(glCapabilities);
488 canvas1.setSize(eventListener1.canvasWidth, eventListener1.canvasHeight);
489 canvas1.addGLEventListener(eventListener1);
490
491 openGLComponent1 = canvas1;
492 openGLAutoDrawable1 = canvas1;
493 }
494
495 // Create slider for x rotation.
496 // The vertically oriented slider rotates around the x axis
497 final JSlider xAxisRotationSlider = new JSlider(SwingConstants.VERTICAL, -180, 180, 1);
498 xAxisRotationSlider.setPaintTicks(false);
499 xAxisRotationSlider.setPaintLabels(false);
500 xAxisRotationSlider.setSnapToTicks(false);
501 xAxisRotationSlider.addChangeListener(new ChangeListener() {
502
503 @Override
504 public void stateChanged(final ChangeEvent e) {
505 eventListener1.setXAxisRotation(xAxisRotationSlider.getValue());
506 }
507 });
508 final JLabel xAxisRotationLabel = new JLabel("X-Axis Rotation");
509
510 // Create slider for y rotation.
511 // The horizontally oriented slider rotates around the y axis
512 final JSlider yAxisRotationSlider = new JSlider(SwingConstants.HORIZONTAL, -180, 180, 1);
513 yAxisRotationSlider.setPaintTicks(false);
514 yAxisRotationSlider.setPaintLabels(false);
515 yAxisRotationSlider.setSnapToTicks(false);
516 yAxisRotationSlider.addChangeListener(new ChangeListener() {
517
518 @Override
519 public void stateChanged(final ChangeEvent e) {
520 eventListener1.setYAxisRotation(yAxisRotationSlider.getValue());
521 }
522 });
523 final JLabel yAxisRotationLabel = new JLabel("Y-Axis Rotation");
524
525 // Create slider for view distance factor.
526 // We want a range of 0.0 to 10.0 with 0.1 increments (so we can scale down using 0.0 to 1.0).
527 // So, set JSlider to 0 to 100 and divide by 10.0 in stateChanged
528 final JSlider viewDistanceFactorSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 10);
529 viewDistanceFactorSlider.setPaintTicks(false);
530 viewDistanceFactorSlider.setPaintLabels(false);
531 viewDistanceFactorSlider.setSnapToTicks(false);
532 viewDistanceFactorSlider.addChangeListener(new ChangeListener() {
533
534 @Override
535 public void stateChanged(final ChangeEvent e) {
536 eventListener1.setViewDistanceFactor(viewDistanceFactorSlider.getValue() / 10.0f);
537 }
538 });
539 final JLabel viewDistanceFactorLabel = new JLabel("View Distance Factor");
540
541 // group the view distance and label into a vertical panel
542 final JPanel viewDistancePanel = new JPanel();
543 viewDistancePanel.setLayout(new BoxLayout(viewDistancePanel, BoxLayout.PAGE_AXIS));
544 viewDistancePanel.add(Box.createVerticalGlue());
545 viewDistancePanel.add(viewDistanceFactorSlider);
546 viewDistancePanel.add(viewDistanceFactorLabel);
547 viewDistancePanel.add(Box.createVerticalGlue());
548
549 // group both OpenGL canvases / windows into a horizontal panel
550 final JPanel openGLPanel = new JPanel();
551 openGLPanel.setLayout(new BoxLayout(openGLPanel, BoxLayout.LINE_AXIS));
552 openGLPanel.add(openGLComponent1);
553 openGLPanel.add(Box.createHorizontalStrut(5));
554
555 // group the open GL panel and the y-axis rotation slider into a vertical panel.
556 final JPanel canvasAndYAxisPanel = new JPanel();
557 canvasAndYAxisPanel.setLayout(new BoxLayout(canvasAndYAxisPanel, BoxLayout.PAGE_AXIS));
558 canvasAndYAxisPanel.add(openGLPanel);
559 canvasAndYAxisPanel.add(Box.createVerticalGlue());
560 canvasAndYAxisPanel.add(yAxisRotationSlider);
561 canvasAndYAxisPanel.add(yAxisRotationLabel);
562
563 // group the X-axis rotation slider and label into a horizontal panel.
564 final JPanel xAxisPanel = new JPanel();
565 xAxisPanel.setLayout(new BoxLayout(xAxisPanel, BoxLayout.LINE_AXIS));
566 xAxisPanel.add(xAxisRotationSlider);
567 xAxisPanel.add(xAxisRotationLabel);
568
569 final JPanel mainPanel = (JPanel) frame.getContentPane();
570 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));
571 mainPanel.add(viewDistancePanel);
572 mainPanel.add(Box.createHorizontalGlue());
573 mainPanel.add(canvasAndYAxisPanel);
574 mainPanel.add(Box.createHorizontalGlue());
575 mainPanel.add(xAxisPanel);
576
577 final Animator animator = new Animator(Thread.currentThread().getThreadGroup());
578 animator.setUpdateFPSFrames(1, null);
579 animator.add(openGLAutoDrawable1);
580
581 final Semaphore windowOpenSemaphore = new Semaphore(0);
582 final Semaphore closingSemaphore = new Semaphore(0);
583
584 // signal the main thread when the frame is closed
585 frame.addWindowListener(new WindowAdapter() {
586
587 @Override
588 public void windowClosing(final WindowEvent e) {
589 closingSemaphore.release();
590 }
591 });
592
593 // make the window visible using the EDT
594 SwingUtilities.invokeLater( new Runnable() {
595 @Override
596 public void run() {
597 frame.pack();
598 frame.setVisible(true);
599 windowOpenSemaphore.release();
600 }
601 });
602
603 // wait for the window to be visible and start the animation
604 try {
605 final boolean windowOpened = windowOpenSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS);
606 Assert.assertEquals(true, windowOpened);
607 } catch (final InterruptedException e) {
608 System.err.println("Closing wait interrupted: " + e.getMessage());
609 }
610 animator.start();
611
612 // sleep for test duration, then request the window to close, wait for the window to close,s and stop the animation
613 try {
614 while(animator.isAnimating() && animator.getTotalFPSDuration() < durationPerTest) {
615 Thread.sleep(100);
616 }
617 AWTRobotUtil.closeWindow(frame, true, awtClosingListener, null);
618 final boolean windowClosed = closingSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS);
619 Assert.assertEquals(true, windowClosed);
620 } catch (final InterruptedException e) {
621 System.err.println("Closing wait interrupted: " + e.getMessage());
622 }
623 animator.stop();
624
625 // ask the EDT to dispose of the frame;
626 // if using newt, explicitly dispose of the canvases because otherwise it seems our destroy methods are not called
627 SwingUtilities.invokeLater( new Runnable() {
628 @Override
629 public void run() {
630 frame.setVisible(false);
631 frame.dispose();
632 if (useNewt) {
633 ((NewtCanvasAWT)openGLComponent1).destroy();
634 }
635 closingSemaphore.release();
636 }
637 });
638
639 // wait for orderly destruction; it seems that if we share a GLContext across newt windows, bad things happen;
640 // I must be doing something wrong but I haven't figured it out yet
641 try {
642 final boolean windowsDisposed = closingSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS);
643 Assert.assertEquals(true, windowsDisposed);
644 } catch (final InterruptedException e) {
645 System.err.println("Closing wait interrupted: " + e.getMessage());
646 }
647
648 // ensure that the two OpenGL canvas' destroy methods completed successfully and released resources before we move on
649 int disposalSuccesses = 0;
650 try {
651 boolean acquired;
652 acquired = disposalCompleteSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS);
653 if (acquired){
654 disposalSuccesses++;
655 }
656 } catch (final InterruptedException e) {
657 System.err.println("Clean exit interrupted: " + e.getMessage());
658 }
659
660 Assert.assertEquals(true, disposalSuccesses == 1);
661 }
662
663 static int atoi(final String a) {
664 int i=0;
665 try {
666 i = Integer.parseInt(a);
667 } catch (final Exception ex) { ex.printStackTrace(); }
668 return i;
669 }
670
671 public static void main(final String[] args) throws IOException {
672 for(int i=0; i<args.length; i++) {
673 if(args[i].equals("-time")) {
674 if (++i < args.length) {
675 durationPerTest = atoi(args[i]);
676 }
677 }
678 }
679 org.junit.runner.JUnitCore.main(TestSingleGLInJSliderNewtAWT.class.getName());
680 }
681
682}
683
AWT Canvas containing a NEWT Window using native parenting.
NEWT Window events are provided for notification purposes ONLY.
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
static GLWindow create(final GLCapabilitiesImmutable caps)
Creates a new GLWindow attaching a new Window referencing a new default Screen and default Display wi...
Definition: GLWindow.java:169
Specifies a set of OpenGL capabilities.
void setNumSamples(final int numSamples)
If sample buffers are enabled, indicates the number of buffers to be allocated.
void setSampleBuffers(final boolean enable)
Defaults to false.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
static boolean isAvailable(final AbstractGraphicsDevice device, final String profile)
Returns the availability of a profile on a device.
Definition: GLProfile.java:305
static GLProfile get(final AbstractGraphicsDevice device, String profile)
Returns a GLProfile object.
static final String GL2
The desktop OpenGL profile 1.x up to 3.0.
Definition: GLProfile.java:579
A heavyweight AWT component which provides OpenGL rendering support.
Definition: GLCanvas.java:170
void addGLEventListener(final GLEventListener listener)
Adds the given listener to the end of this drawable queue.
Definition: GLCanvas.java:1065
Provides access to the OpenGL Utility Library (GLU).
Definition: GLU.java:43
void gluPerspective(float fovy, float aspect, float zNear, float zFar)
Definition: GLU.java:1362
static float setupViewFrustum(final GL2 gl2, final int width, final int height, final float boundsRadius, final float zoomFactor, final float viewFovDegrees)
Sets the OpenGL projection matrix and front and back clipping planes for a viewport and returns the d...
static void logAnyErrorCodes(final Object obj, final GL gl, final String prefix)
void testCreateVisibleDestroy(final boolean useNewt)
Assemble the user interface and start the animator.
static TestUtil.WindowClosingListener addClosingListener(final java.awt.Window win)
static boolean closeWindow(final java.awt.Window win, final boolean willClose, final TestUtil.WindowClosingListener closingListener, final Runnable waitAction)
Programmatically issue windowClosing on AWT or NEWT.
final synchronized void add(final GLAutoDrawable drawable)
Adds a drawable to this animator's list of rendering drawables.
final void setUpdateFPSFrames(final int frames, final PrintStream out)
final synchronized boolean start()
Starts this animator, if not running.
Definition: Animator.java:344
final synchronized boolean stop()
Stops this animator.
Definition: Animator.java:368
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.
Declares events which client code can use to manage OpenGL rendering into a GLAutoDrawable.
void glGenBuffers(int n, IntBuffer buffers)
Entry point to C language function: void {@native glGenBuffers}(GLsizei n, GLuint * buffers) Part ...
static final int GL_STATIC_DRAW
GL_VERSION_1_5, GL_ES_VERSION_2_0, GL_VERSION_ES_1_0, GL_ARB_vertex_buffer_object Alias for: GL_STATI...
Definition: GL.java:673
int glCheckFramebufferStatus(int target)
Entry point to C language function: GLenum {@native glCheckFramebufferStatus}(GLenum target) Part ...
static final int GL_NO_ERROR
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_NO_ERROR" with expres...
Definition: GL.java:481
int glGetError()
Entry point to C language function: GLenum {@native glGetError}() Part of GL_ES_VERSION_2_0,...
static final int GL_FRAMEBUFFER_COMPLETE
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:605
void glBindBuffer(int target, int buffer)
Entry point to C language function: void {@native glBindBuffer}(GLenum target, GLuint buffer) Part...
static final int GL_FRAMEBUFFER
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_OES_framebuffer_object,...
Definition: GL.java:630
void glBufferData(int target, long size, Buffer data, int usage)
Entry point to C language function: void {@native glBufferData}(GLenum target, GLsizeiptr size,...
static final int GL_ARRAY_BUFFER
GL_VERSION_1_5, GL_ES_VERSION_2_0, GL_VERSION_ES_1_0, GL_ARB_vertex_buffer_object Alias for: GL_ARRAY...
Definition: GL.java:633
void setSize(int width, int height)
Requests a new width and height for this AWTGLAutoDrawable.
Subset of OpenGL fixed function pipeline's matrix operations.
static final int GL_PROJECTION
Matrix mode projection.
void glLoadIdentity()
Load the current matrix with the identity matrix.
void glMatrixMode(int mode)
Sets the current matrix mode.