diff options
author | Sven Gothel <[email protected]> | 2019-06-23 08:03:04 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2019-06-23 08:03:04 +0200 |
commit | bba73bc096250a3c7fc036d84b1ea054d1b70b06 (patch) | |
tree | ed02575eac2a46bd49627444dcce972946ae8d2e /src | |
parent | 154e91978498d8b6db9ce34a1f06b298bcf4c361 (diff) |
iOS: Initial working commit supporting iOS (ipad pro 11)
using our OpenJFK 9 x86_64 and arm64 build.
Test demo class is 'com.jogamp.opengl.demos.ios.Hello',
residing in the new demo folder 'src/demos/com/jogamp/opengl/demos/ios/Hello.java'.
This commit does not yet include a working NEWT
specialization for iOS, but it shall followup soon.
Instead this commit demonstrates JOGL operating on
native UIWindow, UIView and CAEAGLLayer as provided by
Nativewindow's IOSUtil.
Test Video https://www.youtube.com/watch?v=Z4lUQNFTGMI
+++
Notable bug: The FBO used and sharing the COLORBUFFER RENDERBUFFER
memory resources with CAEAGLLayer to be displayed in the UIView
seemingly cannot handle GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24
or GL_DEPTH_COMPONENT32 depth buffer - none at all (Device + Simulation).
Therefor the default demo GLEventListener chosen here
don't require a depth buffer ;-)
This issue can hopefully be mitigated with other means
than using a flat FBO sink similar to FBO multisampling.
Diffstat (limited to 'src')
84 files changed, 10796 insertions, 217 deletions
diff --git a/src/demos/com/jogamp/opengl/demos/GearsObject.java b/src/demos/com/jogamp/opengl/demos/GearsObject.java new file mode 100644 index 000000000..6ae4d87b4 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/GearsObject.java @@ -0,0 +1,336 @@ +/** + * Copyright (C) 2011 JogAmp Community. 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. + */ +package com.jogamp.opengl.demos; + +import java.nio.FloatBuffer; + +import com.jogamp.opengl.GL; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.util.GLArrayDataServer; + +/** + * GearsObject.java <BR> + * @author Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P> + */ +public abstract class GearsObject { + public static final FloatBuffer red = Buffers.newDirectFloatBuffer( new float[] { 0.8f, 0.1f, 0.0f, 0.7f } ); + public static final FloatBuffer green = Buffers.newDirectFloatBuffer( new float[] { 0.0f, 0.8f, 0.2f, 0.7f } ); + public static final FloatBuffer blue = Buffers.newDirectFloatBuffer( new float[] { 0.2f, 0.2f, 1.0f, 0.7f } ); + public static final float M_PI = (float)Math.PI; + + public final FloatBuffer gearColor; + public GLArrayDataServer frontFace; + public GLArrayDataServer frontSide; + public GLArrayDataServer backFace; + public GLArrayDataServer backSide; + public GLArrayDataServer outwardFace; + public GLArrayDataServer insideRadiusCyl; + public boolean isShared; + protected boolean validateBuffers = false; + + public abstract GLArrayDataServer createInterleaved(boolean useMappedBuffers, int comps, int dataType, boolean normalized, int initialSize, int vboUsage); + public abstract void addInterleavedVertexAndNormalArrays(GLArrayDataServer array, int components); + public abstract void draw(GL gl, float x, float y, float angle); + + private GLArrayDataServer createInterleavedClone(final GLArrayDataServer ads) { + final GLArrayDataServer n = new GLArrayDataServer(ads); + n.setInterleavedOffset(0); + return n; + } + + private void init(final GL gl, final GLArrayDataServer array) { + array.enableBuffer(gl, true); + array.enableBuffer(gl, false); + } + + public void destroy(final GL gl) { + if(!isShared) { + // could be already destroyed by shared configuration + if(null != frontFace) { + frontFace.destroy(gl); + } + if(null != frontSide) { + frontSide.destroy(gl); + } + if(null != backFace) { + backFace.destroy(gl); + } + if(null != backSide) { + backSide.destroy(gl); + } + if(null != outwardFace) { + outwardFace.destroy(gl); + } + if(null != insideRadiusCyl) { + insideRadiusCyl.destroy(gl); + } + } + frontFace=null; + frontSide=null; + backFace=null; + backSide=null; + outwardFace=null; + insideRadiusCyl=null; + isShared = false; + } + + public GearsObject ( final GearsObject shared ) { + isShared = true; + validateBuffers = shared.validateBuffers; + frontFace = createInterleavedClone(shared.frontFace); + addInterleavedVertexAndNormalArrays(frontFace, 3); + backFace = createInterleavedClone(shared.backFace); + addInterleavedVertexAndNormalArrays(backFace, 3); + frontSide = createInterleavedClone(shared.frontSide); + addInterleavedVertexAndNormalArrays(frontSide, 3); + backSide= createInterleavedClone(shared.backSide); + addInterleavedVertexAndNormalArrays(backSide, 3); + outwardFace = createInterleavedClone(shared.outwardFace); + addInterleavedVertexAndNormalArrays(outwardFace, 3); + insideRadiusCyl = createInterleavedClone(shared.insideRadiusCyl); + addInterleavedVertexAndNormalArrays(insideRadiusCyl, 3); + gearColor = shared.gearColor; + } + + public GearsObject ( + final GL gl, + final boolean useMappedBuffers, + final FloatBuffer gearColor, + final float inner_radius, + final float outer_radius, + final float width, final int teeth, final float tooth_depth, final boolean validateBuffers) + { + final float dz = width * 0.5f; + int i; + float r0, r1, r2; + float angle, da; + float u, v, len; + final float s[] = new float[5]; + final float c[] = new float[5]; + final float normal[] = new float[3]; + // final int tris_per_tooth = 32; + + this.validateBuffers = validateBuffers; + this.isShared = false; + this.gearColor = gearColor; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth / 2.0f; + r2 = outer_radius + tooth_depth / 2.0f; + + da = 2.0f * (float) Math.PI / teeth / 4.0f; + + s[4] = 0; // sin(0f) + c[4] = 1; // cos(0f) + + final int vboUsage = GL.GL_STATIC_DRAW; + + frontFace = createInterleaved(useMappedBuffers, 6, GL.GL_FLOAT, false, 4*teeth+2, vboUsage); + addInterleavedVertexAndNormalArrays(frontFace, 3); + backFace = createInterleaved(useMappedBuffers, 6, GL.GL_FLOAT, false, 4*teeth+2, vboUsage); + addInterleavedVertexAndNormalArrays(backFace, 3); + frontSide = createInterleaved(useMappedBuffers, 6, GL.GL_FLOAT, false, 6*teeth, vboUsage); + addInterleavedVertexAndNormalArrays(frontSide, 3); + backSide = createInterleaved(useMappedBuffers, 6, GL.GL_FLOAT, false, 6*teeth, vboUsage); + addInterleavedVertexAndNormalArrays(backSide, 3); + outwardFace = createInterleaved(useMappedBuffers, 6, GL.GL_FLOAT, false, 4*4*teeth+2, vboUsage); + addInterleavedVertexAndNormalArrays(outwardFace, 3); + insideRadiusCyl = createInterleaved(useMappedBuffers, 6, GL.GL_FLOAT, false, 2*teeth+2, vboUsage); + addInterleavedVertexAndNormalArrays(insideRadiusCyl, 3); + + if( useMappedBuffers ) { + frontFace.mapStorage(gl, GL.GL_WRITE_ONLY); + backFace.mapStorage(gl, GL.GL_WRITE_ONLY); + frontSide.mapStorage(gl, GL.GL_WRITE_ONLY); + backSide.mapStorage(gl, GL.GL_WRITE_ONLY); + outwardFace.mapStorage(gl, GL.GL_WRITE_ONLY); + insideRadiusCyl.mapStorage(gl, GL.GL_WRITE_ONLY); + } + + for (i = 0; i < teeth; i++) { + angle = i * 2.0f * M_PI / teeth; + sincos(angle + da * 0f, s, 0, c, 0); + sincos(angle + da * 1f, s, 1, c, 1); + sincos(angle + da * 2f, s, 2, c, 2); + sincos(angle + da * 3f, s, 3, c, 3); + + /* front */ + normal[0] = 0.0f; + normal[1] = 0.0f; + normal[2] = 1.0f; + + /* front face - GL.GL_TRIANGLE_STRIP */ + vert(frontFace, r0 * c[0], r0 * s[0], dz, normal); + vert(frontFace, r1 * c[0], r1 * s[0], dz, normal); + vert(frontFace, r0 * c[0], r0 * s[0], dz, normal); + vert(frontFace, r1 * c[3], r1 * s[3], dz, normal); + + /* front sides of teeth - GL.GL_TRIANGLES */ + vert(frontSide, r1 * c[0], r1 * s[0], dz, normal); + vert(frontSide, r2 * c[1], r2 * s[1], dz, normal); + vert(frontSide, r2 * c[2], r2 * s[2], dz, normal); + vert(frontSide, r1 * c[0], r1 * s[0], dz, normal); + vert(frontSide, r2 * c[2], r2 * s[2], dz, normal); + vert(frontSide, r1 * c[3], r1 * s[3], dz, normal); + + /* back */ + normal[0] = 0.0f; + normal[1] = 0.0f; + normal[2] = -1.0f; + + /* back face - GL.GL_TRIANGLE_STRIP */ + vert(backFace, r1 * c[0], r1 * s[0], -dz, normal); + vert(backFace, r0 * c[0], r0 * s[0], -dz, normal); + vert(backFace, r1 * c[3], r1 * s[3], -dz, normal); + vert(backFace, r0 * c[0], r0 * s[0], -dz, normal); + + /* back sides of teeth - GL.GL_TRIANGLES*/ + vert(backSide, r1 * c[3], r1 * s[3], -dz, normal); + vert(backSide, r2 * c[2], r2 * s[2], -dz, normal); + vert(backSide, r2 * c[1], r2 * s[1], -dz, normal); + vert(backSide, r1 * c[3], r1 * s[3], -dz, normal); + vert(backSide, r2 * c[1], r2 * s[1], -dz, normal); + vert(backSide, r1 * c[0], r1 * s[0], -dz, normal); + + /* outward faces of teeth */ + u = r2 * c[1] - r1 * c[0]; + v = r2 * s[1] - r1 * s[0]; + len = (float)Math.sqrt(u * u + v * v); + u /= len; + v /= len; + normal[0] = v; + normal[1] = -u; + normal[2] = 0.0f; + + vert(outwardFace, r1 * c[0], r1 * s[0], dz, normal); + vert(outwardFace, r1 * c[0], r1 * s[0], -dz, normal); + vert(outwardFace, r2 * c[1], r2 * s[1], dz, normal); + vert(outwardFace, r2 * c[1], r2 * s[1], -dz, normal); + + normal[0] = c[0]; + normal[1] = s[0]; + vert(outwardFace, r2 * c[1], r2 * s[1], dz, normal); + vert(outwardFace, r2 * c[1], r2 * s[1], -dz, normal); + vert(outwardFace, r2 * c[2], r2 * s[2], dz, normal); + vert(outwardFace, r2 * c[2], r2 * s[2], -dz, normal); + + normal[0] = ( r1 * s[3] - r2 * s[2] ); + normal[1] = ( r1 * c[3] - r2 * c[2] ) * -1.0f ; + vert(outwardFace, r2 * c[2], r2 * s[2], dz, normal); + vert(outwardFace, r2 * c[2], r2 * s[2], -dz, normal); + vert(outwardFace, r1 * c[3], r1 * s[3], dz, normal); + vert(outwardFace, r1 * c[3], r1 * s[3], -dz, normal); + + normal[0] = c[0]; + normal[1] = s[0]; + vert(outwardFace, r1 * c[3], r1 * s[3], dz, normal); + vert(outwardFace, r1 * c[3], r1 * s[3], -dz, normal); + vert(outwardFace, r1 * c[0], r1 * s[0], dz, normal); + vert(outwardFace, r1 * c[0], r1 * s[0], -dz, normal); + + /* inside radius cylinder */ + normal[0] = c[0] * -1.0f; + normal[1] = s[0] * -1.0f; + normal[2] = 0.0f; + vert(insideRadiusCyl, r0 * c[0], r0 * s[0], -dz, normal); + vert(insideRadiusCyl, r0 * c[0], r0 * s[0], dz, normal); + } + /* finish front face */ + normal[0] = 0.0f; + normal[1] = 0.0f; + normal[2] = 1.0f; + vert(frontFace, r0 * c[4], r0 * s[4], dz, normal); + vert(frontFace, r1 * c[4], r1 * s[4], dz, normal); + frontFace.seal(true); + + /* finish back face */ + normal[2] = -1.0f; + vert(backFace, r1 * c[4], r1 * s[4], -dz, normal); + vert(backFace, r0 * c[4], r0 * s[4], -dz, normal); + backFace.seal(true); + + backSide.seal(true); + frontSide.seal(true); + + /* finish outward face */ + sincos(da * 1f, s, 1, c, 1); + u = r2 * c[1] - r1 * c[4]; + v = r2 * s[1] - r1 * s[4]; + len = (float)Math.sqrt(u * u + v * v); + u /= len; + v /= len; + normal[0] = v; + normal[1] = -u; + normal[2] = 0.0f; + vert(outwardFace, r1 * c[4], r1 * s[4], dz, normal); + vert(outwardFace, r1 * c[4], r1 * s[4], -dz, normal); + outwardFace.seal(true); + + /* finish inside radius cylinder */ + normal[0] = c[4] * -1.0f; + normal[1] = s[4] * -1.0f; + normal[2] = 0.0f; + vert(insideRadiusCyl, r0 * c[4], r0 * s[4], -dz, normal); + vert(insideRadiusCyl, r0 * c[4], r0 * s[4], dz, normal); + insideRadiusCyl.seal(true); + + if( useMappedBuffers ) { + frontFace.unmapStorage(gl); + backFace.unmapStorage(gl); + frontSide.unmapStorage(gl); + backSide.unmapStorage(gl); + outwardFace.unmapStorage(gl); + insideRadiusCyl.unmapStorage(gl); + } else { + /** Init VBO and data .. */ + init(gl, frontFace); + init(gl, frontSide); + init(gl, backFace); + init(gl, backSide); + init(gl, outwardFace); + init(gl, insideRadiusCyl); + } + } + + @Override + public String toString() { + final int ffVBO = null != frontFace ? frontFace.getVBOName() : 0; + final int fsVBO = null != frontSide ? frontSide.getVBOName() : 0; + final int bfVBO = null != backFace ? backFace.getVBOName() : 0; + final int bsVBO = null != backSide ? backSide.getVBOName() : 0; + return "GearsObj[0x"+Integer.toHexString(hashCode())+", vbo ff "+ffVBO+", fs "+fsVBO+", bf "+bfVBO+", bs "+bsVBO+"]"; + } + + static void vert(final GLArrayDataServer array, final float x, final float y, final float z, final float n[]) { + array.putf(x); + array.putf(y); + array.putf(z); + array.putf(n[0]); + array.putf(n[1]); + array.putf(n[2]); + } + + static void sincos(final float x, final float sin[], final int sinIdx, final float cos[], final int cosIdx) { + sin[sinIdx] = (float) Math.sin(x); + cos[cosIdx] = (float) Math.cos(x); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/PointsDemo.java b/src/demos/com/jogamp/opengl/demos/PointsDemo.java new file mode 100644 index 000000000..749d37114 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/PointsDemo.java @@ -0,0 +1,48 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos; + +import com.jogamp.opengl.GLEventListener; + +public abstract class PointsDemo implements GLEventListener { + int swapInterval = 0; + final int edge = 8; // 8*8 + + public PointsDemo(final int swapInterval) { + this.swapInterval = swapInterval; + } + + public PointsDemo() { + this.swapInterval = 1; + } + + public abstract void setSmoothPoints(boolean v); + + public abstract void setPointParams(float minSize, float maxSize, float distAttenConst, float distAttenLinear, float distAttenQuadratic, float fadeThreshold); + +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java b/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java new file mode 100644 index 000000000..a2d0f5db7 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java @@ -0,0 +1,673 @@ +/** + * Copyright (C) 2011 JogAmp Community. 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. + */ +package com.jogamp.opengl.demos.es2; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.GestureHandler; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +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; +import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.util.CustomGLEventListener; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.TileRendererBase; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; +import com.jogamp.opengl.util.stereo.EyeParameter; +import com.jogamp.opengl.util.stereo.ViewerPose; +import com.jogamp.opengl.util.stereo.StereoGLEventListener; + +import java.nio.FloatBuffer; + +import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLUniformData; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.opengl.demos.GearsObject; + +/** + * GearsES2.java <BR> + * @author Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P> + */ +public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRendererListener { + private final FloatBuffer lightPos = Buffers.newDirectFloatBuffer( new float[] { 5.0f, 5.0f, 10.0f } ); + + private ShaderState st = null; + private PMVMatrix pmvMatrix = null; + private GLUniformData pmvMatrixUniform = null; + private GLUniformData colorU = null; + private float view_rotx = 20.0f, view_roty = 30.0f; + private boolean flipVerticalInGLOrientation = false; + private final boolean customRendering = false; + + private final float view_rotz = 0.0f; + 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; + private FloatBuffer gear1Color=GearsObject.red, gear2Color=GearsObject.green, gear3Color=GearsObject.blue; + private float angle = 0.0f; + private int swapInterval = 0; + // private MouseListener gearsMouse = new TraceMouseAdapter(new GearsMouseAdapter()); + public MouseListener gearsMouse = new GearsMouseAdapter(); + public KeyListener gearsKeys = new GearsKeyAdapter(); + private TileRendererBase tileRendererInUse = null; + private boolean doRotateBeforePrinting; + + private boolean doRotate = true; + private float[] clearColor = null; + private boolean clearBuffers = true; + private boolean verbose = true; + private volatile boolean isInit = false; + + private PinchToZoomGesture pinchToZoomGesture = null; + + + public GearsES2(final int swapInterval) { + this.swapInterval = swapInterval; + } + + public GearsES2() { + this.swapInterval = 1; + } + + @Override + public void addTileRendererNotify(final TileRendererBase tr) { + tileRendererInUse = tr; + doRotateBeforePrinting = doRotate; + setDoRotation(false); + } + @Override + public void removeTileRendererNotify(final TileRendererBase tr) { + tileRendererInUse = null; + setDoRotation(doRotateBeforePrinting); + } + @Override + public void startTileRendering(final TileRendererBase tr) { + System.err.println("GearsES2.startTileRendering: "+sid()+""+tr); + } + @Override + public void endTileRendering(final TileRendererBase tr) { + System.err.println("GearsES2.endTileRendering: "+sid()+""+tr); + } + + public void setDoRotation(final boolean rotate) { this.doRotate = rotate; } + public void setClearBuffers(final boolean v) { clearBuffers = v; } + public void setVerbose(final boolean v) { verbose = v; } + public void setFlipVerticalInGLOrientation(final boolean v) { flipVerticalInGLOrientation=v; } + + /** float[4] */ + public void setClearColor(final float[] clearColor) { + this.clearColor = clearColor; + } + + public void setGearsColors(final FloatBuffer gear1Color, final FloatBuffer gear2Color, final FloatBuffer gear3Color) { + this.gear1Color = gear1Color; + this.gear2Color = gear2Color; + this.gear3Color = gear3Color; + } + + public void setSharedGears(final GearsES2 shared) { + sharedGears = shared; + } + + public void setSyncObjects(final Object sync) { + syncObjects = sync; + } + + /** + * @return gear1 + */ + public GearsObjectES2 getGear1() { return gear1; } + + /** + * @return gear2 + */ + public GearsObjectES2 getGear2() { return gear2; } + + /** + * @return gear3 + */ + public GearsObjectES2 getGear3() { return gear3; } + + public boolean usesSharedGears() { return usesSharedGears; } + + public void setUseMappedBuffers(final boolean v) { useMappedBuffers = v; } + public void setValidateBuffers(final boolean v) { validateBuffers = v; } + + public PMVMatrix getPMVMatrix() { + return pmvMatrix; + } + + private static final int TIME_OUT = 2000; // 2s + private static final int POLL_DIVIDER = 20; // TO/20 + private static final int TIME_SLICE = TIME_OUT / POLL_DIVIDER ; + + /** + * @return True if this GLEventListener became initialized within TIME_OUT 2s + */ + public boolean waitForInit(final boolean initialized) throws InterruptedException { + int wait; + for (wait=0; wait<POLL_DIVIDER && initialized != isInit ; wait++) { + Thread.sleep(TIME_SLICE); + } + return wait<POLL_DIVIDER; + } + + private final String sid() { return "0x"+Integer.toHexString(hashCode()); } + + @Override + public void init(final GLAutoDrawable drawable) { + if(null != sharedGears && !sharedGears.isInit() ) { + System.err.println(Thread.currentThread()+" GearsES2.init.0 "+sid()+": pending shared Gears .. re-init later XXXXX"); + drawable.setGLEventListenerInitState(this, false); + return; + } + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(verbose) { + System.err.println(Thread.currentThread()+" GearsES2.init.0 "+sid()+": tileRendererInUse "+tileRendererInUse+", "+this); + System.err.println("GearsES2 init "+sid()+" on "+Thread.currentThread()); + System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); + System.err.println("INIT GL IS: " + gl.getClass().getName()); + System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); + } + if( !gl.hasGLSL() ) { + System.err.println("No GLSL available, no rendering."); + return; + } + + st = new ShaderState(); + // st.setVerbose(true); + final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), "shader", + "shader/bin", "gears", true); + final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), "shader", + "shader/bin", "gears", true); + vp0.defaultShaderCustomization(gl, true, true); + fp0.defaultShaderCustomization(gl, true, true); + final ShaderProgram sp0 = new ShaderProgram(); + sp0.add(gl, vp0, System.err); + sp0.add(gl, fp0, System.err); + st.attachShaderProgram(gl, sp0, true); + // Use debug pipeline + // drawable.setGL(new DebugGL(drawable.getGL())); + + pmvMatrix = new PMVMatrix(); + st.attachObject("pmvMatrix", pmvMatrix); + pmvMatrixUniform = new GLUniformData("pmvMatrix", 4, 4, pmvMatrix.glGetPMvMvitMatrixf()); // P, Mv, Mvi and Mvit + st.ownUniform(pmvMatrixUniform); + st.uniform(gl, pmvMatrixUniform); + + final GLUniformData lightU = new GLUniformData("lightPos", 3, lightPos); + st.ownUniform(lightU); + st.uniform(gl, lightU); + + colorU = new GLUniformData("color", 4, GearsObject.red); + st.ownUniform(colorU); + st.uniform(gl, colorU); + + if( null != sharedGears ) { + gear1 = new GearsObjectES2(sharedGears.getGear1(), st, pmvMatrix, pmvMatrixUniform, colorU); + gear2 = new GearsObjectES2(sharedGears.getGear2(), st, pmvMatrix, pmvMatrixUniform, colorU); + gear3 = new GearsObjectES2(sharedGears.getGear3(), st, pmvMatrix, pmvMatrixUniform, colorU); + usesSharedGears = true; + if(verbose) { + System.err.println("gear1 "+sid()+" created w/ share: "+sharedGears.getGear1()+" -> "+gear1); + 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) { + System.err.println("gear1 "+sid()+" created: "+gear1); + } + + gear2 = new GearsObjectES2(gl, useMappedBuffers, st, gear2Color, 0.5f, 2.0f, 2.0f, 10, 0.7f, pmvMatrix, pmvMatrixUniform, colorU, validateBuffers); + if(verbose) { + System.err.println("gear2 "+sid()+" created: "+gear2); + } + + gear3 = new GearsObjectES2(gl, useMappedBuffers, st, gear3Color, 1.3f, 2.0f, 0.5f, 10, 0.7f, pmvMatrix, pmvMatrixUniform, colorU, validateBuffers); + if(verbose) { + System.err.println("gear3 "+sid()+" created: "+gear2); + } + if( null == syncObjects ) { + syncObjects = new Object(); + } + } + + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.addMouseListener(gearsMouse); + window.addKeyListener(gearsKeys); + window.addGestureListener(pinchToZoomListener); + pinchToZoomGesture = new PinchToZoomGesture(drawable.getNativeSurface(), false); + window.addGestureHandler(pinchToZoomGesture); + } + + st.useProgram(gl, false); + + gl.glFinish(); // make sure .. for shared context (impacts OSX 10.9) + + isInit = true; + if(verbose) { + System.err.println(Thread.currentThread()+" GearsES2.init.X "+sid()+" FIN "+this); + } + } + + public final boolean isInit() { return isInit; } + + private final GestureHandler.GestureListener pinchToZoomListener = new GestureHandler.GestureListener() { + @Override + public void gestureDetected(final GestureEvent gh) { + final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) gh; + final float zoom = ze.getZoom(); // * ( ze.getTrigger().getPointerCount() - 1 ); <- too much .. + panZ = zoom * 30f - 30f; // [0 .. 2] -> [-30f .. 30f] + } + }; + + @Override + public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { + if( !isInit ) { return; } + final GL2ES2 gl = glad.getGL().getGL2ES2(); + gl.setSwapInterval(swapInterval); + reshapeImpl(gl, x, y, width, height, width, height); + } + + @Override + public void reshapeTile(final TileRendererBase tr, + final int tileX, final int tileY, final int tileWidth, final int tileHeight, + final int imageWidth, final int imageHeight) { + if( !isInit ) { return; } + final GL2ES2 gl = tr.getAttachedDrawable().getGL().getGL2ES2(); + gl.setSwapInterval(0); + reshapeImpl(gl, tileX, tileY, tileWidth, tileHeight, imageWidth, imageHeight); + } + + private float zNear = 5f; + private float zFar = 10000f; + private float zViewDist = 40.0f; + + public void setZ(final float zNear, final float zFar, final float zViewDist) { + this.zNear = zNear; + this.zFar = zFar; + this.zViewDist = zViewDist; + } + + void reshapeImpl(final GL2ES2 gl, final int tileX, final int tileY, final int tileWidth, final int tileHeight, final int imageWidth, final int imageHeight) { + final boolean msaa = gl.getContext().getGLDrawable().getChosenGLCapabilities().getSampleBuffers(); + if(verbose) { + System.err.println(Thread.currentThread()+" GearsES2.reshape "+sid()+" "+tileX+"/"+tileY+" "+tileWidth+"x"+tileHeight+" of "+imageWidth+"x"+imageHeight+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(gl.getContext().getGLDrawable().getHandle())+", msaa "+msaa+", tileRendererInUse "+tileRendererInUse); + } + + if( !gl.hasGLSL() ) { + return; + } + + // compute projection parameters 'normal' + float left, right, bottom, top; + if( imageHeight > imageWidth ) { + final float a = (float)imageHeight / (float)imageWidth; + left = -1.0f; + right = 1.0f; + bottom = -a; + top = a; + } else { + final float a = (float)imageWidth / (float)imageHeight; + left = -a; + right = a; + bottom = -1.0f; + top = 1.0f; + } + final float w = right - left; + final float h = top - bottom; + + // compute projection parameters 'tiled' + final float l = left + tileX * w / imageWidth; + final float r = l + tileWidth * w / imageWidth; + final float b = bottom + tileY * h / imageHeight; + final float t = b + tileHeight * h / imageHeight; + + final float _w = r - l; + final float _h = t - b; + if(verbose) { + System.err.println(">> GearsES2 "+sid()+", angle "+angle+", [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h+", v-flip "+flipVerticalInGLOrientation); + } + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + if( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) { + pmvMatrix.glScalef(1f, -1f, 1f); + } + pmvMatrix.glFrustumf(l, r, b, t, zNear, zFar); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0.0f, 0.0f, -zViewDist); + st.useProgram(gl, true); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + } + // private boolean useAndroidDebug = false; + + private final float[] mat4Tmp1 = new float[16]; + private final float[] mat4Tmp2 = new float[16]; + private final float[] vec3Tmp1 = new float[3]; + private final float[] vec3Tmp2 = new float[3]; + private final float[] vec3Tmp3 = new float[3]; + + private static final float[] vec3ScalePos = new float[] { 20f, 20f, 20f }; + + @Override + public void reshapeForEye(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height, + final EyeParameter eyeParam, final ViewerPose viewerPose) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + final float[] mat4Projection = FloatUtil.makePerspective(mat4Tmp1, 0, true, eyeParam.fovhv, zNear, zFar); + if( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) { + pmvMatrix.glLoadIdentity(); + pmvMatrix.glScalef(1f, -1f, 1f); + pmvMatrix.glMultMatrixf(mat4Projection, 0); + } else { + pmvMatrix.glLoadMatrixf(mat4Projection, 0); + } + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + + final Quaternion rollPitchYaw = new Quaternion(); + // private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians + // rollPitchYaw.rotateByAngleY(eyeYaw); + // final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0); + final float[] shiftedEyePos = VectorUtil.copyVec3(vec3Tmp1, 0, viewerPose.position, 0); + VectorUtil.scaleVec3(shiftedEyePos, shiftedEyePos, vec3ScalePos); // amplify viewerPose position + VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset); + + rollPitchYaw.mult(viewerPose.orientation); + final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0); + final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0); + final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward); + + final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp1, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp2); + final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Tmp2, true, eyeParam.distNoseToPupilX, eyeParam.distMiddleToPupilY, eyeParam.eyeReliefZ); + final float[] mat4Modelview = FloatUtil.multMatrix(mViewAdjust, mLookAt); + + pmvMatrix.glLoadMatrixf(mat4Modelview, 0); + pmvMatrix.glTranslatef(0.0f, 0.0f, -zViewDist); + st.useProgram(gl, true); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + if( !isInit ) { return; } + isInit = false; + if(verbose) { + System.err.println(Thread.currentThread()+" GearsES2.dispose "+sid()+": tileRendererInUse "+tileRendererInUse); + } + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.removeMouseListener(gearsMouse); + window.removeKeyListener(gearsKeys); + window.removeGestureHandler(pinchToZoomGesture); + pinchToZoomGesture = null; + window.removeGestureListener(pinchToZoomListener); + } + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if( !gl.hasGLSL() ) { + return; + } + st.useProgram(gl, false); + gear1.destroy(gl); + gear1 = null; + gear2.destroy(gl); + gear2 = null; + gear3.destroy(gl); + gear3 = null; + pmvMatrix = null; + colorU = null; + st.destroy(gl); + st = null; + sharedGears = null; + syncObjects = null; + + if(verbose) { + System.err.println(Thread.currentThread()+" GearsES2.dispose "+sid()+" FIN"); + } + } + + @Override + public void display(final GLAutoDrawable drawable) { + display(drawable, 0); + } + + @Override + public void display(final GLAutoDrawable drawable, final int flags) { + if( !isInit ) { return; } + if(null != sharedGears && !sharedGears.isInit() ) { return; } + final GLAnimatorControl anim = drawable.getAnimator(); + if( verbose && ( null == anim || !anim.isAnimating() ) ) { + System.err.println(Thread.currentThread()+" GearsES2.display "+sid()+" "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(drawable.getHandle())); + } + + final boolean repeatedFrame = 0 != ( CustomGLEventListener.DISPLAY_REPEAT & flags ); + final boolean dontClear = 0 != ( CustomGLEventListener.DISPLAY_DONTCLEAR & flags ); + + // Turn the gears' teeth + if( doRotate && !repeatedFrame ) { + angle += 0.5f; + } + + // Get the GL corresponding to the drawable we are animating + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + final boolean hasFocus; + final Object upstreamWidget = drawable.getUpstreamWidget(); + if(upstreamWidget instanceof NativeWindow) { + hasFocus = ((NativeWindow)upstreamWidget).hasFocus(); + } else { + hasFocus = true; + } + + if( clearBuffers && !dontClear ) { + if( null != clearColor ) { + gl.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + } else if( null != tileRendererInUse ) { + gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); + } else { + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + } + if( !gl.hasGLSL() ) { + return; + } + + setGLStates(gl, true); + + st.useProgram(gl, true); + pmvMatrix.glPushMatrix(); + pmvMatrix.glTranslatef(panX, panY, panZ); + pmvMatrix.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f); + pmvMatrix.glRotatef(view_roty, 0.0f, 1.0f, 0.0f); + pmvMatrix.glRotatef(view_rotz, 0.0f, 0.0f, 1.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); + + setGLStates(gl, false); + } + + public void setGLStates(final GL2ES2 gl, final boolean enable) { + // Culling only possible if we do not flip the projection matrix + final boolean useCullFace = ! ( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() || customRendering ); + if( enable ) { + gl.glEnable(GL.GL_DEPTH_TEST); + if( useCullFace ) { + gl.glEnable(GL.GL_CULL_FACE); + } + } else { + gl.glDisable(GL.GL_DEPTH_TEST); + if( useCullFace ) { + gl.glDisable(GL.GL_CULL_FACE); + } + } + } + + @Override + public String toString() { + return "GearsES2[obj "+sid()+" isInit "+isInit+", usesShared "+usesSharedGears+", 1 "+gear1+", 2 "+gear2+", 3 "+gear3+", sharedGears "+sharedGears+"]"; + } + + class GearsKeyAdapter extends KeyAdapter { + public void keyPressed(final KeyEvent e) { + final int kc = e.getKeyCode(); + if(KeyEvent.VK_LEFT == kc) { + view_roty -= 1; + } else if(KeyEvent.VK_RIGHT == kc) { + view_roty += 1; + } else if(KeyEvent.VK_UP == kc) { + view_rotx -= 1; + } else if(KeyEvent.VK_DOWN == kc) { + view_rotx += 1; + } + } + } + + class GearsMouseAdapter implements MouseListener{ + private int prevMouseX, prevMouseY; + + @Override + public void mouseClicked(final MouseEvent e) { + } + + @Override + public void mouseEntered(final MouseEvent e) { + } + + @Override + public void mouseExited(final MouseEvent e) { + } + + @Override + public void mouseWheelMoved(final MouseEvent e) { + final float[] rot = e.getRotation(); + if( e.isControlDown() ) { + // alternative zoom + final float incr = e.isShiftDown() ? rot[0] : rot[1] * 0.5f ; + panZ += incr; + System.err.println("panZ.2: incr "+incr+", dblZoom "+e.isShiftDown()+" -> "+panZ); + } else { + // panning + panX -= rot[0]; // positive -> left + panY += rot[1]; // positive -> up + } + } + + public void mousePressed(final MouseEvent e) { + if( e.getPointerCount()==1 ) { + prevMouseX = e.getX(); + prevMouseY = e.getY(); + } else if( e.getPointerCount() == 4 ) { + final Object src = e.getSource(); + if( e.getPressure(0, true) > 0.7f && src instanceof Window) { // show Keyboard + ((Window) src).setKeyboardVisible(true); + } + } + } + + public void mouseReleased(final MouseEvent e) { + } + + public void mouseMoved(final MouseEvent e) { + if( e.isConfined() ) { + navigate(e); + } else { + // track prev. position so we don't have 'jumps' + // in case we move to confined navigation. + prevMouseX = e.getX(); + prevMouseY = e.getY(); + } + } + + public void mouseDragged(final MouseEvent e) { + navigate(e); + } + + private void navigate(final MouseEvent e) { + final int x = e.getX(); + final int y = e.getY(); + + int width, height; + final Object source = e.getSource(); + Window window = null; + if(source instanceof Window) { + window = (Window) source; + width=window.getSurfaceWidth(); + height=window.getSurfaceHeight(); + } else if (source instanceof GLAutoDrawable) { + final GLAutoDrawable glad = (GLAutoDrawable) source; + width = glad.getSurfaceWidth(); + height = glad.getSurfaceHeight(); + } else { + throw new RuntimeException("Event source neither Window nor Component: "+source); + } + final float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)width); + final float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)height); + view_rotx += thetaX; + view_roty += thetaY; + prevMouseX = x; + prevMouseY = y; + // System.err.println("rotXY.1: "+view_rotx+"/"+view_roty+", source "+e); + } + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java b/src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java new file mode 100644 index 000000000..7266240b1 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java @@ -0,0 +1,146 @@ +/** + * Copyright (C) 2011 JogAmp Community. 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. + */ +package com.jogamp.opengl.demos.es2; + +import java.nio.FloatBuffer; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLBufferStorage; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLUniformData; + +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderState; + +import com.jogamp.opengl.demos.GearsObject; + +/** + * GearsObjectES2.java <BR> + * @author Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P> + */ +public class GearsObjectES2 extends GearsObject { + final PMVMatrix pmvMatrix; + final GLUniformData pmvMatrixUniform; + final GLUniformData colorUniform; + final ShaderState st; + + public GearsObjectES2(final GL gl, final boolean useMappedBuffers, final ShaderState st, final FloatBuffer gearColor, + final float inner_radius, final float outer_radius, + final float width, + final int teeth, + final float tooth_depth, final PMVMatrix pmvMatrix, final GLUniformData pmvMatrixUniform, final GLUniformData colorUniform, final boolean validateBuffers) + { + super(gl, useMappedBuffers, gearColor, inner_radius, outer_radius, width, teeth, tooth_depth, validateBuffers); + this.pmvMatrix = pmvMatrix; + this.pmvMatrixUniform = pmvMatrixUniform; + this.colorUniform = colorUniform; + this.st = st; + associate(st); + } + + public GearsObjectES2(final GearsObjectES2 shared, + final ShaderState st, + final PMVMatrix pmvMatrix, + final GLUniformData pmvMatrixUniform, final GLUniformData colorUniform) + { + super(shared); + this.pmvMatrix = pmvMatrix; + this.pmvMatrixUniform = pmvMatrixUniform; + this.colorUniform = colorUniform; + this.st = st; + associate(st); + } + + private void associate(final ShaderState st) { + frontFace.associate(st, true); + frontSide.associate(st, true); + backFace.associate(st, true); + backSide.associate(st, true); + outwardFace.associate(st, true); + insideRadiusCyl.associate(st, true); + } + + @Override + public GLArrayDataServer createInterleaved(final boolean useMappedBuffers, final int comps, final int dataType, final boolean normalized, final int initialSize, final int vboUsage) { + if( useMappedBuffers ) { + return GLArrayDataServer.createGLSLInterleavedMapped(comps, dataType, normalized, initialSize, vboUsage); + } else { + return GLArrayDataServer.createGLSLInterleaved(comps, dataType, normalized, initialSize, vboUsage); + } + } + + @Override + public void addInterleavedVertexAndNormalArrays(final GLArrayDataServer array, final int components) { + array.addGLSLSubArray("vertices", components, GL.GL_ARRAY_BUFFER); + array.addGLSLSubArray("normals", components, GL.GL_ARRAY_BUFFER); + } + + private void draw(final GL2ES2 gl, final GLArrayDataServer array, final int mode, final int face) { + if( !isShared || gl.glIsBuffer(array.getVBOName()) ) { + if( validateBuffers ) { + array.bindBuffer(gl, true); + final int bufferTarget = array.getVBOTarget(); + final int bufferName = array.getVBOName(); + final long bufferSize = array.getSizeInBytes(); + final int hasBufferName = gl.getBoundBuffer(bufferTarget); + final GLBufferStorage hasStorage = gl.getBufferStorage(hasBufferName); + final boolean ok = bufferName == hasBufferName && + bufferName == hasStorage.getName() && + bufferSize == hasStorage.getSize(); + if( !ok ) { + throw new GLException("GLBufferStorage Validation Error: Target[exp 0x"+Integer.toHexString(bufferTarget)+", has 0x"+Integer.toHexString(bufferTarget)+ + ", Name[exp "+bufferName+", has "+hasBufferName+", Size exp "+bufferSize+", Storage "+hasStorage+"]"); + } + } + array.enableBuffer(gl, true); + // System.err.println("XXX Draw face "+face+" of "+this); + gl.glDrawArrays(mode, 0, array.getElementCount()); + array.enableBuffer(gl, false); + } + } + + @Override + public void draw(final GL _gl, final float x, final float y, final float angle) { + final GL2ES2 gl = _gl.getGL2ES2(); + pmvMatrix.glPushMatrix(); + pmvMatrix.glTranslatef(x, y, 0f); + pmvMatrix.glRotatef(angle, 0f, 0f, 1f); + if( pmvMatrix.update() ) { + st.uniform(gl, pmvMatrixUniform); + } else { + throw new InternalError("PMVMatrix.update() returns false after mutable operations"); + } + + colorUniform.setData(gearColor); + st.uniform(gl, colorUniform); + + draw(gl, frontFace, GL.GL_TRIANGLE_STRIP, 0); + draw(gl, frontSide, GL.GL_TRIANGLES, 1); + draw(gl, backFace, GL.GL_TRIANGLE_STRIP, 2); + draw(gl, backSide, GL.GL_TRIANGLES, 3); + draw(gl, outwardFace, GL.GL_TRIANGLE_STRIP, 4); + draw(gl, insideRadiusCyl, GL.GL_TRIANGLE_STRIP, 5); + + pmvMatrix.glPopMatrix(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/LandscapeES2.java b/src/demos/com/jogamp/opengl/demos/es2/LandscapeES2.java new file mode 100644 index 000000000..0a42ae302 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/LandscapeES2.java @@ -0,0 +1,187 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.es2; + +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; +import java.nio.FloatBuffer; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLUniformData; + +/** + * LandscapeES2 + */ +public class LandscapeES2 implements GLEventListener { + private int swapInterval = 0; + private boolean verbose = true; + + static public final int TARGET_FPS = 120; + private long millisOffset; + private int frameCount; + private float frameRate; + private ShaderCode vertShader; + private ShaderCode fragShader; + private ShaderProgram shaderProg; + private ShaderState shaderState; + private float[] resolution; + private GLUniformData resolutionUni; + private GLUniformData timeUni; + private GLArrayDataServer vertices; + + private int fcount = 0, lastm = 0; + private final int fint = 1; + + public LandscapeES2(final int swapInterval) { + this.swapInterval = swapInterval; + } + + public LandscapeES2() { + this.swapInterval = 1; + } + + public void setVerbose(final boolean v) { verbose = v; } + + public void init(final GLAutoDrawable drawable) { + System.err.println(Thread.currentThread()+" LandscapeES2.init ..."); + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + if(verbose) { + System.err.println("LandscapeES2 init on "+Thread.currentThread()); + System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); + System.err.println("INIT GL IS: " + gl.getClass().getName()); + System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); + System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); + System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); + System.err.println("GL GLSL: "+gl.hasGLSL()+", has-compiler-func: "+gl.isFunctionAvailable("glCompileShader")+", version "+(gl.hasGLSL() ? gl.glGetString(GL2ES2.GL_SHADING_LANGUAGE_VERSION) : "none")+", "+gl.getContext().getGLSLVersionNumber()); + System.err.println("GL FBO: basic "+ gl.hasBasicFBOSupport()+", full "+gl.hasFullFBOSupport()); + System.err.println("GL Profile: "+gl.getGLProfile()); + System.err.println("GL Renderer Quirks:" + gl.getContext().getRendererQuirks().toString()); + System.err.println("GL:" + gl + ", " + gl.getContext().getGLVersion()); + } + + vertShader = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), "shader", "shader/bin", "landscape", true); + fragShader = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), "shader", "shader/bin", "landscape", true); + vertShader.defaultShaderCustomization(gl, true, true); + fragShader.defaultShaderCustomization(gl, true, true); + shaderProg = new ShaderProgram(); + shaderProg.add(gl, vertShader, System.err); + shaderProg.add(gl, fragShader, System.err); + + shaderState = new ShaderState(); + shaderState.attachShaderProgram(gl, shaderProg, true); + + resolution = new float[] { drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), 0}; + resolutionUni = new GLUniformData("iResolution", 3, FloatBuffer.wrap(resolution)); + shaderState.ownUniform(resolutionUni); + shaderState.uniform(gl, resolutionUni); + + timeUni = new GLUniformData("iGlobalTime", 0.0f); + shaderState.ownUniform(timeUni); + + vertices = GLArrayDataServer.createGLSL("inVertex", 2, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + vertices.putf(-1.0f); vertices.putf(-1.0f); + vertices.putf(+1.0f); vertices.putf(-1.0f); + vertices.putf(-1.0f); vertices.putf(+1.0f); + vertices.putf(+1.0f); vertices.putf(+1.0f); + vertices.seal(gl, true); + shaderState.ownAttribute(vertices, true); + shaderState.useProgram(gl, false); + + millisOffset = System.currentTimeMillis(); + + System.err.println(Thread.currentThread()+" LandscapeES2.init FIN"); + } + + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + System.err.println(Thread.currentThread()+" LandscapeES2.reshape "+x+"/"+y+" "+width+"x"+height+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(drawable.getHandle())); + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) + + shaderState.useProgram(gl, true); + + resolution[0] = drawable.getSurfaceWidth(); + resolution[1] = drawable.getSurfaceHeight(); + shaderState.uniform(gl, resolutionUni); + + shaderState.useProgram(gl, false); + } + + public void dispose(final GLAutoDrawable drawable) { + System.err.println(Thread.currentThread()+" LandscapeES2.dispose ... "); + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + shaderState.useProgram(gl, false); + shaderState.destroy(gl); + shaderState = null; + + System.err.println(Thread.currentThread()+" LandscapeES2.dispose FIN"); + } + + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + // Shader fills complete framebuffer regardless of DEPTH, no Clear required. + // gl.glClearColor(0.5f, 0.1f, 0.1f, 1); + // gl.glClear(GL.GL_COLOR_BUFFER_BIT); + + shaderState.useProgram(gl, true); + + timeUni.setData((System.currentTimeMillis() - millisOffset) / 1000.0f); + shaderState.uniform(gl, timeUni); + vertices.enableBuffer(gl, true); + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + vertices.enableBuffer(gl, false); + + shaderState.useProgram(gl, false); + + // Compute current framerate and printout. + frameCount++; + fcount += 1; + final int m = (int) (System.currentTimeMillis() - millisOffset); + if (m - lastm > 1000 * fint) { + frameRate = (float)(fcount) / fint; + fcount = 0; + lastm = m; + } + if (frameCount % TARGET_FPS == 0) { + System.out.println("FrameCount: " + frameCount + " - " + "FrameRate: " + frameRate); + } + } + + boolean confinedFixedCenter = false; + + public void setConfinedFixedCenter(final boolean v) { + confinedFixedCenter = v; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/PointsDemoES2.java b/src/demos/com/jogamp/opengl/demos/es2/PointsDemoES2.java new file mode 100644 index 000000000..0b4dac9b2 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/PointsDemoES2.java @@ -0,0 +1,208 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.es2; + +import java.nio.FloatBuffer; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES1; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GL2GL3; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLUniformData; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.opengl.demos.PointsDemo; + +public class PointsDemoES2 extends PointsDemo { + ShaderState st; + PMVMatrix pmvMatrix; + GLUniformData pmvMatrixUniform; + GLArrayDataServer vertices ; + GLArrayDataServer pointSizes ; + private int swapInterval = 0; + final int edge = 8; // 8*8 + /** vec4[2]: { (sz, smooth, attnMinSz, attnMaxSz), (attnCoeff(3), attnFadeTs) } */ + private static final String mgl_PointParams = "mgl_PointParams"; + + /** ( pointSize, pointSmooth, attn. pointMinSize, attn. pointMaxSize ) , ( attenuation coefficients 1f 0f 0f, attenuation fade theshold 1f ) */ + private final FloatBuffer pointParams = Buffers.newDirectFloatBuffer(new float[] { 1.0f, 0.0f, 0.0f, 4096.0f, 1.0f, 0.0f, 0.0f, 1.0f }); + + public PointsDemoES2(final int swapInterval) { + this.swapInterval = swapInterval; + } + + public PointsDemoES2() { + this.swapInterval = 1; + } + + public void setSmoothPoints(final boolean v) { + pointParams.put(1, v ? 1.0f : 0.0f); + } + + public void setPointParams(final float minSize, final float maxSize, final float distAttenConst, final float distAttenLinear, final float distAttenQuadratic, final float fadeThreshold) { + pointParams.put(2, minSize); + pointParams.put(3, maxSize); + pointParams.put(4+0, distAttenConst); + pointParams.put(4+1, distAttenLinear); + pointParams.put(4+2, distAttenQuadratic); + pointParams.put(4+3, fadeThreshold); + } + + public void init(final GLAutoDrawable glad) { + final GL2ES2 gl = glad.getGL().getGL2ES2(); + + System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); + System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); + System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); + System.err.println("GL GLSL: "+gl.hasGLSL()+", has-compiler-func: "+gl.isFunctionAvailable("glCompileShader")+", version "+(gl.hasGLSL() ? gl.glGetString(GL2ES2.GL_SHADING_LANGUAGE_VERSION) : "none")); + System.err.println("GL Profile: "+gl.getGLProfile()); + + st = new ShaderState(); + st.setVerbose(true); + final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), "shader", + "shader/bin", "PointsShader", true); + final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), "shader", + "shader/bin", "PointsShader", true); + vp0.defaultShaderCustomization(gl, true, true); + fp0.defaultShaderCustomization(gl, true, true); + final ShaderProgram sp0 = new ShaderProgram(); + sp0.add(gl, vp0, System.err); + sp0.add(gl, fp0, System.err); + st.attachShaderProgram(gl, sp0, true); + + // setup mgl_PMVMatrix + pmvMatrix = new PMVMatrix(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); // P, Mv + st.ownUniform(pmvMatrixUniform); + st.uniform(gl, pmvMatrixUniform); + + st.uniform(gl, new GLUniformData(mgl_PointParams, 4, pointParams)); + + final GLUniformData colorStaticUniform = new GLUniformData("mgl_ColorStatic", 4, Buffers.newDirectFloatBuffer(new float[] { 1.0f, 1.0f, 1.0f, 1.0f }) ); + st.uniform(gl, colorStaticUniform); + st.ownUniform(colorStaticUniform); + + // Allocate Vertex Array + vertices = GLArrayDataServer.createGLSL("mgl_Vertex", 3, GL.GL_FLOAT, false, edge*edge, GL.GL_STATIC_DRAW); + pointSizes = GLArrayDataServer.createGLSL("mgl_PointSize", 1, GL.GL_FLOAT, false, edge*edge, GL.GL_STATIC_DRAW); + for(int i=0; i<edge; i++) { + for(int j=0; j<edge; j++) { + final float x = -3+j*0.7f; + final float y = -3+i*0.7f; + final float p = (i*edge+j)*0.5f; + // System.err.println("["+j+"/"+i+"]: "+x+"/"+y+": "+p); + vertices.putf(x); vertices.putf(y); vertices.putf( 0); + pointSizes.putf(p); + } + } + vertices.seal(gl, true); + st.ownAttribute(vertices, true); + vertices.enableBuffer(gl, false); + pointSizes.seal(gl, true); + st.ownAttribute(pointSizes, true); + pointSizes.enableBuffer(gl, false); + + // OpenGL Render Settings + gl.glEnable(GL.GL_DEPTH_TEST); + st.useProgram(gl, false); + } + + public void display(final GLAutoDrawable glad) { + final GL2ES2 gl = glad.getGL().getGL2ES2(); + gl.glClearColor(0f, 0f, 0f, 0f); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + st.useProgram(gl, true); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, -10); + st.uniform(gl, pmvMatrixUniform); + + final GLUniformData ud = st.getUniform(mgl_PointParams); + if(null!=ud) { + // same data object + st.uniform(gl, ud); + } + + vertices.enableBuffer(gl, true); + pointSizes.enableBuffer(gl, true); + + if(gl.isGL2GL3()) { + gl.glEnable(GL2GL3.GL_VERTEX_PROGRAM_POINT_SIZE); + } + if(gl.isGL2ES1()) { + gl.glEnable(GL2ES1.GL_POINT_SPRITE); // otherwise no gl_PointCoord + } + gl.glEnable ( GL.GL_BLEND ); + gl.glBlendFunc ( GL.GL_SRC_ALPHA, GL.GL_ONE ); + + gl.glDrawArrays(GL.GL_POINTS, 0, edge*edge); + + if(gl.isGL2GL3()) { + gl.glDisable(GL2GL3.GL_VERTEX_PROGRAM_POINT_SIZE); + } + + pointSizes.enableBuffer(gl, false); + vertices.enableBuffer(gl, false); + st.useProgram(gl, false); + } + + public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { + // Thread.dumpStack(); + final GL2ES2 gl = glad.getGL().getGL2ES2(); + + gl.setSwapInterval(swapInterval); // in case switching the drawable (impl. may bound attribute there) + + st.useProgram(gl, true); + // Set location in front of camera + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.gluPerspective(45.0F, ( (float) width / (float) height ) / 1.0f, 1.0F, 100.0F); + //pmvMatrix.glOrthof(-4.0f, 4.0f, -4.0f, 4.0f, 1.0f, 100.0f); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + } + + public void dispose(final GLAutoDrawable glad) { + final GL2ES2 gl = glad.getGL().getGL2ES2(); + st.destroy(gl); + st = null; + pmvMatrix = null; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/RedSquareES2.java b/src/demos/com/jogamp/opengl/demos/es2/RedSquareES2.java new file mode 100644 index 000000000..a6e1f5cd9 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/RedSquareES2.java @@ -0,0 +1,274 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.es2; + +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.TileRendererBase; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLUniformData; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +public class RedSquareES2 implements GLEventListener, TileRendererBase.TileRendererListener { + private ShaderState st; + private PMVMatrix pmvMatrix; + private GLUniformData pmvMatrixUniform; + private GLArrayDataServer vertices ; + private GLArrayDataServer colors ; + private long t0; + private int swapInterval = 0; + private float aspect = 1.0f; + private boolean doRotate = true; + private boolean verbose = true; + private boolean clearBuffers = true; + private TileRendererBase tileRendererInUse = null; + private boolean doRotateBeforePrinting; + + public RedSquareES2(final int swapInterval) { + this.swapInterval = swapInterval; + } + + public RedSquareES2() { + this.swapInterval = 1; + } + + @Override + public void addTileRendererNotify(final TileRendererBase tr) { + tileRendererInUse = tr; + doRotateBeforePrinting = doRotate; + setDoRotation(false); + } + @Override + public void removeTileRendererNotify(final TileRendererBase tr) { + tileRendererInUse = null; + setDoRotation(doRotateBeforePrinting); + } + @Override + public void startTileRendering(final TileRendererBase tr) { + System.err.println("RedSquareES2.startTileRendering: "+tr); + } + @Override + public void endTileRendering(final TileRendererBase tr) { + System.err.println("RedSquareES2.endTileRendering: "+tr); + } + + public void setAspect(final float aspect) { this.aspect = aspect; } + public void setDoRotation(final boolean rotate) { this.doRotate = rotate; } + public void setClearBuffers(final boolean v) { clearBuffers = v; } + public void setVerbose(final boolean v) { verbose = v; } + + @Override + public void init(final GLAutoDrawable glad) { + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.init: tileRendererInUse "+tileRendererInUse); + } + final GL2ES2 gl = glad.getGL().getGL2ES2(); + + if(verbose) { + System.err.println("RedSquareES2 init on "+Thread.currentThread()); + System.err.println("Chosen GLCapabilities: " + glad.getChosenGLCapabilities()); + System.err.println("INIT GL IS: " + gl.getClass().getName()); + System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); + } + if( !gl.hasGLSL() ) { + System.err.println("No GLSL available, no rendering."); + return; + } + st = new ShaderState(); + st.setVerbose(true); + final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), "shader", + "shader/bin", "RedSquareShader", true); + final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), "shader", + "shader/bin", "RedSquareShader", true); + vp0.defaultShaderCustomization(gl, true, true); + fp0.defaultShaderCustomization(gl, true, true); + final ShaderProgram sp0 = new ShaderProgram(); + sp0.add(gl, vp0, System.err); + sp0.add(gl, fp0, System.err); + st.attachShaderProgram(gl, sp0, true); + + // setup mgl_PMVMatrix + pmvMatrix = new PMVMatrix(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); // P, Mv + st.ownUniform(pmvMatrixUniform); + st.uniform(gl, pmvMatrixUniform); + + // Allocate Vertex Array + vertices = GLArrayDataServer.createGLSL("mgl_Vertex", 3, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + vertices.putf(-2); vertices.putf( 2); vertices.putf( 0); + vertices.putf( 2); vertices.putf( 2); vertices.putf( 0); + vertices.putf(-2); vertices.putf(-2); vertices.putf( 0); + vertices.putf( 2); vertices.putf(-2); vertices.putf( 0); + vertices.seal(gl, true); + st.ownAttribute(vertices, true); + vertices.enableBuffer(gl, false); + + // Allocate Color Array + colors= GLArrayDataServer.createGLSL("mgl_Color", 4, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + colors.putf(1); colors.putf(0); colors.putf(0); colors.putf(1); + colors.putf(0); colors.putf(0); colors.putf(1); colors.putf(1); + colors.putf(1); colors.putf(0); colors.putf(0); colors.putf(1); + colors.putf(1); colors.putf(0); colors.putf(0); colors.putf(1); + colors.seal(gl, true); + st.ownAttribute(colors, true); + colors.enableBuffer(gl, false); + + // OpenGL Render Settings + gl.glEnable(GL.GL_DEPTH_TEST); + st.useProgram(gl, false); + + t0 = System.currentTimeMillis(); + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.init FIN"); + } + } + + @Override + public void display(final GLAutoDrawable glad) { + final long t1 = System.currentTimeMillis(); + + final GL2ES2 gl = glad.getGL().getGL2ES2(); + if( clearBuffers ) { + if( null != tileRendererInUse ) { + gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); + } else { + gl.glClearColor(0, 0, 0, 0); + } + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + } + if( !gl.hasGLSL() ) { + return; + } + st.useProgram(gl, true); + // One rotation every four seconds + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, -10); + if(doRotate) { + final float ang = ((t1 - t0) * 360.0F) / 4000.0F; + pmvMatrix.glRotatef(ang, 0, 0, 1); + pmvMatrix.glRotatef(ang, 0, 1, 0); + } + st.uniform(gl, pmvMatrixUniform); + + // Draw a square + vertices.enableBuffer(gl, true); + colors.enableBuffer(gl, true); + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + vertices.enableBuffer(gl, false); + colors.enableBuffer(gl, false); + st.useProgram(gl, false); + } + + @Override + public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { + final GL2ES2 gl = glad.getGL().getGL2ES2(); + gl.setSwapInterval(swapInterval); + reshapeImpl(gl, x, y, width, height, width, height); + } + + @Override + public void reshapeTile(final TileRendererBase tr, + final int tileX, final int tileY, final int tileWidth, final int tileHeight, + final int imageWidth, final int imageHeight) { + final GL2ES2 gl = tr.getAttachedDrawable().getGL().getGL2ES2(); + gl.setSwapInterval(0); + reshapeImpl(gl, tileX, tileY, tileWidth, tileHeight, imageWidth, imageHeight); + } + + void reshapeImpl(final GL2ES2 gl, final int tileX, final int tileY, final int tileWidth, final int tileHeight, final int imageWidth, final int imageHeight) { + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.reshape "+tileX+"/"+tileY+" "+tileWidth+"x"+tileHeight+" of "+imageWidth+"x"+imageHeight+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(gl.getContext().getGLDrawable().getHandle())+", tileRendererInUse "+tileRendererInUse); + } + // Thread.dumpStack(); + if( !gl.hasGLSL() ) { + return; + } + + st.useProgram(gl, true); + // Set location in front of camera + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + + // compute projection parameters 'normal' perspective + final float fovy=45f; + final float aspect2 = ( (float) imageWidth / (float) imageHeight ) / aspect; + final float zNear=1f; + final float zFar=100f; + + // compute projection parameters 'normal' frustum + final float top=(float)Math.tan(fovy*((float)Math.PI)/360.0f)*zNear; + final float bottom=-1.0f*top; + final float left=aspect2*bottom; + final float right=aspect2*top; + final float w = right - left; + final float h = top - bottom; + + // compute projection parameters 'tiled' + final float l = left + tileX * w / imageWidth; + final float r = l + tileWidth * w / imageWidth; + final float b = bottom + tileY * h / imageHeight; + final float t = b + tileHeight * h / imageHeight; + + pmvMatrix.glFrustumf(l, r, b, t, zNear, zFar); + //pmvMatrix.glOrthof(-4.0f, 4.0f, -4.0f, 4.0f, 1.0f, 100.0f); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + + System.err.println(Thread.currentThread()+" RedSquareES2.reshape FIN"); + } + + @Override + public void dispose(final GLAutoDrawable glad) { + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.dispose: tileRendererInUse "+tileRendererInUse); + } + final GL2ES2 gl = glad.getGL().getGL2ES2(); + if( !gl.hasGLSL() ) { + return; + } + st.destroy(gl); + st = null; + pmvMatrix = null; + if(verbose) { + System.err.println(Thread.currentThread()+" RedSquareES2.dispose FIN"); + } + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/PointsShader.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/PointsShader.fp new file mode 100644 index 000000000..82268958f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/PointsShader.fp @@ -0,0 +1,53 @@ + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; +#else + #define mgl_FragColor gl_FragColor +#endif + +#ifdef GL_ES + #define MEDIUMP mediump +#else + #define MEDIUMP +#endif + +// [0].rgba: 0, smooth, attnMinSz, attnMaxSz +// [1].rgba: attnCoeff(3), attnFadeTs +uniform MEDIUMP vec4 mgl_PointParams[2]; + +#define pointSmooth (mgl_PointParams[0].g) + +varying vec4 frontColor; + +// #define TEST 1 + +void main (void) +{ + mgl_FragColor = frontColor; + + if( pointSmooth > 0.5 ) { + // smooth (AA) + const float border = 0.90; // take/give 10% for AA + + // origin to 0/0, [-1/-1 .. 1/1] + vec2 pointPos = 2.0 * gl_PointCoord - 1.0 ; + float r = length( pointPos ); // one-circle sqrt(x * x + y * y), range: in-circle [0..1], out >1 + float r1 = 1.0 - ( step(border, r) * 10.0 * ( r - border ) ) ; // [0..1] + #ifndef TEST + if( r1 < 0.0 ) { + discard; + } + #endif + + #ifndef TEST + mgl_FragColor.a *= r1; + #else + mgl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + mgl_FragColor.r = r1 < 0.0 ? 1.0 : 0.0; + mgl_FragColor.g = r > 1.0 ? 1.0 : 0.0; + mgl_FragColor.b = r > border ? 1.0 : 0.0; + #endif + } +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/PointsShader.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/PointsShader.vp new file mode 100644 index 000000000..562874785 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/PointsShader.vp @@ -0,0 +1,53 @@ + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +#ifdef GL_ES + #define MEDIUMP mediump +#else + #define MEDIUMP +#endif + +uniform vec4 mgl_ColorStatic; +uniform mat4 mgl_PMVMatrix[4]; // P, Mv, Mvi and Mvit (transpose(inverse(ModelView)) == normalMatrix) + +// [0].rgba: 0, smooth, attnMinSz, attnMaxSz +// [1].rgba: attnCoeff(3), attnFadeTs +uniform MEDIUMP vec4 mgl_PointParams[2]; + +#define pointSmooth (mgl_PointParams[0].g) +#define pointSizeMin (mgl_PointParams[0].b) +#define pointSizeMax (mgl_PointParams[0].a) +#define pointDistanceConstantAtten (mgl_PointParams[1].r) +#define pointDistanceLinearAtten (mgl_PointParams[1].g) +#define pointDistanceQuadraticAtten (mgl_PointParams[1].b) +#define pointFadeThresholdSize (mgl_PointParams[1].a) + +attribute vec4 mgl_Vertex; +attribute float mgl_PointSize; + +varying vec4 frontColor; + +void main(void) +{ + frontColor = mgl_ColorStatic; + + vec4 eyeCoord = mgl_PMVMatrix[1] * mgl_Vertex; + gl_Position = mgl_PMVMatrix[0] * eyeCoord; + + float dist = distance(eyeCoord, vec4(0.0, 0.0, 0.0, 1.0)); + float atten = sqrt( 1.0 / ( pointDistanceConstantAtten + + ( pointDistanceLinearAtten + + pointDistanceQuadraticAtten * dist + ) * dist + ) + ); + float size = clamp(mgl_PointSize * atten, pointSizeMin, pointSizeMax); + gl_PointSize = max(size, pointFadeThresholdSize); + + float fade = min(size, pointFadeThresholdSize) / pointFadeThresholdSize; + frontColor.a *= fade * fade; +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.fp new file mode 100644 index 000000000..60b92401e --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.fp @@ -0,0 +1,16 @@ +// Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; +#else + #define mgl_FragColor gl_FragColor +#endif + +varying vec4 frontColor; + +void main (void) +{ + mgl_FragColor = frontColor; +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.java b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.java new file mode 100644 index 000000000..1f07ef1db --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.java @@ -0,0 +1,73 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.es2.shader; + +public class RedSquareShader { + public static final String VERTEX_SHADER_TEXT = + " #ifdef GL_ES\n" + + " precision mediump float;\n" + + " precision mediump int;\n" + + "#endif\n" + + "\n" + + "#if __VERSION__ >= 130\n" + + " #define attribute in\n" + + " #define varying out\n" + + "#endif\n"+ + "\n" + + "uniform mat4 mgl_PMVMatrix[2];\n" + + "attribute vec4 mgl_Vertex;\n" + + "attribute vec4 mgl_Color;\n" + + "varying vec4 frontColor;\n" + + "\n" + + "void main(void)\n" + + "{\n" + + " frontColor=mgl_Color;\n" + + " gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * mgl_Vertex;\n" + + "}\n" ; + + public static final String FRAGMENT_SHADER_TEXT = + " #ifdef GL_ES\n" + + " precision mediump float;\n" + + " precision mediump int;\n" + + "#endif\n" + + "\n" + + "#if __VERSION__ >= 130\n" + + " #define varying in\n" + + " out vec4 mgl_FragColor;\n" + + "#else\n" + + " #define mgl_FragColor gl_FragColor\n" + + "#endif\n" + + "\n" + + "varying vec4 frontColor;\n" + + "\n" + + "void main (void)\n" + + "{\n" + + " mgl_FragColor = frontColor;\n" + + "}\n" ; +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.vp new file mode 100644 index 000000000..9283dd7bd --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader.vp @@ -0,0 +1,18 @@ +// Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +uniform mat4 mgl_PMVMatrix[2]; +attribute vec4 mgl_Vertex; +attribute vec4 mgl_Color; +varying vec4 frontColor; + +void main(void) +{ + frontColor=mgl_Color; + gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * mgl_Vertex; +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader2.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader2.fp new file mode 100644 index 000000000..25a2df2d7 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/RedSquareShader2.fp @@ -0,0 +1,16 @@ +// Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; +#else + #define mgl_FragColor gl_FragColor +#endif + +varying vec4 frontColor; + +void main (void) +{ + mgl_FragColor = vec4(0.0, frontColor.g, frontColor.b, 1.0); +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/default.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/default.vp new file mode 100644 index 000000000..2037086f1 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/default.vp @@ -0,0 +1,24 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +#ifdef GL_ES + #define MEDIUMP mediump + #define HIGHP highp + #define LOWP lowp +#else + #define MEDIUMP + #define HIGHP + #define LOWP +#endif + +uniform HIGHP mat4 gcu_PMVMatrix[3]; // P, Mv, and Mvi +attribute HIGHP vec4 gca_Vertices; + +void main(void) +{ + gl_Position = gcu_PMVMatrix[0] * gcu_PMVMatrix[1] * gca_Vertices; +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/elektronenmultiplizierer_development.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/elektronenmultiplizierer_development.fp new file mode 100644 index 000000000..60f054b46 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/elektronenmultiplizierer_development.fp @@ -0,0 +1,389 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Details see: src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/ElektronenMultiplizierer.java + */ + +/** + * http://www.youtube.com/user/DemoscenePassivist + * author: Dominik Stroehlein (DemoscenePassivist) + **/ + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; + #define texture2D texture +#else + #define mgl_FragColor gl_FragColor +#endif + +#ifdef GL_ES + precision mediump float; + precision mediump sampler2D; + precision mediump int; +#endif + +uniform int en; //effectnumber +uniform float et; //effecttime +uniform sampler2D fb; //fbotexture +uniform float br; //brightness +uniform float tm; //time +uniform vec2 resolution;//screen resolution/fbo resolution + +float camerafocallengthdode; +vec3 camerapositiondode; +vec2 sizedode; +vec3 backgroundcolor = vec3(0,0.6,0.46); +mat3 worldrotationxyz; +mat3 fractalplanerotationx; +mat3 fractalplanerotationy; +mat3 camerarotationdode; +vec2 oglFragCoord; + +//fractal formula used for sphreretracing/distance-estimation +//dodecahedron serpinski (knighty) +//http://www.fractalforums.com/index.php?topic=3158.msg16982#msg16982 +//normal vectors for the dodecahedra-siepinski folding planes are: +//(phi^2, 1, -phi), (-phi, phi^2, 1), (1, -phi, phi^2), (-phi*(1+phi), phi^2-1, 1+phi), (1+phi, -phi*(1+phi), phi^2-1) and x=0, y=0, z=0 planes. + +//const pre-calc +const float phi = 1.618; +// Using math functions in initializers fails on MacOSX +// const float _IKVNORM_ = 1.0 / sqrt(pow(phi * (1.0 + phi), 2.0) + pow(phi * phi - 1.0, 2.0) + pow(1.0 + phi, 2.0)); +const float _IKVNORM_ = 0.190989113930771; +const float _C1_ = phi * (1.0 + phi) * _IKVNORM_; +const float _C2_ = (phi * phi - 1.0) * _IKVNORM_; +const float _1C_ = (1.0 + phi) * _IKVNORM_; +const vec3 phi3 = vec3(0.5, 0.5 / phi, 0.5 * phi); +const vec3 c3 = vec3(_C1_, _C2_, _1C_); + +vec3 distancefunction(vec3 w) { +//!P center scale offset ... + vec3 offset; + if (en==6) { + offset = vec3(0.61,0.1*et,0.99); + } else { + offset = vec3(0.61,0.0,0.99); + } +//!P center scale \0/ this is awesome for fadeins !!! + float scale = 2.; + w *= worldrotationxyz; + float d, t; + float md = 1000.0, cd = 0.0; +//!P iterations (8) ... 2x see below + for (int i = 0; i < 8; i++) { + w *= fractalplanerotationx; + w = abs(w); + t = w.x * phi3.z + w.y * phi3.y - w.z * phi3.x; + if (t < 0.0) { w += vec3(-2.0, -2.0, 2.0) * t * phi3.zyx; } + t = -w.x * phi3.x + w.y * phi3.z + w.z * phi3.y; + if (t < 0.0) { w += vec3(2.0, -2.0, -2.0) * t * phi3.xzy; } + t = w.x * phi3.y - w.y * phi3.x + w.z * phi3.z; + if (t < 0.0) { w += vec3(-2.0, 2.0, -2.0) * t * phi3.yxz; } + t = -w.x * c3.x + w.y * c3.y + w.z * c3.z; + if (t < 0.0) { w += vec3(2.0, -2.0, -2.0) * t * c3.xyz; } + t = w.x * c3.z - w.y * c3.x + w.z * c3.y; + if (t < 0.0) { w += vec3(-2.0, 2.0, -2.0) * t * c3.zxy; } + w *= fractalplanerotationy; + w *= scale; + w -= offset * (scale - 1.0); + //accumulate minimum orbit for coloring ... + d = dot(w, w); +//!P iterations for coloring (4) + if (i < 4) { + md = min(md, d); + cd = d; + } + } +//!P max iterations (8) + return vec3((length(w) - 2.0) * pow(scale, -8.0), md, cd); +} + +//calculate ray direction fragment coordinates +vec3 raydirection(vec2 pixel) { + vec2 p = (0.5*sizedode-pixel)/vec2(sizedode.x,-sizedode.y); +//!P aspect ratio of dode + p.x *= sizedode.x/sizedode.y; +//!P vec3 w = vec3(0, 0, 1), vec3 v = vec3(0, 1, 0), vec3 u = vec3(1, 0, 0); + vec3 d = (p.x * vec3(1, 0, 0)+p.y * vec3(0, 1, 0)-camerafocallengthdode * vec3(0, 0, 1)); + return normalize(camerarotationdode * d); +} + +//iq's fake ambient occlusion +//http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf +//http://www.iquilezles.org/www/articles/ao/ao.htm +float ambientocclusion(vec3 p, vec3 n, float eps) { + float o = 1.0; +//!P ao spread (10.6) +// spreads the output color intensity + eps *= 10.6; +//!P ao intensity (0.16) + float k = 0.16 / eps; + //add little start distance to the surface + float d = 2.0 * eps; +//!P ao iterations (5) ... + for (int i = 0; i < 5; ++i) { + o -= (d - distancefunction(p + n * d).x) * k; + d += eps; + //fade ao when distance to the surface increases + k *= 0.5; + } + return clamp(o, 0.0, 1.0); +} + +vec4 render(vec2 pixel) { + vec3 ray_direction = raydirection(pixel); +//!P minimum ray length (6e-5) + float ray_length = 6e-5; + vec3 ray = camerapositiondode + ray_length * ray_direction; +//!P minimum epsilon (6e-7) ... + float eps = 6e-7; + vec3 dist; + vec3 normal = vec3(0); + int steps = 0; + bool hit = false; + float minmarch = 0.0; +//!P maxmarch = 10000.0; + float maxmarch = 25.0; +//!P field of view scale = (1.0 / sqrt(1.0 + camerafocallengthdode * camerafocallengthdode)) +//!P detail of surface approximation = 1.22 +//!P pixelscale = (1.0 / min(sizedode.x, sizedode.y)) + float epsfactor = 2.0 * (1.0 / sqrt(1.0 + camerafocallengthdode * camerafocallengthdode)) * (1.0 / min(sizedode.x, sizedode.y)) * 1.22; + ray_length = minmarch; + ray = camerapositiondode + ray_length * ray_direction; +//!P max number of raymarching steps (90); + for (int i = 0; i < 90; i++) { + steps = i; + dist = distancefunction(ray); +//!P X-) questionable surface smoothing (0.53) + dist.x *= 0.53; + //backtrack previous step and check if it was only a "fussel" + if (hit && dist.x < eps || ray_length > maxmarch || ray_length < minmarch) { + steps--; + break; + } + hit = false; + ray_length += dist.x; + ray = camerapositiondode + ray_length * ray_direction; + eps = ray_length * epsfactor; + if (dist.x < eps || ray_length < minmarch) { + hit = true; + } + } + //\0/ there is a hit! + vec4 color = vec4(backgroundcolor,0.5); + if (hit) { + float aof = 1.0; + if (steps < 1 || ray_length < minmarch) { + normal = normalize(ray); + } else { + //gradient in x,y and z direction for intersection point + //!P minimum normal (1.5e-7) + float e = max(eps * 0.5, 1.5e-7); + normal = normalize(vec3( + distancefunction(ray + vec3(e, 0, 0)).x - distancefunction(ray - vec3(e, 0, 0)).x, + distancefunction(ray + vec3(0, e, 0)).x - distancefunction(ray - vec3(0, e, 0)).x, + distancefunction(ray + vec3(0, 0, e)).x - distancefunction(ray - vec3(0, 0, e)).x + )); + aof = ambientocclusion(ray, normal, eps); + } +//!P hardcoded light position vec3(-50,150,-25) + float diffuse = max(dot(normal, normalize(vec3(-50,150,-25) - ray)), 0.0); +//blinn/phong specular stuff ... +//!P specular exponent (4) +//!P specularity (0.8) +//!P diffuse color vec3(0.45) 2x in one line ... +//!P ambient color vec2 ambientcolor = vec2(0.5,0.3) + color.rgb = (mix(vec3(0.5), backgroundcolor, 0.3) * vec3(0.45) + vec3(0.45) * diffuse + pow(diffuse, 4.) * 0.8)*aof; + color.a = 1.0; + } +//!P fog factor = 0.01 + color.rgb = mix(backgroundcolor, color.rgb, exp(-pow(ray_length, 2.0) * 0.01)); + return color; +} + +mat3 xmatrixrotation(float angle) { + return mat3( + vec3(1.0, 0.0, 0.0), + vec3(0.0, cos(angle), sin(angle)), + vec3(0.0, -sin(angle), cos(angle)) + ); +} + +mat3 ymatrixrotation(float angle) { + return mat3( + vec3(cos(angle), 0.0, -sin(angle)), + vec3( 0.0, 1.0, 0.0), + vec3(sin(angle), 0.0, cos(angle)) + ); +} + +vec4 raymarch_orbittrap_image(vec2 fragcoord) { + //do the matrix calculations by hand X-) + //as mat4 constructor and arithmetic assignments are + //currently broken (2010-09-21) on ATI cards i found + //a workaround using vec4 constructors wich works on + //both NVIDIA+ATI --- MAGIC. DO NOT TOUCH! -=#:-) + mat3 identitymatrix = mat3(1,0,0,0,1,0,0,0,1); + float sin_phi = sin(0.1*tm); + float cos_phi = cos(0.1*tm); + mat3 zrot = mat3( + vec3( cos_phi, sin_phi, 0.0), + vec3(-sin_phi, cos_phi, 0.0), + vec3( 0.0, 0.0, 1.0) + ); + vec2 position; + float fractalplanex_var; + float fractalplaney_var; + position = oglFragCoord.xy; + camerafocallengthdode = 1.0; + if (en==2) { + sizedode = vec2(384,384); + camerapositiondode = vec3(0.0,0.0,-2.7); + } else if (en==3) { + camerapositiondode = vec3(0.0,0.0,-2.7*(10.-et)); + } else if (en==4) { + camerapositiondode = vec3(0.0,0.0,-2.7*(10.-9.3)); + fractalplanex_var = et; + fractalplaney_var = 0.0; + } else if (en==5) { + //inside effect + camerapositiondode = vec3(0.0,0.0,-0.05); + fractalplanex_var = 1.06; + fractalplaney_var = -1.0-et; + } else if (en==6) { + camerapositiondode = vec3(0.0,0.0,-2.7*(10.-9.5)); + fractalplanex_var = et; + fractalplaney_var = sin(et*0.03)-1.0; + } else if (en==7) { + sizedode = vec2(384,384); + fractalplanex_var = et; + fractalplaney_var = sin(et*0.93)-1.0; + camerapositiondode = vec3(0.0,0.0,-2.7); + } + worldrotationxyz = xmatrixrotation(0.1*tm)*ymatrixrotation(0.1*tm)*zrot*identitymatrix; + fractalplanerotationx = xmatrixrotation(fractalplanex_var)*identitymatrix; + fractalplanerotationy = xmatrixrotation(fractalplaney_var)*identitymatrix; + camerarotationdode = ymatrixrotation(3.14)*identitymatrix; + vec4 color = render(position); + return color; +} + +//---------------------------------------------------------------------------------------------------------- + +vec4 orbitmapping(vec4 c, vec2 w) { +//!P orbit trap scale and offset + vec2 orbittrapoffset = vec2(0.24,-0.24); + float orbittrapscale; + if (en==0) { + //julia set ... + orbittrapscale = 0.625; + } else { + //mandlebrot ... + orbittrapscale = 0.325; + } + vec2 sp = 0.5 + (w / orbittrapscale - orbittrapoffset); + vec4 s = texture2D(fb, sp); + if (s.a > 0.0) { + c = mix(c, s, s.a); + } + return c; +} + +vec4 orbittrap(vec2 z) { + float powerjulia = 2.; + vec3 colorjulia = vec3(1.0); + vec4 color = vec4(colorjulia, 0.0); + float n = 0.0; + vec2 c; + if (en==0) { + //julia mode ... +//!P use offset-julia from 2.25 to 2.5 + c = vec2(sin(et+2.07)*0.05,cos(et+2.07)); + } else { + //mandelbrot mode ... + c = z; + } +//!P max iterations for julia (128) ... 2x parameter - see below! + for (int i = 0; i<128; i++) { + n += 1.0; + float r = pow(length(z), powerjulia); + float a = powerjulia * atan(z.y, z.x); + z = vec2(cos(a) * r, sin(a) * r) +c; +//!P min iterations for julia (1.0) ... + if (n >= 1.0) { + color = orbitmapping(color, z); +//!P orbit trap alpha precision (0.6) ... + if (color.a >= 0.6) { + break; + } + } + } +//!P max iterations for julia (128.0) ... + float blend = clamp(1.0 - (n / 128.0) * 2.0, 0.0, 1.0); + color.rgb = mix(colorjulia, color.rgb, blend); + return color; +} + +void main() { + vec2 sizejulia = resolution; + sizedode = sizejulia; + oglFragCoord = gl_FragCoord.xy; + vec4 color; + if (en==0 || en==1) { + //render 2d julia/mandelbrot +//!P camera position for julia ... + vec3 camerapositionjulia; + if (en==0) { + //julia + camerapositionjulia = vec3(-0.2,-0.515,0.095347+(et*1.75)); + } else { + //mandelbrot + camerapositionjulia = vec3(0.325895,0.049551,0.0005+et); + } +//!P absolute output size of julia orbit trap ... + vec2 z = ((oglFragCoord.xy - (sizejulia * 0.5)) / sizejulia) * + vec2(sizejulia.x/sizejulia.y, 1.0) * //aspect ratio + camerapositionjulia.z + + camerapositionjulia.xy; + color = orbittrap(z); + } else { + color = raymarch_orbittrap_image(oglFragCoord.xy); + } + if (en==2 || en==7) { + mgl_FragColor = color; + } else { + //do normal rendering ... + //analog-tv distortion ... + vec2 position = oglFragCoord.xy / sizejulia.xy; + position.y *=-1.0; + vec3 color_tv = color.rgb; + //contrast + color_tv = clamp(color_tv*0.5+0.5*color_tv*color_tv*1.2,0.0,1.0); + //circular vignette fade + color_tv *= 0.5 + 0.5*16.0*position.x*position.y*(1.0-position.x)*(-1.0-position.y); + //color shift + if (en==0 || en==3) { + color_tv *= vec3(0.8,1.0,0.7); //green + } + if (en==1 || en==4) { + color_tv *= vec3(0.95,0.85,1.0); //blue + } + if (en==5) { + color_tv *= vec3(1.0,0.7,1.0); //purple + } + + if (en==6) { + color_tv *= vec3(0.7,1.0,1.0); //cyan + } + if (en==2) { + color_tv *= vec3(1.0,1.0,0.7); //yellow + } + //tvlines effect + color_tv *= 0.9+0.1*sin(1.5*tm+position.y*1000.0); + //tv flicker effect + color_tv *= 0.97+0.13*sin(2.5*tm); + color_tv *= br; + mgl_FragColor = vec4(color_tv,1.0); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/elektronenmultiplizierer_port.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/elektronenmultiplizierer_port.fp new file mode 100644 index 000000000..77c34f74f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/elektronenmultiplizierer_port.fp @@ -0,0 +1,242 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Details see: src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/ElektronenMultiplizierer.java + */ + +/** + * http://www.youtube.com/user/DemoscenePassivist + * author: Dominik Stroehlein (DemoscenePassivist) + **/ + +//When I wrote this, only God and I understood what I was doing ... +// ... now only God knows! X-) + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; + #define texture2D texture +#else + #define mgl_FragColor gl_FragColor +#endif + +uniform int en; +uniform float et; +uniform sampler2D fb; +uniform float br,tm; +uniform vec2 resolution; +float v; +vec3 n; +vec2 e; +vec3 f=vec3(0,.6,.46); +mat3 i,m,r,y; +vec2 c; +const float x=1.618,t=1./sqrt(pow(x*(1.+x),2.)+pow(x*x-1.,2.)+pow(1.+x,2.)),z=x*(1.+x)*t,s=(x*x-1.)*t,w=(1.+x)*t; +const vec3 a=vec3(.5,.5/x,.5*x),p=vec3(z,s,w); +vec3 l(vec3 v) { + vec3 n; + if(en==6) + n=vec3(.61,.1*et,.99); + else + n=vec3(.61,0.,.99); + float e=2.; + v*=i; + float f,x,c=1000.,y=0.; + for(int z=0;z<8;z++) { + v*=m; + v=abs(v); + x=v.x*a.z+v.y*a.y-v.z*a.x; + if(x<0.) + v+=vec3(-2.,-2.,2.)*x*a.zyx; + x=-v.x*a.x+v.y*a.z+v.z*a.y; + if(x<0.) + v+=vec3(2.,-2.,-2.)*x*a.xzy; + x=v.x*a.y-v.y*a.x+v.z*a.z; + if(x<0.) + v+=vec3(-2.,2.,-2.)*x*a.yxz; + x=-v.x*p.x+v.y*p.y+v.z*p.z; + if(x<0.) + v+=vec3(2.,-2.,-2.)*x*p.xyz; + x=v.x*p.z-v.y*p.x+v.z*p.y; + if(x<0.) + v+=vec3(-2.,2.,-2.)*x*p.zxy; + v*=r; + v*=e; + v-=n*(e-1.); + f=dot(v,v); + if(z<4) + c=min(c,f),y=f; + } + return vec3((length(v)-2.)*pow(e,-8.),c,y); +} +vec3 b(vec2 x) { + vec2 n=(.5*e-x)/vec2(e.x,-e.y); + n.x*=e.x/e.y; + vec3 a=n.x*vec3(1,0,0)+n.y*vec3(0,1,0)-v*vec3(0,0,1); + return normalize(y*a); +} +float b(vec3 e,vec3 x,float v) { + float n=1.; + v*=10.6; + float t=.16/v,y=2.*v; + for(int i=0;i<5;++i) + n-=(y-l(e+x*y).x)*t,y+=v,t*=.5; + return clamp(n,0.,1.); +} +vec4 h(vec2 x) { + vec3 a=b(x); + float i=6e-05; + vec3 y=n+i*a; + float c=6e-07; + vec3 m,z=vec3(0); + int r=0; + bool t=false; + float s=0.,w=25.,p=2.*(1./sqrt(1.+v*v))*(1./min(e.x,e.y))*1.22; + i=s; + y=n+i*a; + for(int g=0;g<90;g++) { + r=g; + m=l(y); + m.x*=.53; + if(t&&m.x<c||i>w||i<s) { + r--; + break; + } + t=false; + i+=m.x; + y=n+i*a; + c=i*p; + if(m.x<c||i<s) + t=true; + } + vec4 g=vec4(f,.5); + if(t) { + float d=1.; + if(r<1||i<s) + z=normalize(y); + else { + float h=max(c*.5,1.5e-07); + z=normalize(vec3(l(y+vec3(h,0,0)).x-l(y-vec3(h,0,0)).x,l(y+vec3(0,h,0)).x-l(y-vec3(0,h,0)).x,l(y+vec3(0,0,h)).x-l(y-vec3(0,0,h)).x)); + d=b(y,z,c); + } + float h=max(dot(z,normalize(vec3(-66,162,-30)-y)),0.); + g.xyz=(mix(vec3(.5),f,.3)*vec3(.45)+vec3(.45)*h+pow(h,4.)*.8)*d; + g.w=1.; + } + g.xyz=mix(f,g.xyz,exp(-pow(i,2.)*.01)); + return g; +} +mat3 g(float e) { + return mat3(vec3(1.,0.,0.),vec3(0.,cos(e),sin(e)),vec3(0.,-sin(e),cos(e))); +} +mat3 d(float e) { + return mat3(vec3(cos(e),0.,-sin(e)),vec3(0.,1.,0.),vec3(sin(e),0.,cos(e))); +} +vec4 D(vec2 x) { + mat3 a=mat3(1,0,0,0,1,0,0,0,1); + float t=sin(.1*tm),z=cos(.1*tm); + mat3 p=mat3(vec3(z,t,0.),vec3(-t,z,0.),vec3(0.,0.,1.)); + vec2 f; + float s,w; + f=c.xy; + v=1.; + if(en==2) + e=vec2(384,384),n=vec3(0.,0.,-2.7); + if(en==3) + n=vec3(0.,0.,-2.7*(10.-et)); + if(en==4) + n=vec3(0.,0.,-1.89),s=et,w=0.; + if(en==5) + n=vec3(0.,0.,-.05),s=1.06,w=-1.-et; + if(en==6) + n=vec3(0.,0.,-1.35),s=et,w=sin(et*.03)-1.; + if(en==7) + e=vec2(384,384),s=et,w=sin(et*.93)-1.,n=vec3(0.,0.,-2.7); + i=g(.1*tm)*d(.1*tm)*p*a; + m=g(s)*a; + r=g(w)*a; + y=d(3.14)*a; + vec4 l=h(f); + if(l.w<.00392) { + discard; + } + return l; +} +vec4 D(vec4 e,vec2 x) { + vec2 n=vec2(.24,-.24); + float y; + if(en==0) + y=.625; + else + y=.325; + vec2 v=.5+(x/y-n); + vec4 c=texture2D(fb,v); + if(c.w>0.) + e=mix(e,c,c.w); + return e; +} +vec4 o(vec2 v) { + float n=2.; + vec3 e=vec3(1.); + vec4 i=vec4(e,0.); + float y=0.; + vec2 x; + if(en==0) + x=vec2(sin(et+2.07)*.05,cos(et+2.07)); + else + x=v; + for(int f=0;f<128;f++) { + y+=1.; + float t=pow(length(v),n),c=n*atan(v.y,v.x); + v=vec2(cos(c)*t,sin(c)*t)+x; + if(y>=1.) { + i=D(i,v); + if(i.w>=.6) { + break; + } + } + } + float c=clamp(1.-y/128.*2.,0.,1.); + i.xyz=mix(e,i.xyz,c); + return i; +} +void main() { + //vec2 v=vec2(640.0,480.0); + vec2 v =resolution; + e=v; + c=gl_FragCoord.xy; + vec4 n; + if(en==0||en==1) { + vec3 a; + if(en==0) + a=vec3(-.2,-.515,.095347+et*1.75); + else + a=vec3(.325895,.049551,.0005+et); + vec2 x=(c.xy-v*.5)/v*vec2(v.x/v.y,1.)*a.z+a.xy; + n=o(x); + } else + n=D(c.xy); + if(en==2||en==7) + mgl_FragColor=n; + else { + vec2 i=c.xy/v.xy; + i.y*=-1.; + vec3 x=n.xyz; + x=clamp(x*.5+.5*x*x*1.2,0.,1.); + x*=.5+8.*i.x*i.y*(1.-i.x)*(-1.-i.y); + if(en==0||en==3) + x*=vec3(.8,1.,.7); + if(en==1||en==4) + x*=vec3(.95,.85,1.); + if(en==5) + x*=vec3(1.,.7,1.); + if(en==6) + x*=vec3(.7,1.,1.); + if(en==2) + x*=vec3(1.,1.,.7); + x*=.9+.1*sin(1.5*tm+i.y*1000.); + x*=.97+.13*sin(2.5*tm); + x*=br; + mgl_FragColor=vec4(x,1.); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-1.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-1.fp new file mode 100644 index 000000000..563e0a4b0 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-1.fp @@ -0,0 +1,16 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragData[2]; +#else + #define mgl_FragData gl_FragData +#endif + +varying vec4 frontColor; + +void main (void) +{ + mgl_FragData[0] = vec4( frontColor.r, 0.0, 0.0, 1.0 ); + mgl_FragData[1] = vec4( 0.0, frontColor.g, 0.0, 1.0 ); +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-1.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-1.vp new file mode 100644 index 000000000..4cab59c64 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-1.vp @@ -0,0 +1,19 @@ +// Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +uniform mat4 gcu_PMVMatrix[2]; // P, Mv, and Mvi +attribute vec4 gca_Vertices; +attribute vec4 gca_Colors; + +varying vec4 frontColor; + +void main(void) +{ + frontColor = gca_Colors; + gl_Position = gcu_PMVMatrix[0] * gcu_PMVMatrix[1] * gca_Vertices; +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-2.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-2.fp new file mode 100644 index 000000000..510096d66 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-2.fp @@ -0,0 +1,22 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragData[2]; + #define texture2D texture +#else + #define mgl_FragData gl_FragData +#endif + +uniform sampler2D gcs_TexUnit0; +uniform sampler2D gcs_TexUnit1; + +varying vec4 frontColor; +varying vec2 texCoord; + +void main (void) +{ + vec2 rg = texture2D(gcs_TexUnit0, texCoord).rg + texture2D(gcs_TexUnit1, texCoord).rg; + float b = frontColor.b - length(rg); + mgl_FragData[0] = vec4( rg, b, 1.0 ); +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-2.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-2.vp new file mode 100644 index 000000000..89290b05a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/fbo-mrt-2.vp @@ -0,0 +1,21 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +uniform mat4 gcu_PMVMatrix[2]; // P, Mv, and Mvi +attribute vec4 gca_Vertices; +attribute vec4 gca_Colors; +attribute vec2 gca_TexCoords; + +varying vec4 frontColor; +varying vec2 texCoord; + +void main(void) +{ + frontColor = gca_Colors; + texCoord = gca_TexCoords; + gl_Position = gcu_PMVMatrix[0] * gcu_PMVMatrix[1] * gca_Vertices; +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/gears.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/gears.fp new file mode 100644 index 000000000..14328dc1e --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/gears.fp @@ -0,0 +1,48 @@ +// Copyright (C) 2011 JogAmp Community. All rights reserved. +// Details see GearsES2.java + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; +#else + #define mgl_FragColor gl_FragColor +#endif + +uniform vec4 color; + +varying vec3 normal; +varying vec4 position; +varying vec3 lightDir; +varying float attenuation; +varying vec3 cameraDir; + +// Defining The Material Colors +const vec4 matAmbient = vec4(0.2, 0.2, 0.2, 1.0); // orig default +const vec4 matDiffuse = vec4(0.8, 0.8, 0.8, 1.0); // orig default +// const vec4 matSpecular = vec4(0.0, 0.0, 0.0, 1.0); // orig default +const vec4 matSpecular = vec4(0.8, 0.8, 0.8, 1.0); +// const float matShininess = 0.0; // orig default +const float matShininess = 0.5; + +void main() +{ + vec4 ambient = color * matAmbient; + vec4 specular = vec4(0.0); + + float lambertTerm = dot(normal, lightDir); + vec4 diffuse = color * lambertTerm * attenuation * matDiffuse; + if (lambertTerm > 0.0) { + float NdotHV; + /* + vec3 halfDir = normalize (lightDir + cameraDir); + NdotHV = max(0.0, dot(normal, halfDir)); + */ + vec3 E = normalize(-position.xyz); + vec3 R = reflect(-lightDir, normal); + NdotHV = max(0.0, dot(R, E)); + + specular += color * pow(NdotHV, matShininess) * attenuation * matSpecular; + } + + mgl_FragColor = ambient + diffuse + specular ; +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/gears.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/gears.vp new file mode 100644 index 000000000..24f4f9c52 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/gears.vp @@ -0,0 +1,45 @@ +// Copyright (C) 2011 JogAmp Community. All rights reserved. +// Details see GearsES2.java + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +uniform mat4 pmvMatrix[4]; // P, Mv, Mvi and Mvit +uniform vec3 lightPos; + +attribute vec4 vertices; +attribute vec4 normals; + +varying vec3 normal; +varying vec4 position; +varying vec3 lightDir; +varying float attenuation; +varying vec3 cameraDir; + +const float constantAttenuation = 0.5; // 1.0; +const float linearAttenuation = 0.001; // 0.0; +const float quadraticAttenuation= 0.0002; // 0.0; + +void main(void) +{ + // Transforming The Vertex Position To ModelView-Space + position = pmvMatrix[1] * vertices; // vertex eye position + + // incl. projection + gl_Position = pmvMatrix[0] * position; + + // Transforming The Normal To ModelView-Space + normal = normalize((pmvMatrix[3] * normals).xyz); + + // Calculating The Vector From The Vertex Position To The Light Position + lightDir = lightPos - position.xyz; + float d = length(lightDir); + attenuation = 1.0 / ( + constantAttenuation + + linearAttenuation * d + + quadraticAttenuation * d * d ); + lightDir = normalize(lightDir); + cameraDir = normalize((pmvMatrix[2] * vec4(0,0,0,1.0)).xyz - vertices.xyz); +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/landscape.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/landscape.fp new file mode 100644 index 000000000..b19c057d3 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/landscape.fp @@ -0,0 +1,339 @@ +// Elevated shader +// https://www.shadertoy.com/view/MdX3Rr by inigo quilez + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; +#else + #define mgl_FragColor gl_FragColor +#endif + +uniform vec3 iResolution; +uniform float iGlobalTime; + +// Created by inigo quilez - iq/2013 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + +//stereo thanks to Croqueteer +//#define STEREO + +mat3 m = mat3( 0.00, 0.80, 0.60, + -0.80, 0.36, -0.48, + -0.60, -0.48, 0.64 ); + +float hash( float n ) +{ + return fract(sin(n)*43758.5453123); +} + + +float noise( in vec3 x ) +{ + vec3 p = floor(x); + vec3 f = fract(x); + + f = f*f*(3.0-2.0*f); + + float n = p.x + p.y*57.0 + 113.0*p.z; + + float res = mix(mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x), + mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y), + mix(mix( hash(n+113.0), hash(n+114.0),f.x), + mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z); + return res; +} + + + + +vec3 noised( in vec2 x ) +{ + vec2 p = floor(x); + vec2 f = fract(x); + + vec2 u = f*f*(3.0-2.0*f); + + float n = p.x + p.y*57.0; + + float a = hash(n+ 0.0); + float b = hash(n+ 1.0); + float c = hash(n+ 57.0); + float d = hash(n+ 58.0); + return vec3(a+(b-a)*u.x+(c-a)*u.y+(a-b-c+d)*u.x*u.y, + 30.0*f*f*(f*(f-2.0)+1.0)*(vec2(b-a,c-a)+(a-b-c+d)*u.yx)); + +} + +float noise( in vec2 x ) +{ + vec2 p = floor(x); + vec2 f = fract(x); + + f = f*f*(3.0-2.0*f); + + float n = p.x + p.y*57.0; + + float res = mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x), + mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y); + + return res; +} + +float fbm( vec3 p ) +{ + float f = 0.0; + + f += 0.5000*noise( p ); p = m*p*2.02; + f += 0.2500*noise( p ); p = m*p*2.03; + f += 0.1250*noise( p ); p = m*p*2.01; + f += 0.0625*noise( p ); + + return f/0.9375; +} + +mat2 m2 = mat2(1.6,-1.2,1.2,1.6); + +float fbm( vec2 p ) +{ + float f = 0.0; + + f += 0.5000*noise( p ); p = m2*p*2.02; + f += 0.2500*noise( p ); p = m2*p*2.03; + f += 0.1250*noise( p ); p = m2*p*2.01; + f += 0.0625*noise( p ); + + return f/0.9375; +} + +float terrain( in vec2 x ) +{ + vec2 p = x*0.003; + float a = 0.0; + float b = 1.0; + vec2 d = vec2(0.0); + for(int i=0;i<5; i++) + { + vec3 n = noised(p); + d += n.yz; + a += b*n.x/(1.0+dot(d,d)); + b *= 0.5; + p=mat2(1.6,-1.2,1.2,1.6)*p; + } + + return 140.0*a; +} + +float terrain2( in vec2 x ) +{ + vec2 p = x*0.003; + float a = 0.0; + float b = 1.0; + vec2 d = vec2(0.0); + for(int i=0;i<14; i++) + { + vec3 n = noised(p); + d += n.yz; + a += b*n.x/(1.0+dot(d,d)); + b *= 0.5; + p=m2*p; + } + + return 140.0*a; +} + + +float map( in vec3 p ) +{ + float h = terrain(p.xz); + + float ss = 0.03; + float hh = h*ss; + float fh = fract(hh); + float ih = floor(hh); + fh = mix( sqrt(fh), fh, smoothstep(50.0,140.0,h) ); + h = (ih+fh)/ss; + + return p.y - h; +} + +float map2( in vec3 p ) +{ + float h = terrain2(p.xz); + + + float ss = 0.03; + float hh = h*ss; + float fh = fract(hh); + float ih = floor(hh); + fh = mix( sqrt(fh), fh, smoothstep(50.0,140.0,h) ); + h = (ih+fh)/ss; + + return p.y - h; +} + +bool jinteresct(in vec3 rO, in vec3 rD, out float resT ) +{ + float h = 0.0; + float t = 0.0; + for( int j=0; j<120; j++ ) + { + //if( t>2000.0 ) break; + + vec3 p = rO + t*rD; +if( p.y>300.0 ) break; + h = map( p ); + + if( h<0.1 ) + { + resT = t; + return true; + } + t += max(0.1,0.5*h); + + } + + if( h<5.0 ) + { + resT = t; + return true; + } + return false; +} + +float sinteresct(in vec3 rO, in vec3 rD ) +{ + float res = 1.0; + float t = 0.0; + for( int j=0; j<50; j++ ) + { + //if( t>1000.0 ) break; + vec3 p = rO + t*rD; + + float h = map( p ); + + if( h<0.1 ) + { + return 0.0; + } + res = min( res, 16.0*h/t ); + t += h; + + } + + return clamp( res, 0.0, 1.0 ); +} + +vec3 calcNormal( in vec3 pos, float t ) +{ + float e = 0.001; + e = 0.001*t; + vec3 eps = vec3(e,0.0,0.0); + vec3 nor; + nor.x = map2(pos+eps.xyy) - map2(pos-eps.xyy); + nor.y = map2(pos+eps.yxy) - map2(pos-eps.yxy); + nor.z = map2(pos+eps.yyx) - map2(pos-eps.yyx); + return normalize(nor); +} + +vec3 camPath( float time ) +{ + vec2 p = 600.0*vec2( cos(1.4+0.37*time), + cos(3.2+0.31*time) ); + + return vec3( p.x, 0.0, p.y ); +} + +void main(void) +{ + vec2 xy = -1.0 + 2.0*gl_FragCoord.xy / iResolution.xy; + + vec2 s = xy*vec2(1.75,1.0); + + #ifdef STEREO + float isCyan = mod(gl_FragCoord.x + mod(gl_FragCoord.y,2.0),2.0); + #endif + + float time = iGlobalTime*.15; + + vec3 light1 = normalize( vec3( 0.4, 0.22, 0.6 ) ); + vec3 light2 = vec3( -0.707, 0.000, -0.707 ); + + + vec3 campos = camPath( time ); + vec3 camtar = camPath( time + 3.0 ); + campos.y = terrain( campos.xz ) + 15.0; + camtar.y = campos.y*0.5; + + float roll = 0.1*cos(0.1*time); + vec3 cw = normalize(camtar-campos); + vec3 cp = vec3(sin(roll), cos(roll),0.0); + vec3 cu = normalize(cross(cw,cp)); + vec3 cv = normalize(cross(cu,cw)); + vec3 rd = normalize( s.x*cu + s.y*cv + 1.6*cw ); + + #ifdef STEREO + campos += 2.0*cu*isCyan; // move camera to the right - the rd vector is still good + #endif + + float sundot = clamp(dot(rd,light1),0.0,1.0); + vec3 col; + float t; + if( !jinteresct(campos,rd,t) ) + { + col = 0.9*vec3(0.97,.99,1.0)*(1.0-0.3*rd.y); + col += 0.2*vec3(0.8,0.7,0.5)*pow( sundot, 4.0 ); + } + else + { + vec3 pos = campos + t*rd; + + vec3 nor = calcNormal( pos, t ); + + float dif1 = clamp( dot( light1, nor ), 0.0, 1.0 ); + float dif2 = clamp( 0.2 + 0.8*dot( light2, nor ), 0.0, 1.0 ); + float sh = 1.0; + if( dif1>0.001 ) + sh = sinteresct(pos+light1*20.0,light1); + + vec3 dif1v = vec3(dif1); + dif1v *= vec3( sh, sh*sh*0.5+0.5*sh, sh*sh ); + + float r = noise( 7.0*pos.xz ); + + col = (r*0.25+0.75)*0.9*mix( vec3(0.10,0.05,0.03), vec3(0.13,0.10,0.08), clamp(terrain2( vec2(pos.x,pos.y*48.0))/200.0,0.0,1.0) ); + col = mix( col, 0.17*vec3(0.5,.23,0.04)*(0.50+0.50*r),smoothstep(0.70,0.9,nor.y) ); + col = mix( col, 0.10*vec3(0.2,.30,0.00)*(0.25+0.75*r),smoothstep(0.95,1.0,nor.y) ); + col *= 0.75; + // snow + #if 1 + float h = smoothstep(55.0,80.0,pos.y + 25.0*fbm(0.01*pos.xz) ); + float e = smoothstep(1.0-0.5*h,1.0-0.1*h,nor.y); + float o = 0.3 + 0.7*smoothstep(0.0,0.1,nor.x+h*h); + float s = h*e*o; + s = smoothstep( 0.1, 0.9, s ); + col = mix( col, 0.4*vec3(0.6,0.65,0.7), s ); + #endif + + + vec3 brdf = 2.0*vec3(0.17,0.19,0.20)*clamp(nor.y,0.0,1.0); + brdf += 6.0*vec3(1.00,0.95,0.80)*dif1v; + brdf += 2.0*vec3(0.20,0.20,0.20)*dif2; + + col *= brdf; + + float fo = 1.0-exp(-pow(0.0015*t,1.5)); + vec3 fco = vec3(0.7) + 0.6*vec3(0.8,0.7,0.5)*pow( sundot, 4.0 ); + col = mix( col, fco, fo ); + } + + col = sqrt(col); + + vec2 uv = xy*0.5+0.5; + col *= 0.7 + 0.3*pow(16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y),0.1); + + #ifdef STEREO + col *= vec3( isCyan, 1.0-isCyan, 1.0-isCyan ); + #endif + + mgl_FragColor = vec4(col,1.0); +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/landscape.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/landscape.vp new file mode 100644 index 000000000..fc698f2a8 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/landscape.vp @@ -0,0 +1,11 @@ + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +attribute vec2 inVertex; + +void main() { + gl_Position = vec4(inVertex, 0, 1); +}
\ No newline at end of file diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/mgl_default_xxx.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/mgl_default_xxx.fp new file mode 100644 index 000000000..a2abf9e2c --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/mgl_default_xxx.fp @@ -0,0 +1,16 @@ +// Copyright 2012 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; +#else + #define mgl_FragColor gl_FragColor +#endif + +varying vec4 frontColor; + +void main (void) +{ + mgl_FragColor = frontColor; +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/mgl_default_xxx.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/mgl_default_xxx.vp new file mode 100644 index 000000000..98e7916ab --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/mgl_default_xxx.vp @@ -0,0 +1,18 @@ +//Copyright 2012 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +uniform mat4 mgl_PMVMatrix[2]; // P, Mv +attribute vec4 mgl_Vertex; +attribute vec4 mgl_Color; + +varying vec4 frontColor; + +void main(void) +{ + frontColor = mgl_Color; + gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * mgl_Vertex; +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/ruler.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/ruler.fp new file mode 100644 index 000000000..f16a3eeb1 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/ruler.fp @@ -0,0 +1,33 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; +#else + #define mgl_FragColor gl_FragColor +#endif + +#ifdef GL_ES + #define MEDIUMP mediump + #define HIGHP highp + #define LOWP lowp +#else + #define MEDIUMP + #define HIGHP + #define LOWP +#endif + +uniform MEDIUMP vec3 gcu_RulerColor; +uniform MEDIUMP vec2 gcu_RulerPixFreq; + +const MEDIUMP vec2 onev2 = vec2(1.0, 1.0); + +void main (void) +{ + MEDIUMP vec2 c = step( onev2, mod(gl_FragCoord.xy, gcu_RulerPixFreq) ); + if( c.s == 0.0 || c.t == 0.0 ) { + mgl_FragColor = vec4(gcu_RulerColor, 1.0); + } else { + discard; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/texsequence_xxx.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/texsequence_xxx.fp new file mode 100644 index 000000000..e4f21f95f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/texsequence_xxx.fp @@ -0,0 +1,30 @@ +// Copyright 2012 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; + #define texture2D texture +#else + #define mgl_FragColor gl_FragColor +#endif + +varying vec2 mgl_texCoord; +varying vec4 frontColor; + +// Insert dynamic code after the following tag: +// TEXTURE-SEQUENCE-CODE-BEGIN +// TEXTURE-SEQUENCE-CODE-END + +void main (void) +{ + vec4 texColor; + if(0.0 <= mgl_texCoord.t && mgl_texCoord.t<=1.0) { + texColor = myTexture2D(mgl_ActiveTexture, mgl_texCoord); + } else { + texColor = vec4(1, 1, 1, 1); + } + + // mix frontColor with texture .. + mgl_FragColor = vec4(frontColor*texColor); +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/texsequence_xxx.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/texsequence_xxx.vp new file mode 100644 index 000000000..1030dab47 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/texsequence_xxx.vp @@ -0,0 +1,22 @@ +// Copyright 2012 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +uniform mat4 mgl_PMVMatrix[2]; +// uniform mat4 mgl_STMatrix; +attribute vec4 mgl_Vertex; +attribute vec4 mgl_Color; +attribute vec4 mgl_MultiTexCoord; +varying vec4 frontColor; +varying vec2 mgl_texCoord; + +void main(void) +{ + frontColor=mgl_Color; + // mgl_texCoord = (mgl_STMatrix * mgl_MultiTexCoord).st; + mgl_texCoord = mgl_MultiTexCoord.st; + gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * mgl_Vertex; +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/texture01_xxx.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/texture01_xxx.fp new file mode 100644 index 000000000..93f252cd6 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/texture01_xxx.fp @@ -0,0 +1,28 @@ +// Copyright 2012 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; + #define texture2D texture +#else + #define mgl_FragColor gl_FragColor +#endif + +varying vec2 mgl_texCoord; +varying vec4 frontColor; + +uniform sampler2D mgl_ActiveTexture; + +void main (void) +{ + vec4 texColor; + if(0.0 <= mgl_texCoord.t && mgl_texCoord.t<=1.0) { + texColor = texture2D(mgl_ActiveTexture, mgl_texCoord); + } else { + discard; + } + + // mix frontColor with texture .. pre-multiplying texture alpha + mgl_FragColor = vec4( mix( frontColor.rgb, texColor.rgb, texColor.a ), frontColor.a ); +} + diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/texture01_xxx.vp b/src/demos/com/jogamp/opengl/demos/es2/shader/texture01_xxx.vp new file mode 100644 index 000000000..1030dab47 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/texture01_xxx.vp @@ -0,0 +1,22 @@ +// Copyright 2012 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define attribute in + #define varying out +#endif + +uniform mat4 mgl_PMVMatrix[2]; +// uniform mat4 mgl_STMatrix; +attribute vec4 mgl_Vertex; +attribute vec4 mgl_Color; +attribute vec4 mgl_MultiTexCoord; +varying vec4 frontColor; +varying vec2 mgl_texCoord; + +void main(void) +{ + frontColor=mgl_Color; + // mgl_texCoord = (mgl_STMatrix * mgl_MultiTexCoord).st; + mgl_texCoord = mgl_MultiTexCoord.st; + gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * mgl_Vertex; +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/shader/texture02_xxx.fp b/src/demos/com/jogamp/opengl/demos/es2/shader/texture02_xxx.fp new file mode 100644 index 000000000..10073e85c --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/shader/texture02_xxx.fp @@ -0,0 +1,28 @@ +// Copyright 2012 JogAmp Community. All rights reserved. + +#if __VERSION__ >= 130 + #define varying in + out vec4 mgl_FragColor; + #define texture2D texture +#else + #define mgl_FragColor gl_FragColor +#endif + +varying vec2 mgl_texCoord; +varying vec4 frontColor; + +uniform sampler2D mgl_Texture0; +uniform sampler2D mgl_Texture1; + +const vec4 One = vec4(1.0, 1.0, 1.0, 1.0); + +void main (void) +{ + vec4 texColor0 = texture2D(mgl_Texture0, mgl_texCoord); + vec4 texColor1 = texture2D(mgl_Texture1, mgl_texCoord); + + // mgl_FragColor = ( ( texColor0 + texColor1 ) / 2.0 ) * frontColor; + // mgl_FragColor = mix(texColor0, texColor1, One/2.0) * frontColor; + mgl_FragColor = min(One, mix(texColor0, texColor1, One/2.0) * 1.6) * frontColor; +} + diff --git a/src/demos/com/jogamp/opengl/demos/ios/Hello.java b/src/demos/com/jogamp/opengl/demos/ios/Hello.java new file mode 100644 index 000000000..d593dd3bc --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/ios/Hello.java @@ -0,0 +1,196 @@ +/** + * Copyright 2019 Gothel Software e.K. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY Gothel Software e.K. ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Gothel Software e.K. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of Gothel Software e.K. + */ +package com.jogamp.opengl.demos.ios; + +import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.VersionUtil; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.nativewindow.MutableGraphicsConfiguration; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; + +import com.jogamp.common.GlueGenVersion; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.es2.RedSquareES2; + +import jogamp.nativewindow.WrappedWindow; +import jogamp.nativewindow.ios.IOSUtil; +import jogamp.opengl.GLDrawableFactoryImpl; + +import com.jogamp.opengl.GLAutoDrawableDelegate; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLDrawable; +import com.jogamp.opengl.GLDrawableFactory; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLProfile; + +public class Hello { + + private static int parseInt(final String s, final int def) { + try { + return Integer.parseInt(s); + } catch (final NumberFormatException nfe) {} + return def; + } + + public static void main(final String[] args) { + int width = 832, height = 480; // ipad pro 11: 2388x1668 px (scale: 2) + int fboDepthBits = 0; // CAEAGLLayer fails with depth 16 + 24 in Simulation + boolean exitJVM = false; + String demoName = "com.jogamp.opengl.demos.es2.LandscapeES2"; + for(int i=0; i<args.length; i++) { + if(args[i].equals("-exit")) { + exitJVM = true; + } else if(args[i].equals("-demo") && i+1<args.length) { + demoName = args[++i]; + } else if(args[i].equals("-width") && i+1<args.length) { + width = parseInt(args[++i], width); + } else if(args[i].equals("-height") && i+1<args.length) { + height = parseInt(args[++i], height); + } else if(args[i].equals("-fboDepthBits") && i+1<args.length) { + fboDepthBits = parseInt(args[++i], fboDepthBits); + } else { + System.err.println("ignoring arg["+i+"]: "+args[i]); + } + } + System.out.println("Hello JogAmp World: exitJVM "+exitJVM+", size "+width+"x"+height+", fboDepthBits "+fboDepthBits+", demo "+demoName); + System.out.println("os.name: <"+System.getProperty("os.name")+">"); + System.out.println("os.version: <"+System.getProperty("os.version")+">"); + System.out.println("os.arch: <"+System.getProperty("os.arch")+">"); + System.out.println("java.vendor: <"+System.getProperty("java.vendor")+">"); + System.out.println("java.vendor.url: <"+System.getProperty("java.vendor.url")+">"); + System.out.println("java.version: <"+System.getProperty("java.version")+">"); + System.out.println("java.vm.name: <"+System.getProperty("java.vm.name")+">"); + System.out.println("java.runtime.name: <"+System.getProperty("java.runtime.name")+">"); + System.out.println(""); + System.out.println(VersionUtil.getPlatformInfo()); + System.out.println(""); + System.out.println("Version Info:"); + System.out.println(GlueGenVersion.getInstance()); + System.out.println(""); + System.out.println("Full Manifest:"); + System.out.println(GlueGenVersion.getInstance().getFullManifestInfo(null)); + + System.out.println(""); + System.err.println("mark-01"); + System.err.println(""); + System.err.println(JoglVersion.getInstance()); + System.err.println(""); + System.err.println("mark-02"); + System.err.println(""); + GLProfile.initSingleton(); + System.err.println(""); + System.err.println("mark-03"); + System.out.println(""); + System.out.println(JoglVersion.getDefaultOpenGLInfo(GLProfile.getDefaultDevice(), null, true)); + System.out.println(""); + System.err.println("mark-04"); + System.err.println(""); + + GLAutoDrawableDelegate glad = null; + final long uiWindow = IOSUtil.CreateUIWindow(0, 0, width, height); + try { + // 1) Config .. + final GLProfile glp = GLProfile.getGL2ES2(); + final GLCapabilities reqCaps = new GLCapabilities(glp); + reqCaps.setOnscreen(true); + reqCaps.setDoubleBuffered(false); + reqCaps.setDepthBits(fboDepthBits); + System.out.println("Requested GL Caps: "+reqCaps); + final GLDrawableFactoryImpl factory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactory(glp); + + // 2) Create native window and wrap it around out NativeWindow structure + final long uiView = IOSUtil.GetUIView(uiWindow, true); + final long caeaglLayer = IOSUtil.GetCAEAGLLayer(uiView); + System.out.println("EAGL: UIWindow 0x"+Long.toHexString(uiWindow)); + System.out.println("EAGL: UIView 0x"+Long.toHexString(uiView)); + System.out.println("EAGL: EAGLLayer 0x"+Long.toHexString(caeaglLayer)); + System.out.println("isUIWindow "+IOSUtil.isUIWindow(uiWindow)+", isUIView "+IOSUtil.isUIView(uiView)+ + ", isCAEAGLLayer "+IOSUtil.isCAEAGLLayer(caeaglLayer)); + final AbstractGraphicsScreen aScreen = NativeWindowFactory.createScreen(NativeWindowFactory.createDevice(null, true /* own */), -1); + final UpstreamWindowHookMutableSizePos hook = new UpstreamWindowHookMutableSizePos(0, 0, width, height, width, height); + final MutableGraphicsConfiguration config = new MutableGraphicsConfiguration(aScreen, reqCaps, reqCaps); + final WrappedWindow nativeWindow = new WrappedWindow(config, uiView, hook, true, uiWindow); + + // 3) Create a GLDrawable .. + final GLDrawable drawable = factory.createGLDrawable(nativeWindow); + drawable.setRealized(true); + // final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable(aScreen.getDevice(), reqCaps, null, width, height); + glad = new GLAutoDrawableDelegate(drawable, null, nativeWindow, false, null) { + @Override + protected void destroyImplInLock() { + super.destroyImplInLock(); // destroys drawable/context + nativeWindow.destroy(); // destroys the actual window, incl. the device + IOSUtil.DestroyUIWindow(uiWindow); + } + }; + glad.display(); // force native context creation + + // Check caps of GLDrawable after realization + final GLCapabilitiesImmutable chosenCaps = glad.getChosenGLCapabilities(); + System.out.println("Choosen GL Caps: "+chosenCaps); + + GLEventListener demo = null; + { + try { + demo = (GLEventListener) ReflectionUtil.createInstance(demoName, Hello.class.getClassLoader()); + } catch( final Exception e ) { + System.err.println(e.getMessage()+" using: <"+demoName+">"); + } + if( null == demo ) { + demo = new RedSquareES2(); + } + } + System.out.println("Choosen demo "+demo.getClass().getName()); + glad.addGLEventListener(demo); + + for(int i=0; i<60*10; i++) { // 10s w/ 60fps + glad.display(); // force native context creation + try { + Thread.sleep(16); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + } + + } finally { + if( null != glad ) { + glad.destroy(); + } + } + + System.err.println(""); + System.err.println("mark-05"); + System.err.println(""); + + if( exitJVM ) { + System.exit(0); + } + } +} diff --git a/src/demos/com/jogamp/opengl/demos/ios/Hello0.java b/src/demos/com/jogamp/opengl/demos/ios/Hello0.java new file mode 100644 index 000000000..045914855 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/ios/Hello0.java @@ -0,0 +1,20 @@ +package com.jogamp.opengl.demos.ios; + +import com.jogamp.opengl.GLProfile; + +import jogamp.nativewindow.ios.IOSUtil; + +public class Hello0 { + public static void main(final String[] args) { + System.out.println("Hello JogAmp World"); + GLProfile.initSingleton(); + { + IOSUtil.RunOnMainThread(true, false, new Runnable() { + @Override + public void run() { + IOSUtil.CreateGLViewDemoA(); + } } ); + } + } + +} diff --git a/src/jogl/classes/com/jogamp/opengl/FBObject.java b/src/jogl/classes/com/jogamp/opengl/FBObject.java index c36727fe4..00a560fc7 100644 --- a/src/jogl/classes/com/jogamp/opengl/FBObject.java +++ b/src/jogl/classes/com/jogamp/opengl/FBObject.java @@ -34,7 +34,6 @@ import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GL2ES3; import com.jogamp.opengl.GL2GL3; -import com.jogamp.opengl.GL3; import com.jogamp.opengl.GLBase; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLCapabilitiesImmutable; @@ -43,6 +42,7 @@ import com.jogamp.opengl.GLException; import com.jogamp.opengl.GLProfile; import jogamp.opengl.Debug; +import jogamp.opengl.ios.eagl.EAGL; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.PropertyAccess; @@ -483,6 +483,48 @@ public class FBObject { @Override public final ColorAttachment getColorAttachment() { return this; } + @Override + public boolean initialize(final GL gl) throws GLException { + final boolean init = 0 == getName(); + if( init ) { + final boolean checkError = DEBUG || GLContext.DEBUG_GL; + if( checkError ) { + checkPreGLError(gl); + } + final int[] name = new int[] { -1 }; + gl.glGenRenderbuffers(1, name, 0); + setName(name[0]); + + gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, getName()); + if( getSamples() > 0 ) { + ((GL2ES3)gl).glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, getSamples(), format, getWidth(), getHeight()); + } else { + // FIXME: Need better way to inject the IOS EAGL Layer into FBObject + // FIXME: May want to implement optional injection of a BufferStorage SPI? + final GLContext ctx = gl.getContext(); + final Long iosEAGLLayer = (Long) ctx.getAttachedObject("IOS_EAGL_LAYER"); + if( null != iosEAGLLayer ) { + EAGL.eaglBindDrawableStorageToRenderbuffer(gl.getContext().contextHandle, GL.GL_RENDERBUFFER, iosEAGLLayer.longValue()); + } else { + gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, format, getWidth(), getHeight()); + } + } + if( checkError ) { + final int glerr = gl.glGetError(); + if(GL.GL_NO_ERROR != glerr) { + gl.glDeleteRenderbuffers(1, name, 0); + setName(0); + throw new GLException("GL Error "+toHexString(glerr)+" while creating "+this); + } + } + if(DEBUG) { + System.err.println("Attachment.init.X: "+this); + } + } + return init; + } + + } /** Texture FBO attachment */ @@ -1250,7 +1292,7 @@ public class FBObject { return("FBO missing read buffer"); case GL.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return("FBO missing multisample buffer"); - case GL3.GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: + case GL3ES3.GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: return("FBO missing layer targets"); case GL.GL_FRAMEBUFFER_UNSUPPORTED: @@ -1281,7 +1323,7 @@ public class FBObject { case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: case GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: case GL.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - case GL3.GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: + case GL3ES3.GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: if(0 == colorbufferCount || null == depth) { // we are in transition return true; diff --git a/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java index 51da34ce0..1fe42a332 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java @@ -43,6 +43,7 @@ package com.jogamp.opengl; import java.util.ArrayList; import java.util.List; +import com.jogamp.common.os.Platform; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.opengl.GLAutoDrawableDelegate; @@ -57,6 +58,7 @@ import com.jogamp.nativewindow.NativeWindowFactory; import com.jogamp.nativewindow.ProxySurface; import com.jogamp.nativewindow.UpstreamSurfaceHook; +import jogamp.common.os.PlatformPropsImpl; import jogamp.opengl.Debug; /** <p> Provides a virtual machine- and operating system-independent @@ -137,6 +139,8 @@ public abstract class GLDrawableFactory { factoryClassName = "jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory"; } else if ( nwt == NativeWindowFactory.TYPE_MACOSX ) { factoryClassName = "jogamp.opengl.macosx.cgl.MacOSXCGLDrawableFactory"; + } else if ( nwt == NativeWindowFactory.TYPE_IOS ) { + factoryClassName = "jogamp.opengl.ios.eagl.IOSEAGLDrawableFactory"; } else { // may use egl*Factory .. if (DEBUG || GLProfile.DEBUG) { @@ -144,7 +148,7 @@ public abstract class GLDrawableFactory { } } } - if ( !GLProfile.disableOpenGLDesktop ) { + if ( !GLProfile.disableOpenGLDesktop || GLProfile.disabledEGL ) { if ( null != factoryClassName ) { if (DEBUG || GLProfile.DEBUG) { System.err.println("GLDrawableFactory.static - Native OS Factory for: "+nwt+": "+factoryClassName); @@ -168,7 +172,7 @@ public abstract class GLDrawableFactory { System.err.println("Info: GLDrawableFactory.static - Desktop GLDrawableFactory - disabled!"); } - if(!GLProfile.disableOpenGLES) { + if(!GLProfile.disableOpenGLES && !GLProfile.disabledEGL) { try { tmp = (GLDrawableFactory) ReflectionUtil.createInstance("jogamp.opengl.egl.EGLDrawableFactory", cl); } catch (final Exception jre) { @@ -434,6 +438,15 @@ public abstract class GLDrawableFactory { /** * Returns the sole GLDrawableFactory instance for the desktop (X11, WGL, ..) if exist or null + * <p> + * To fetch the appropriate {@link GLDrawableFactory} for native desktop + * or mobile, use {@link #getFactory(boolean)}. + * </p> + * <p> + * It is possible that the desktop {@link GLDrawableFactory} will be used for + * native mobile GL profiles, e.g. {@link Platform.OSType#IOS}. + * </p> + * @return the matching {@link GLDrawableFactory} or {@code null} if none is available */ public static GLDrawableFactory getDesktopFactory() { GLProfile.initSingleton(); @@ -441,7 +454,16 @@ public abstract class GLDrawableFactory { } /** - * Returns the sole GLDrawableFactory instance for EGL if exist or null + * Returns the sole {@link GLDrawableFactory} instance for EGL if exist or null. + * <p> + * To fetch the appropriate {@link GLDrawableFactory} for native desktop + * or mobile, use {@link #getFactory(boolean)}. + * </p> + * <p> + * It is possible that a non EGL {@link GLDrawableFactory} will be used for + * native mobile GL profiles, e.g. {@link Platform.OSType#IOS}. + * </p> + * @return the matching {@link GLDrawableFactory} or {@code null} if none is available */ public static GLDrawableFactory getEGLFactory() { GLProfile.initSingleton(); @@ -449,34 +471,61 @@ public abstract class GLDrawableFactory { } /** - * Returns the sole GLDrawableFactory instance. + * Returns the sole {@link GLDrawableFactory} instance. * - * @param glProfile GLProfile to determine the factory type, ie EGLDrawableFactory, - * or one of the native GLDrawableFactory's, ie X11/GLX, Windows/WGL or MacOSX/CGL. + * @param glProfile GLProfile to determine the factory type, ie for native mobile GL or native desktop GL. + * @return the matching {@link GLDrawableFactory} + * @throws GLException if no matching {@link GLDrawableFactory} exists */ public static GLDrawableFactory getFactory(final GLProfile glProfile) throws GLException { - return getFactoryImpl(glProfile.getImplName()); + final GLDrawableFactory f = getFactoryImpl(glProfile.getImplName()); + if( null != f ) { + return f; + } + throw new GLException("No GLDrawableFactory available for profile: "+glProfile); } - - protected static GLDrawableFactory getFactoryImpl(final String glProfileImplName) throws GLException { - if ( GLProfile.usesNativeGLES(glProfileImplName) ) { - if(null!=eglFactory) { + /** + * Returns the sole {@link GLDrawableFactory} instance, either for mobile if {@code usesNativeGLES} is true, + * or for desktop otherwise. + * @param useNativeGLES request native mobile GLES support if true + * @return the matching {@link GLDrawableFactory} or {@code null} if none is available + */ + public static GLDrawableFactory getFactory(final boolean useNativeGLES) { + GLProfile.initSingleton(); + return getFactoryImpl( useNativeGLES ); + } + protected static GLDrawableFactory getFactoryImpl(final String glProfileImplName) { + return getFactoryImpl( GLProfile.usesNativeGLES(glProfileImplName) ); + } + protected static GLDrawableFactory getFactoryImpl(final boolean useNativeGLES) { + if( useNativeGLES ) { + if(null!=eglFactory && eglFactory.hasOpenGLESSupport() ) { return eglFactory; } - } else if(null!=nativeOSFactory) { - return nativeOSFactory; + if(null!=nativeOSFactory && nativeOSFactory.hasOpenGLESSupport() ) { + return nativeOSFactory; + } + } else { + if(null!=nativeOSFactory && nativeOSFactory.hasOpenGLDesktopSupport() ) { + return nativeOSFactory; + } } - throw new GLException("No GLDrawableFactory available for profile: "+glProfileImplName); + return null; } - - protected static GLDrawableFactory getFactoryImpl(final AbstractGraphicsDevice device) throws GLException { + /** + * Returns the sole {@link GLDrawableFactory} matching the given {@link AbstractGraphicsDevice} instance, + * which will be suitable either for native mobile or native desktop. + * @param device the queries {@link AbstractGraphicsDevice} seeking for its matching factory + * @return the matching {@link GLDrawableFactory} or {@code null} if none is available + */ + public static GLDrawableFactory getFactory(final AbstractGraphicsDevice device) { if(null != nativeOSFactory && nativeOSFactory.getIsDeviceCompatible(device)) { return nativeOSFactory; } if(null != eglFactory && eglFactory.getIsDeviceCompatible(device)) { return eglFactory; } - throw new GLException("No native platform GLDrawableFactory, nor EGLDrawableFactory available: "+device); + return null; } /** diff --git a/src/jogl/classes/com/jogamp/opengl/GLProfile.java b/src/jogl/classes/com/jogamp/opengl/GLProfile.java index e19535e5d..0e0d45444 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLProfile.java +++ b/src/jogl/classes/com/jogamp/opengl/GLProfile.java @@ -86,7 +86,7 @@ public class GLProfile { * and if one platform may have a buggy implementation, * setting the property <code>jogl.disable.openglcore</code> disables querying possible existing native OpenGL core profiles. * <p> - * This exclusion is disabled for {@link Platform.OSType#MACOS}. + * This exclusion is disabled for {@link Platform.OSType#MACOS} and {@link Platform.OSType#IOS}. * </p> */ public static final boolean disableOpenGLCore; @@ -99,7 +99,7 @@ public class GLProfile { * This exclusion also disables {@link #disableOpenGLES OpenGL ES}. * </p> * <p> - * This exclusion is disabled for {@link Platform.OSType#MACOS}. + * This exclusion is disabled for {@link Platform.OSType#MACOS} and {@link Platform.OSType#IOS}. * </p> */ public static final boolean disableOpenGLARBContext; @@ -119,6 +119,13 @@ public class GLProfile { public static final boolean disableOpenGLDesktop; /** + * In case no EGL implementation is available + * like on the {@link Platform.OSType#IOS} platform, + * this is set to {@code true}. + */ + public static final boolean disabledEGL; + + /** * Disable surfaceless OpenGL context capability and its probing * by setting the property <code>jogl.disable.surfacelesscontext</code>. * <p> @@ -145,11 +152,13 @@ public class GLProfile { static { // Also initializes TempJarCache if shall be used. Platform.initSingleton(); - final boolean isOSX = Platform.OSType.MACOS == Platform.getOSType(); + final boolean isIOS = Platform.OSType.IOS == Platform.getOSType(); + final boolean isOSXorIOS = Platform.OSType.MACOS == Platform.getOSType() || isIOS; DEBUG = Debug.debug("GLProfile"); - disableOpenGLCore = PropertyAccess.isPropertyDefined("jogl.disable.openglcore", true) && !isOSX; - disableOpenGLARBContext = PropertyAccess.isPropertyDefined("jogl.disable.openglarbcontext", true) && !isOSX; + disabledEGL = isIOS; + disableOpenGLCore = PropertyAccess.isPropertyDefined("jogl.disable.openglcore", true) && !isOSXorIOS; + disableOpenGLARBContext = PropertyAccess.isPropertyDefined("jogl.disable.openglarbcontext", true) && !isOSXorIOS; disableOpenGLES = disableOpenGLARBContext || PropertyAccess.isPropertyDefined("jogl.disable.opengles", true); disableOpenGLDesktop = PropertyAccess.isPropertyDefined("jogl.disable.opengldesktop", true); disableSurfacelessContext = PropertyAccess.isPropertyDefined("jogl.disable.surfacelesscontext", true); @@ -243,7 +252,7 @@ public class GLProfile { initLock.unlock(); } if(DEBUG) { - if( justInitialized && ( hasGL234Impl || hasGL234OnEGLImpl || hasGLES1Impl || hasGLES3Impl ) ) { + if( justInitialized && ( hasGL234Impl || hasGL234OnMobileImpl || hasGLES1Impl || hasGLES3Impl ) ) { System.err.println(JoglVersion.getDefaultOpenGLInfo(defaultDevice, null, true)); } } @@ -671,6 +680,18 @@ public class GLProfile { public static final String[] GL_PROFILE_LIST_MIN_DESKTOP = new String[] { GL2, GL3bc, GL4bc, GL3, GL4 }; /** + * Order of maximum original mobile profiles. + * + * <ul> + * <li> GLES3 </li> + * <li> GLES2 </li> + * <li> GLES1 </li> + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_MAX_MOBILE = new String[] { GLES3, GLES2, GLES1 }; + + /** * Order of maximum fixed function profiles * * <ul> @@ -1627,10 +1648,10 @@ public class GLProfile { private static /*final*/ boolean hasDesktopGLFactory; private static /*final*/ boolean hasGL234Impl; - private static /*final*/ boolean hasEGLFactory; + private static /*final*/ boolean hasMobileFactory; private static /*final*/ boolean hasGLES3Impl; private static /*final*/ boolean hasGLES1Impl; - private static /*final*/ boolean hasGL234OnEGLImpl; + private static /*final*/ boolean hasGL234OnMobileImpl; private static /*final*/ Constructor<?> ctorGL234Impl; private static /*final*/ Constructor<?> ctorGLES3Impl; private static /*final*/ Constructor<?> ctorGLES1Impl; @@ -1638,7 +1659,7 @@ public class GLProfile { private static /*final*/ Constructor<?> ctorGLES3ProcAddr; private static /*final*/ Constructor<?> ctorGLES1ProcAddr; - private static /*final*/ GLDrawableFactoryImpl eglFactory = null; + private static /*final*/ GLDrawableFactoryImpl mobileFactory = null; private static /*final*/ GLDrawableFactoryImpl desktopFactory = null; private static /*final*/ AbstractGraphicsDevice defaultDevice = null; @@ -1683,7 +1704,7 @@ public class GLProfile { ctorGL234ProcAddr = null; } } - hasGL234OnEGLImpl = hasGL234Impl; + hasGL234OnMobileImpl = hasGL234Impl; // depends on hasEGLFactory { @@ -1748,7 +1769,7 @@ public class GLProfile { try { desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2); if(null != desktopFactory) { - final DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(2, GLContext.CTX_PROFILE_COMPAT); + final GLDynamicLookupHelper glLookupHelper = desktopFactory.getGLDynamicLookupHelper(2, GLContext.CTX_PROFILE_COMPAT); hasGL234Impl = null!=glLookupHelper && glLookupHelper.isLibComplete() && hasGL234Impl; hasDesktopGLFactory = hasGL234Impl; } @@ -1777,48 +1798,46 @@ public class GLProfile { defaultDesktopDevice = desktopFactory.getDefaultDevice(); } - if ( ReflectionUtil.isClassAvailable("jogamp.opengl.egl.EGLDrawableFactory", classloader) ) { - t=null; - try { - eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2); - if(null != eglFactory) { - // update hasGLES1Impl, hasGLES3Impl, hasGL234OnEGLImpl based on library completion - final GLDynamicLookupHelper es2DynLookup = eglFactory.getGLDynamicLookupHelper(2, GLContext.CTX_PROFILE_ES); - final GLDynamicLookupHelper es1DynLookup = eglFactory.getGLDynamicLookupHelper(1, GLContext.CTX_PROFILE_ES); - final GLDynamicLookupHelper glXDynLookup = eglFactory.getGLDynamicLookupHelper(3, GLContext.CTX_PROFILE_CORE); - hasGLES3Impl = null!=es2DynLookup && es2DynLookup.isLibComplete() && hasGLES3Impl; - hasGLES1Impl = null!=es1DynLookup && es1DynLookup.isLibComplete() && hasGLES1Impl; - hasGL234OnEGLImpl = null!=glXDynLookup && glXDynLookup.isLibComplete() && hasGL234OnEGLImpl; - hasEGLFactory = hasGLES3Impl || hasGLES1Impl || hasGL234OnEGLImpl; - } - } catch (final LinkageError le) { - t=le; - } catch (final SecurityException se) { - t=se; - } catch (final NullPointerException npe) { - t=npe; - } catch (final RuntimeException re) { - t=re; + t=null; + try { + mobileFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2); + if(null != mobileFactory) { + // update hasGLES1Impl, hasGLES3Impl, hasGL234OnEGLImpl based on library completion + final GLDynamicLookupHelper es2DynLookup = mobileFactory.getGLDynamicLookupHelper(2, GLContext.CTX_PROFILE_ES); + final GLDynamicLookupHelper es1DynLookup = mobileFactory.getGLDynamicLookupHelper(1, GLContext.CTX_PROFILE_ES); + final GLDynamicLookupHelper glXDynLookup = mobileFactory.getGLDynamicLookupHelper(3, GLContext.CTX_PROFILE_CORE); + hasGLES3Impl = null!=es2DynLookup && es2DynLookup.isLibComplete() && hasGLES3Impl; + hasGLES1Impl = null!=es1DynLookup && es1DynLookup.isLibComplete() && hasGLES1Impl; + hasGL234OnMobileImpl = null!=glXDynLookup && glXDynLookup.isLibComplete() && hasGL234OnMobileImpl; + hasMobileFactory = hasGLES3Impl || hasGLES1Impl || hasGL234OnMobileImpl; } - if(DEBUG) { - if(null!=t) { - t.printStackTrace(); - } + } catch (final LinkageError le) { + t=le; + } catch (final SecurityException se) { + t=se; + } catch (final NullPointerException npe) { + t=npe; + } catch (final RuntimeException re) { + t=re; + } + if(DEBUG) { + if(null!=t) { + t.printStackTrace(); } } - final AbstractGraphicsDevice defaultEGLDevice; - if(null == eglFactory) { - hasEGLFactory = false; - hasGL234OnEGLImpl= false; + final AbstractGraphicsDevice defaultMobileDevice; + if(null == mobileFactory) { + hasMobileFactory = false; + hasGL234OnMobileImpl= false; hasGLES3Impl = false; hasGLES1Impl = false; - defaultEGLDevice = null; + defaultMobileDevice = null; if(DEBUG) { - System.err.println("Info: GLProfile.init - EGL GLDrawable factory not available"); + System.err.println("Info: GLProfile.init - Mobile GLDrawable factory not available"); } } else { - defaultEGLDevice = eglFactory.getDefaultDevice(); + defaultMobileDevice = mobileFactory.getDefaultDevice(); } if( null != defaultDesktopDevice ) { @@ -1826,10 +1845,10 @@ public class GLProfile { if(DEBUG) { System.err.println("Info: GLProfile.init - Default device is desktop derived: "+defaultDevice); } - } else if ( null != defaultEGLDevice ) { - defaultDevice = defaultEGLDevice; + } else if ( null != defaultMobileDevice ) { + defaultDevice = defaultMobileDevice; if(DEBUG) { - System.err.println("Info: GLProfile.init - Default device is EGL derived: "+defaultDevice); + System.err.println("Info: GLProfile.init - Default device is mobile derived: "+defaultDevice); } } else { if(DEBUG) { @@ -1839,22 +1858,22 @@ public class GLProfile { } // we require to initialize the EGL device 1st, if available - final boolean addedEGLProfile = null != defaultEGLDevice ? initProfilesForDevice(defaultEGLDevice) : false; + final boolean addedMobileProfile = null != defaultMobileDevice ? initProfilesForDevice(defaultMobileDevice) : false; final boolean addedDesktopProfile = null != defaultDesktopDevice ? initProfilesForDevice(defaultDesktopDevice) : false; - final boolean addedAnyProfile = addedEGLProfile || addedDesktopProfile ; + final boolean addedAnyProfile = addedMobileProfile || addedDesktopProfile ; if(DEBUG) { - System.err.println("GLProfile.init addedAnyProfile "+addedAnyProfile+" (desktop: "+addedDesktopProfile+", egl "+addedEGLProfile+")"); + System.err.println("GLProfile.init addedAnyProfile "+addedAnyProfile+" (desktop: "+addedDesktopProfile+", mobile "+addedMobileProfile+")"); System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable); System.err.println("GLProfile.init hasDesktopGLFactory "+hasDesktopGLFactory); System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl); - System.err.println("GLProfile.init hasEGLFactory "+hasEGLFactory); + System.err.println("GLProfile.init hasMobileFactory "+hasMobileFactory); System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl); System.err.println("GLProfile.init hasGLES3Impl "+hasGLES3Impl); - System.err.println("GLProfile.init hasGL234OnEGLImpl "+hasGL234OnEGLImpl); + System.err.println("GLProfile.init hasGL234OnEGLImpl "+hasGL234OnMobileImpl); System.err.println("GLProfile.init defaultDevice "+defaultDevice); System.err.println("GLProfile.init defaultDevice Desktop "+defaultDesktopDevice); - System.err.println("GLProfile.init defaultDevice EGL "+defaultEGLDevice); + System.err.println("GLProfile.init defaultDevice Mobile "+defaultMobileDevice); System.err.println("GLProfile.init profile order "+array2String(GL_PROFILE_LIST_ALL)); } } @@ -1869,22 +1888,25 @@ public class GLProfile { } initLock.lock(); try { - final GLDrawableFactory factory = GLDrawableFactory.getFactoryImpl(device); - factory.enterThreadCriticalZone(); - try { - return initProfilesForDeviceCritical(device); - } finally { - factory.leaveThreadCriticalZone(); + final GLDrawableFactory factory = GLDrawableFactory.getFactory(device); + if( null != factory ) { + factory.enterThreadCriticalZone(); + try { + return initProfilesForDeviceCritical(device); + } finally { + factory.leaveThreadCriticalZone(); + } } } finally { initLock.unlock(); } + return false; } private static boolean initProfilesForDeviceCritical(final AbstractGraphicsDevice device) { final boolean isSet = GLContext.getAvailableGLVersionsSet(device); if(DEBUG) { - System.err.println("Info: GLProfile.initProfilesForDevice: "+device+" ("+device.getClass().getName()+"), isSet "+isSet+", hasDesktopGLFactory "+hasDesktopGLFactory+", hasEGLFactory "+hasEGLFactory); + System.err.println("Info: GLProfile.initProfilesForDevice: "+device+" ("+device.getClass().getName()+"), isSet "+isSet+", hasDesktopGLFactory "+hasDesktopGLFactory+", hasEGLFactory "+hasMobileFactory); } if(isSet) { // Avoid recursion and check whether impl. is sane! @@ -1899,7 +1921,7 @@ public class GLProfile { HashMap<String, GLProfile> mappedDesktopProfiles = null; boolean addedDesktopProfile = false; HashMap<String, GLProfile> mappedEGLProfiles = null; - boolean addedEGLProfile = false; + boolean addedMobileProfile = false; final boolean deviceIsDesktopCompatible = hasDesktopGLFactory && desktopFactory.getIsDeviceCompatible(device); @@ -1930,20 +1952,20 @@ public class GLProfile { } } - final boolean deviceIsEGLCompatible = hasEGLFactory && eglFactory.getIsDeviceCompatible(device); + final boolean deviceIsMobileCompatible = hasMobileFactory && mobileFactory.getIsDeviceCompatible(device); // also test GLES1, GLES2 and GLES3 on desktop, since we have implementations / emulations available. - if( deviceIsEGLCompatible ) { + if( deviceIsMobileCompatible ) { // 1st pretend we have all EGL profiles .. computeProfileMap(device, true /* desktopCtxUndef*/, true /* esCtxUndef */); // Triggers eager initialization of share context in GLDrawableFactory for the device, // hence querying all available GLProfiles - final Thread sharedResourceThread = eglFactory.getSharedResourceThread(); + final Thread sharedResourceThread = mobileFactory.getSharedResourceThread(); if(null != sharedResourceThread) { initLock.addOwner(sharedResourceThread); } - final boolean eglSharedCtxAvail = eglFactory.createSharedResource(device); + final boolean eglSharedCtxAvail = mobileFactory.createSharedResource(device); if(null != sharedResourceThread) { initLock.removeOwner(sharedResourceThread); } @@ -1952,28 +1974,28 @@ public class GLProfile { throw new InternalError("Available GLVersions not set for "+device); } mappedEGLProfiles = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); - addedEGLProfile = mappedEGLProfiles.size() > 0; + addedMobileProfile = mappedEGLProfiles.size() > 0; } if (DEBUG) { - System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail+ - ", profiles: "+(addedEGLProfile ? mappedEGLProfiles.size() : 0)); + System.err.println("GLProfile.initProfilesForDevice: "+device+": mobile Shared Ctx "+eglSharedCtxAvail+ + ", profiles: "+(addedMobileProfile ? mappedEGLProfiles.size() : 0)); } } - if( !addedDesktopProfile && !addedEGLProfile ) { + if( !addedDesktopProfile && !addedMobileProfile ) { setProfileMap(device, new HashMap<String /*GLProfile_name*/, GLProfile>()); // empty if(DEBUG) { System.err.println("GLProfile: device could not be initialized: "+device); System.err.println("GLProfile: compatible w/ desktop: "+deviceIsDesktopCompatible+ - ", egl "+deviceIsEGLCompatible); + ", mobile "+deviceIsMobileCompatible); System.err.println("GLProfile: desktoplFactory "+desktopFactory); - System.err.println("GLProfile: eglFactory "+eglFactory); + System.err.println("GLProfile: mobileFactory "+mobileFactory); System.err.println("GLProfile: hasGLES1Impl "+hasGLES1Impl); System.err.println("GLProfile: hasGLES3Impl "+hasGLES3Impl); } } else { final HashMap<String, GLProfile> mappedAllProfiles = new HashMap<String, GLProfile>(); - if( addedEGLProfile ) { + if( addedMobileProfile ) { mappedAllProfiles.putAll(mappedEGLProfiles); } if( addedDesktopProfile ) { @@ -1985,7 +2007,7 @@ public class GLProfile { GLContext.setAvailableGLVersionsSet(device, true); if (DEBUG) { - System.err.println("GLProfile.initProfilesForDevice: "+device.getUniqueID()+": added profile(s): desktop "+addedDesktopProfile+", egl "+addedEGLProfile); + System.err.println("GLProfile.initProfilesForDevice: "+device.getUniqueID()+": added profile(s): desktop "+addedDesktopProfile+", mobile "+addedMobileProfile); System.err.println("GLProfile.initProfilesForDevice: "+device.getUniqueID()+": "+glAvailabilityToString(device)); if(addedDesktopProfile) { dumpGLInfo(desktopFactory, device); @@ -1993,16 +2015,16 @@ public class GLProfile { for(int i=0; i<availCaps.size(); i++) { System.err.println(availCaps.get(i)); } - } else if(addedEGLProfile) { - dumpGLInfo(eglFactory, device); - final List<GLCapabilitiesImmutable> availCaps = eglFactory.getAvailableCapabilities(device); + } else if(addedMobileProfile) { + dumpGLInfo(mobileFactory, device); + final List<GLCapabilitiesImmutable> availCaps = mobileFactory.getAvailableCapabilities(device); for(int i=0; i<availCaps.size(); i++) { System.err.println(availCaps.get(i)); } } } - return addedDesktopProfile || addedEGLProfile; + return addedDesktopProfile || addedMobileProfile; } private static void dumpGLInfo(final GLDrawableFactoryImpl factory, final AbstractGraphicsDevice device) { @@ -2106,7 +2128,7 @@ public class GLProfile { * Returns the profile implementation */ private static String computeProfileImpl(final AbstractGraphicsDevice device, final String profile, final boolean desktopCtxUndef, final boolean esCtxUndef, final boolean isHardwareRasterizer[]) { - final boolean hasAnyGL234Impl = hasGL234Impl || hasGL234OnEGLImpl; + final boolean hasAnyGL234Impl = hasGL234Impl || hasGL234OnMobileImpl; final boolean hardwareRasterizer[] = new boolean[1]; if ( GL2ES1 == profile ) { final boolean gles1Available; diff --git a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java index 560d99025..92511dc11 100644 --- a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java +++ b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java @@ -69,11 +69,12 @@ public class JoglVersion extends JogampVersion { return toString(gl, null).toString(); } - public static StringBuilder getAvailableCapabilitiesInfo(final GLDrawableFactory factory, final AbstractGraphicsDevice device, StringBuilder sb) { + public static StringBuilder getAvailableCapabilitiesInfo(final AbstractGraphicsDevice device, StringBuilder sb) { if(null==sb) { sb = new StringBuilder(); } boolean done = false; + final GLDrawableFactory factory = GLDrawableFactory.getFactory(device); if(null!=factory) { try { final List<GLCapabilitiesImmutable> availCaps = factory.getAvailableCapabilities(device); @@ -100,10 +101,12 @@ public class JoglVersion extends JogampVersion { device = GLProfile.getDefaultDevice(); } sb.append(Platform.getNewline()).append(Platform.getNewline()); - sb.append("Desktop Capabilities: ").append(Platform.getNewline()); - getAvailableCapabilitiesInfo(GLDrawableFactory.getDesktopFactory(), device, sb); - sb.append("EGL Capabilities: ").append(Platform.getNewline()); - getAvailableCapabilitiesInfo(GLDrawableFactory.getEGLFactory(), device, sb); + try { + sb.append("Capabilities for ").append(device.toString()).append(Platform.getNewline()); + getAvailableCapabilitiesInfo(device, sb); + } catch (final GLException gle) { + System.err.println(gle.getMessage()); + } return sb; } diff --git a/src/jogl/classes/jogamp/opengl/DummyGLExtProcAddressTable.java b/src/jogl/classes/jogamp/opengl/DummyGLExtProcAddressTable.java new file mode 100644 index 000000000..1cde06e3c --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/DummyGLExtProcAddressTable.java @@ -0,0 +1,61 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.opengl; + +import com.jogamp.gluegen.runtime.ProcAddressTable; +import com.jogamp.common.util.SecurityUtil; + +/** + * Representing the non-existing platform GL extension, i.e. a dummy type. + * <p> + * This table is a cache of pointers to the dynamically-linkable C library. + * </p> + * @see ProcAddressTable + */ +public final class DummyGLExtProcAddressTable extends ProcAddressTable { + + public DummyGLExtProcAddressTable(){ super(); } + + public DummyGLExtProcAddressTable(final com.jogamp.gluegen.runtime.FunctionAddressResolver resolver){ super(resolver); } + + @Override + protected boolean isFunctionAvailableImpl(final String functionNameUsr) throws IllegalArgumentException { + return false; + } + @Override + public long getAddressFor(final String functionNameUsr) throws SecurityException, IllegalArgumentException { + SecurityUtil.checkAllLinkPermission(); + final String functionNameBase = com.jogamp.gluegen.runtime.opengl.GLNameResolver.normalizeVEN(com.jogamp.gluegen.runtime.opengl.GLNameResolver.normalizeARB(functionNameUsr, true), true); + // The user is calling a bogus function or one which is not + // runtime linked + throw new RuntimeException( + "WARNING: Address field query failed for \"" + functionNameBase + "\"/\"" + functionNameUsr + + "\"; it's either statically linked or address field is not a known " + + "function"); + } +} diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 6866374bc..84c62b95d 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -2442,10 +2442,13 @@ public abstract class GLContextImpl extends GLContext { GLRendererQuirks.pushStickyDeviceQuirks(factoryDefaultDevice, quirks); } if( isES ) { - final AbstractGraphicsDevice eglFactoryDefaultDevice = GLDrawableFactory.getEGLFactory().getDefaultDevice(); - if( !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, adevice) && - !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, factoryDefaultDevice) ) { - GLRendererQuirks.pushStickyDeviceQuirks(eglFactoryDefaultDevice, quirks); + final GLDrawableFactory mobileFactory = GLDrawableFactory.getFactory(true); + if( null != factory ) { + final AbstractGraphicsDevice esFactoryDefaultDevice = mobileFactory.getDefaultDevice(); + if( !GLRendererQuirks.areSameStickyDevice(esFactoryDefaultDevice, adevice) && + !GLRendererQuirks.areSameStickyDevice(esFactoryDefaultDevice, factoryDefaultDevice) ) { + GLRendererQuirks.pushStickyDeviceQuirks(esFactoryDefaultDevice, quirks); + } } } } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index dfe6bdd9f..2e108d3ce 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -68,12 +68,16 @@ import com.jogamp.opengl.GLOffscreenAutoDrawable; import com.jogamp.opengl.GLProfile; import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.os.Platform; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.DelegatedUpstreamSurfaceHookWithSurfaceSize; +import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; import com.jogamp.opengl.GLAutoDrawableDelegate; import com.jogamp.opengl.GLRendererQuirks; +import jogamp.common.os.PlatformPropsImpl; + /** Extends GLDrawableFactory with a few methods for handling typically software-accelerated offscreen rendering (Device @@ -275,8 +279,18 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { GLDrawable result = null; adevice.lock(); try { + final boolean forceOnscreenFBOLayer; + final boolean useFBORendertarget; + if( chosenCaps.isOnscreen() && Platform.OSType.IOS == PlatformPropsImpl.OS_TYPE ) // FIXME: avoid hardcoding? + { + forceOnscreenFBOLayer = true; + useFBORendertarget = true; + } else { + forceOnscreenFBOLayer = false; + useFBORendertarget = false; + } final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(target, true); - if(null != ols) { + if(null != ols || forceOnscreenFBOLayer ) { final GLCapabilitiesImmutable chosenCapsMod = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(chosenCaps, this, adevice); // layered surface -> Offscreen/[FBO|PBuffer] @@ -284,12 +298,15 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { throw new GLException("Neither FBO nor Pbuffer is available for "+chosenCapsMod+", "+target); } config.setChosenCapabilities(chosenCapsMod); - ols.setChosenCapabilities(chosenCapsMod); + if( null != ols ) { + ols.setChosenCapabilities(chosenCapsMod); + } if(DEBUG) { System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer"); System.err.println("chosenCaps: "+chosenCaps); System.err.println("chosenCapsMod: "+chosenCapsMod); System.err.println("OffscreenLayerSurface: **** "+ols); + System.err.println("forceOnscreenFBOLayer: **** "+forceOnscreenFBOLayer+", useFBORendertarget "+useFBORendertarget); System.err.println("Target: **** "+target); ExceptionUtils.dumpStack(System.err); } @@ -297,7 +314,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target); } if( chosenCapsMod.isFBO() ) { - result = createFBODrawableImpl(target, chosenCapsMod, 0); + result = createFBODrawableImpl(target, chosenCapsMod, useFBORendertarget?-1:0); } else { result = createOffscreenDrawableImpl(target); } @@ -433,6 +450,60 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { new UpstreamSurfaceHookMutableSize(width, height) ) ); } + /** + * Quick path to produce a Surfaceless resizable FBO Drawable. + * <p> + * Caller has to be sure Surfaceless context as well as FBO is supported + * on the platform, no checks will be made. + * </p> + * @param device2Use actual device to be used + * @param capsRequested + * @param width + * @param height + */ + protected final GLFBODrawableImpl createSurfacelessFBODrawable(final AbstractGraphicsDevice device2Use, + final GLCapabilitiesImmutable capsRequested, + final int width, final int height) { + if(width<=0 || height<=0) { + throw new GLException("initial size must be positive (were (" + width + " x " + height + "))"); + } + final GLCapabilities capsChosen = (GLCapabilities) capsRequested.cloneMutable(); + { + capsChosen.setOnscreen(false); + capsChosen.setFBO( true ); + capsChosen.setPBuffer( false ); + capsChosen.setBitmap( false ); + } + // final ProxySurface surface = createSurfacelessImpl(device2Use, false, glCapsMin, capsRequested, null, width, height); + final GLCapabilitiesImmutable surfaceCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(capsRequested); + final ProxySurface surface = createMutableSurfaceImpl(device2Use, false /* createNewDevice */, surfaceCaps, capsRequested, null, new GenericUpstreamSurfacelessHook(width, height)); + + final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(surface); + return new GLFBODrawableImpl.ResizeableImpl(this, dummyDrawable, surface, capsChosen, 0); + } + /** + * Quick path to produce a Surfaceless Drawable. + * <p> + * Caller has to be sure Surfaceless context is supported + * on the platform, no checks will be made. + * </p> + * @param device2Use actual device to be used + * @param capsRequested + * @param width + * @param height + */ + protected final GLDrawableImpl createSurfacelessDrawable(final AbstractGraphicsDevice device2Use, + final GLCapabilitiesImmutable capsRequested, + final int width, final int height) { + if(width<=0 || height<=0) { + throw new GLException("initial size must be positive (were (" + width + " x " + height + "))"); + } + // final ProxySurface surface = createSurfacelessImpl(device2Use, false, glCapsMin, capsRequested, null, width, height); + final GLCapabilitiesImmutable surfaceCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(capsRequested); + final ProxySurface surface = createMutableSurfaceImpl(device2Use, false /* createNewDevice */, surfaceCaps, capsRequested, null, new GenericUpstreamSurfacelessHook(width, height)); + return createOnscreenDrawableImpl(surface); + } + @Override public final GLDrawable createDummyDrawable(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser) { final AbstractGraphicsDevice device = createNewDevice ? getOrCreateSharedDevice(deviceReq) : deviceReq; diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index cddaebe25..64cca7bdd 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -87,17 +87,17 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { * @param parent * @param surface * @param fboCaps the requested FBO capabilities - * @param textureUnit + * @param textureUnit if valid, i.e. >= 0, signals {@link #FBOMODE_USE_TEXTURE}, otherwise a color renderbuffer is assumed */ protected GLFBODrawableImpl(final GLDrawableFactoryImpl factory, final GLDrawableImpl parent, final NativeSurface surface, final GLCapabilitiesImmutable fboCaps, final int textureUnit) { super(factory, surface, fboCaps, false); this.initialized = false; - this.fboModeBits = FBOMODE_USE_TEXTURE; + this.fboModeBits = textureUnit>=0 ? FBOMODE_USE_TEXTURE : 0; this.parent = parent; this.origParentChosenCaps = getChosenGLCapabilities(); // just to avoid null, will be reset at initialize(..) - this.texUnit = textureUnit; + this.texUnit = textureUnit>=0 ? textureUnit : 0; this.samples = fboCaps.getNumSamples(); this.fboResetQuirk = false; this.swapBufferContext = null; diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGLnDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLGLnDynamicLibraryBundleInfo.java index 6a3a20100..b30a901f4 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGLnDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGLnDynamicLibraryBundleInfo.java @@ -59,7 +59,7 @@ public final class EGLGLnDynamicLibraryBundleInfo extends EGLDynamicLibraryBundl if( Platform.OSType.MACOS == osType ) { libsGL.add("/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"); libsGL.add("GL"); - } else if( Platform.OSType.WINDOWS == Platform.getOSType() ) { + } else if( Platform.OSType.WINDOWS == osType ) { libsGL.add("OpenGL32"); } else { // this is the default lib name, according to the spec diff --git a/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLContext.java b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLContext.java new file mode 100644 index 000000000..57c20d465 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLContext.java @@ -0,0 +1,477 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.opengl.ios.eagl; + +import java.util.Map; + +import com.jogamp.nativewindow.AbstractGraphicsConfiguration; +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.MutableGraphicsConfiguration; +import com.jogamp.nativewindow.OffscreenLayerSurface; +import com.jogamp.opengl.FBObject; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLContext; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLFBODrawable; +import com.jogamp.opengl.GLProfile; + +import jogamp.nativewindow.ios.IOSUtil; +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLDynamicLookupHelper; +import jogamp.opengl.GLFBODrawableImpl; +import jogamp.opengl.GLFBODrawableImpl.SwapBufferContext; +import jogamp.opengl.DummyGLExtProcAddressTable; +import jogamp.opengl.ios.eagl.IOSEAGLDrawable.GLBackendType; + +import com.jogamp.common.os.Platform; +import com.jogamp.gluegen.runtime.ProcAddressTable; +import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; +import com.jogamp.opengl.GLRendererQuirks; + +public class IOSEAGLContext extends GLContextImpl +{ + // Abstract interface for implementation of this context + protected interface GLBackendImpl { + /** Indicating CALayer, i.e. onscreen rendering using offscreen layer. */ + boolean isUsingCAEAGLLayer(); + long create(long share, int ctp, int major, int minor); + boolean destroy(long ctx); + void associateDrawable(boolean bound); + boolean makeCurrent(long ctx); + boolean release(long ctx); + } + + static boolean isGLProfileSupported(final int ctp, final int major, final int minor) { + if( 0 == ( CTX_PROFILE_ES & ctp ) ) { + // only ES profiles supported + return false; + } + return true; + } + static int GLProfile2EAGLProfileValue(final int ctp, final int major, final int minor) { + if(!isGLProfileSupported(ctp, major, minor)) { + throw new GLException("OpenGL profile not supported.0: "+getGLVersion(major, minor, ctp, "@GLProfile2EAGLProfileValue")); + } + switch( major ) { + case 1: + return EAGL.kEAGLRenderingAPIOpenGLES1; + case 2: + return EAGL.kEAGLRenderingAPIOpenGLES2; + case 3: + return EAGL.kEAGLRenderingAPIOpenGLES3; + } + throw new GLException("OpenGL profile not supported.1: "+getGLVersion(major, minor, ctp, "@GLProfile2EAGLProfileValue")); + } + + private boolean haveSetOpenGLMode = false; + private GLBackendType openGLMode = GLBackendType.CAEAGL_LAYER; + + // Implementation object (either NSOpenGL-based or CGL-based) + protected GLBackendImpl impl; + + // CGL extension functions. + private DummyGLExtProcAddressTable cglExtProcAddressTable; + + private int lastWidth, lastHeight; + + protected IOSEAGLContext(final GLDrawableImpl drawable, + final GLContext shareWith) { + super(drawable, shareWith); + initOpenGLImpl(getOpenGLMode()); + } + + @Override + protected void resetStates(final boolean isInit) { + // no inner state _cglExt = null; + super.resetStates(isInit); + } + + @Override + public Object getPlatformGLExtensions() { + return null; + } + + @Override + public final ProcAddressTable getPlatformExtProcAddressTable() { + return getCGLExtProcAddressTable(); + } + + public final DummyGLExtProcAddressTable getCGLExtProcAddressTable() { + return cglExtProcAddressTable; + } + + @Override + protected Map<String, String> getFunctionNameMap() { return null; } + + @Override + protected Map<String, String> getExtensionNameMap() { return null; } + + @Override + protected long createContextARBImpl(final long share, final boolean direct, final int ctp, final int major, final int minor) { + if(!isGLProfileSupported(ctp, major, minor)) { + if(DEBUG) { + System.err.println(getThreadName() + ": createContextARBImpl: Not supported "+getGLVersion(major, minor, ctp, "@creation on iOS "+Platform.getOSVersionNumber())); + } + return 0; + } + + // Will throw exception upon error + long ctx = impl.create(share, ctp, major, minor); + if(0 != ctx) { + if (!impl.makeCurrent(ctx)) { + if(DEBUG) { + System.err.println(getThreadName() + ": createContextARB couldn't make current "+getGLVersion(major, minor, ctp, "@creation")); + } + impl.release(ctx); + impl.destroy(ctx); + ctx = 0; + } else if(DEBUG) { + System.err.println(getThreadName() + ": createContextARBImpl: OK "+getGLVersion(major, minor, ctp, "@creation")+", share "+share+", direct "+direct+" on iOS "+Platform.getOSVersionNumber()); + } + } else if(DEBUG) { + System.err.println(getThreadName() + ": createContextARBImpl: NO "+getGLVersion(major, minor, ctp, "@creation on iOS "+Platform.getOSVersionNumber())); + } + return ctx; + } + + @Override + protected void destroyContextARBImpl(final long _context) { + impl.release(_context); + impl.destroy(_context); + } + + @Override + public final boolean isGLReadDrawableAvailable() { + return false; + } + + @Override + protected boolean createImpl(final long shareWithHandle) throws GLException { + final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); + final AbstractGraphicsDevice device = config.getScreen().getDevice(); + final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final GLProfile glp = glCaps.getGLProfile(); + final boolean createContextARBAvailable = isCreateContextARBAvail(device); + if(DEBUG) { + System.err.println(getThreadName() + ": IOSEAGLContext.createImpl: START "+glCaps+", share "+toHexString(shareWithHandle)); + System.err.println(getThreadName() + ": Use ARB[avail["+getCreateContextARBAvailStr(device)+ + "] -> "+createContextARBAvailable+"]]"); + } + if( !glp.isGLES() ) { + throw new GLException("Desktop OpenGL profile not supported on iOS "+Platform.getOSVersionNumber()+": "+glp); + } + contextHandle = createContextARB(shareWithHandle, true); + return 0 != contextHandle; + } + + @Override + protected void makeCurrentImpl() throws GLException { + /** FIXME: won't work w/ special drawables (like FBO) - check for CGL mode regressions! + * + if (getOpenGLMode() != ((IOSEAGLDrawable)drawable).getOpenGLMode()) { + setOpenGLMode(((IOSEAGLDrawable)drawable).getOpenGLMode()); + } */ + if ( !impl.makeCurrent(contextHandle) ) { + throw new GLException("Error making Context current: "+this); + } + drawableUpdatedNotify(); + } + + @Override + protected void releaseImpl() throws GLException { + if (!impl.release(contextHandle)) { + throw new GLException("Error releasing OpenGL Context: "+this); + } + } + + @Override + protected void destroyImpl() throws GLException { + if(!impl.destroy(contextHandle)) { + throw new GLException("Error destroying OpenGL Context: "+this); + } + } + + @Override + protected void drawableUpdatedNotify() throws GLException { + if( drawable.getChosenGLCapabilities().isOnscreen() ) { + final int w = drawable.getSurfaceWidth(); + final int h = drawable.getSurfaceHeight(); + // final boolean sizeChanged = w != lastWidth || h != lastHeight; + if(drawable instanceof GLFBODrawable) { + final GLFBODrawable fbod = (GLFBODrawable) drawable; + final FBObject.Colorbuffer col = fbod.getColorbuffer(GL.GL_FRONT); // FIXME GL_BACK swap .. + final int renderbuffer = col.getName(); + EAGL.eaglPresentRenderbuffer(contextHandle, renderbuffer); + } + // TODO: Check for resize ... + lastWidth = w; + lastHeight = h; + } + } + + @Override + protected void associateDrawable(final boolean bound) { + // context stuff depends on drawable stuff + if(bound) { + final GLDrawableImpl drawable = getDrawableImpl(); + if( drawable instanceof GLFBODrawableImpl ) { + final GLFBODrawableImpl fboDrawable = (GLFBODrawableImpl) drawable; + fboDrawable.setSwapBufferContext(new SwapBufferContext() { + @Override + public void swapBuffers(final boolean doubleBuffered) { + EAGL.eaglPresentRenderbuffer(contextHandle, GL.GL_RENDERBUFFER); + } } ); + } + // FIXME: Need better way to inject the IOS EAGL Layer into FBObject + // FIXME: May want to implement optional injection of a BufferStorage SPI? + // FBObject.ColorAttachment.initialize(GL): EAGL.eaglBindDrawableStorageToRenderbuffer(contextHandle, GL.GL_RENDERBUFFER, eaglLayer); + final long eaglLayer = IOSUtil.GetCAEAGLLayer(drawable.getNativeSurface().getSurfaceHandle()); + System.err.println("EAGL: Ctx attach EAGLLayer 0x"+Long.toHexString(eaglLayer)); + attachObject("IOS_EAGL_LAYER", new Long(eaglLayer)); + + super.associateDrawable(true); // 1) init drawable stuff (FBO init, ..) + impl.associateDrawable(true); // 2) init context stuff + } else { + impl.associateDrawable(false); // 1) free context stuff + super.associateDrawable(false); // 2) free drawable stuff + + EAGL.eaglBindDrawableStorageToRenderbuffer(contextHandle, GL.GL_RENDERBUFFER, 0); + detachObject("IOS_EAGL_LAYER"); + } + } + + @Override + protected void copyImpl(final GLContext source, final int mask) throws GLException { + throw new GLException("copyImpl n/a: "+this); + } + + /** + * {@inheritDoc} + * <p> + * Ignoring {@code contextFQN}, using {@code iOS}-{@link AbstractGraphicsDevice#getUniqueID()}. + * </p> + */ + @Override + protected final void updateGLXProcAddressTable(final String contextFQN, final GLDynamicLookupHelper dlh) { + if( null == dlh ) { + throw new GLException("No GLDynamicLookupHelper for "+this); + } + final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); + final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); + final String key = "iOS-"+adevice.getUniqueID(); + if (DEBUG) { + System.err.println(getThreadName() + ": Initializing EAGL extension address table: "+key); + } + ProcAddressTable table = null; + synchronized(mappedContextTypeObjectLock) { + table = mappedGLXProcAddress.get( key ); + } + if(null != table) { + cglExtProcAddressTable = (DummyGLExtProcAddressTable) table; + if(DEBUG) { + System.err.println(getThreadName() + ": GLContext CGL ProcAddressTable reusing key("+key+") -> "+toHexString(table.hashCode())); + } + } else { + cglExtProcAddressTable = new DummyGLExtProcAddressTable(new GLProcAddressResolver()); + resetProcAddressTable(getCGLExtProcAddressTable(), dlh); + synchronized(mappedContextTypeObjectLock) { + mappedGLXProcAddress.put(key, getCGLExtProcAddressTable()); + if(DEBUG) { + System.err.println(getThreadName() + ": GLContext CGL ProcAddressTable mapping key("+key+") -> "+toHexString(getCGLExtProcAddressTable().hashCode())); + } + } + } + } + + @Override + protected final StringBuilder getPlatformExtensionsStringImpl() { + return new StringBuilder(); + } + + // Support for "mode switching" as described in IOSEAGLDrawable + public void setOpenGLMode(final GLBackendType mode) { + if (mode == openGLMode) { + return; + } + if (haveSetOpenGLMode) { + throw new GLException("Can't switch between using EAGL and ... more than once"); + } + destroyImpl(); + ((IOSEAGLDrawable)drawable).setOpenGLMode(mode); + if (DEBUG) { + System.err.println("IOSEAGLContext: Switching context mode " + openGLMode + " -> " + mode); + } + initOpenGLImpl(mode); + openGLMode = mode; + haveSetOpenGLMode = true; + } + public final GLBackendType getOpenGLMode() { return openGLMode; } + + protected void initOpenGLImpl(final GLBackendType backend) { + switch (backend) { + case CAEAGL_LAYER: + impl = new CAEAGLLayerImpl(); + break; + default: + throw new InternalError("Illegal implementation mode " + backend); + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + super.append(sb); + sb.append("] "); + return sb.toString(); + } + + class CAEAGLLayerImpl implements GLBackendImpl { + private final OffscreenLayerSurface backingLayerHost = null; + + @Override + public boolean isUsingCAEAGLLayer() { return null != backingLayerHost; } + + /** Only returns a valid UIView. If !UIView, return null and mark isFBO or isSurfaceless. */ + private long getUIViewHandle(final boolean[] isFBO, final boolean[] isSurfaceless) { + final long uiViewHandle; + if(drawable instanceof GLFBODrawableImpl) { + uiViewHandle = 0; + isFBO[0] = true; + isSurfaceless[0] = false; + if(DEBUG) { + System.err.println("UI viewHandle.1: GLFBODrawableImpl drawable: isFBO "+isFBO[0]+", isSurfaceless "+isSurfaceless[0]+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + } else { + final long drawableHandle = drawable.getHandle(); + final boolean isUIView = IOSUtil.isUIView(drawableHandle); + final boolean isUIWindow = IOSUtil.isUIWindow(drawableHandle); + isFBO[0] = false; + isSurfaceless[0] = false; + + if( isUIView ) { + uiViewHandle = drawableHandle; + } else if( isUIWindow ) { + uiViewHandle = IOSUtil.GetUIView(drawableHandle, true /* only EAGL */); + } else if( isSurfaceless() ) { + isSurfaceless[0] = true; + uiViewHandle = 0; + } else { + throw new GLException("Drawable's handle neither NSView, NSWindow nor PBuffer: drawableHandle "+toHexString(drawableHandle)+", isNSView "+isUIView+", isNSWindow "+isUIWindow+", isFBO "+isFBO[0]+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + if(DEBUG) { + System.err.println("NS viewHandle.2: drawableHandle "+toHexString(drawableHandle)+" -> nsViewHandle "+toHexString(uiViewHandle)+": isNSView "+isUIView+", isNSWindow "+isUIWindow+", isFBO "+isFBO[0]+", isSurfaceless "+isSurfaceless[0]+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + } + return uiViewHandle; + } + + @Override + public long create(final long share, final int ctp, final int major, final int minor) { + long ctx = 0; + final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); + final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + // Create new context + if (DEBUG) { + System.err.println("Share context for EAGL-based context is " + toHexString(share)); + } + final boolean isFBO = drawable instanceof GLFBODrawableImpl; + final int api = GLProfile2EAGLProfileValue(ctp, major, minor); + if( 0 != share ) { + ctx = EAGL.eaglCreateContextShared(api, EAGL.eaglGetSharegroup(share)); + } else { + ctx = EAGL.eaglCreateContext(api); + } + if (0 != ctx) { + final GLCapabilitiesImmutable fixedCaps; + if( isFBO ) { + fixedCaps = chosenCaps; + } else { + if( DEBUG ) { + System.err.println("Warning: CAEAGLLayer w/ non FBO caps"); + } + fixedCaps = chosenCaps; + } + if(DEBUG) { + System.err.println("NS create backingLayerHost: "+backingLayerHost); + System.err.println("NS create share: "+share); + System.err.println("NS create drawable type: "+drawable.getClass().getName()); + System.err.println("NS create chosenCaps: "+chosenCaps); + System.err.println("NS create fixedCaps: "+fixedCaps); + System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle())); + System.err.println("NS create surface native-handle: "+toHexString(drawable.getNativeSurface().getSurfaceHandle())); + // Thread.dumpStack(); + } + config.setChosenCapabilities(fixedCaps); + if(DEBUG) { + System.err.println("EAGL create fixedCaps: "+fixedCaps); + } + } + return ctx; + } + + @Override + public boolean destroy(final long ctx) { + return EAGL.eaglDeleteContext(ctx, true /* releaseOnMainThread */); + } + + @Override + public void associateDrawable(final boolean bound) { + } + + @Override + public boolean makeCurrent(final long ctx) { + return EAGL.eaglMakeCurrentContext(ctx); + } + + @Override + public boolean release(final long ctx) { + try { + if( hasRendererQuirk(GLRendererQuirks.GLFlushBeforeRelease) && null != IOSEAGLContext.this.getGLProcAddressTable() ) { + gl.glFlush(); + } + } catch (final GLException gle) { + if(DEBUG) { + System.err.println("IOSEAGLContext.CGLImpl.release: INFO: glFlush() caught exception:"); + gle.printStackTrace(); + } + } + return EAGL.eaglMakeCurrentContext(0); + } + } + + @Override + protected Integer setSwapIntervalImpl2(final int interval) { + // TODO + return null; + } +} diff --git a/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDrawable.java b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDrawable.java new file mode 100644 index 000000000..a851e60c6 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDrawable.java @@ -0,0 +1,90 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.opengl.ios.eagl; + +import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLContext; +import com.jogamp.opengl.GLDrawableFactory; +import com.jogamp.opengl.GLException; + +import jogamp.opengl.GLDrawableImpl; + +public abstract class IOSEAGLDrawable extends GLDrawableImpl { + public enum GLBackendType { + /** Default OpenGL Backend */ + CAEAGL_LAYER(0); + + public final int id; + + GLBackendType(final int id){ + this.id = id; + } + } + + private boolean haveSetOpenGLMode = false; + private GLBackendType openGLMode = GLBackendType.CAEAGL_LAYER; + + public IOSEAGLDrawable(final GLDrawableFactory factory, final NativeSurface comp, final boolean realized) { + super(factory, comp, realized); + initOpenGLImpl(getOpenGLMode()); + } + + @Override + protected void setRealizedImpl() { + } + + @Override + protected void associateContext(final GLContext ctx, final boolean bound) { + } + + @Override + protected final void swapBuffersImpl(final boolean doubleBuffered) { + } + + // Support for "mode switching" as described in MacOSXCGLDrawable + public void setOpenGLMode(final GLBackendType mode) { + if (mode == openGLMode) { + return; + } + if (haveSetOpenGLMode) { + throw new GLException("Can't switch between using NSOpenGLPixelBuffer and CGLPBufferObj more than once"); + } + setRealized(false); + if (DEBUG) { + System.err.println("MacOSXCGLDrawable: Switching context mode " + openGLMode + " -> " + mode); + } + initOpenGLImpl(mode); + openGLMode = mode; + haveSetOpenGLMode = true; + } + public final GLBackendType getOpenGLMode() { return openGLMode; } + + protected void initOpenGLImpl(final GLBackendType backend) { /* nop */ } + +} diff --git a/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDrawableFactory.java new file mode 100644 index 000000000..3c3f1edb8 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDrawableFactory.java @@ -0,0 +1,453 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.opengl.ios.eagl; + +import java.nio.Buffer; +import java.nio.ShortBuffer; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.nativewindow.DefaultGraphicsScreen; +import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.nativewindow.ProxySurface; +import com.jogamp.nativewindow.UpstreamSurfaceHook; +import com.jogamp.nativewindow.ios.IOSGraphicsDevice; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLCapabilitiesChooser; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLContext; +import com.jogamp.opengl.GLDrawable; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLProfile; + +import jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.ios.IOSDummyUpstreamSurfaceHook; +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLDrawableFactoryImpl; +import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLDynamicLookupHelper; +import jogamp.opengl.GLGraphicsConfigurationUtil; +import jogamp.opengl.SharedResourceRunner; + +import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; +import com.jogamp.opengl.GLExtensions; +import com.jogamp.opengl.GLRendererQuirks; + +public class IOSEAGLDrawableFactory extends GLDrawableFactoryImpl { + private static final boolean DEBUG_SHAREDCTX = DEBUG || GLContext.DEBUG; + + private static GLDynamicLookupHelper iosEAGLDynamicLookupHelper = null; + + public IOSEAGLDrawableFactory() { + super(); + + synchronized(IOSEAGLDrawableFactory.class) { + if(null==iosEAGLDynamicLookupHelper) { + GLDynamicLookupHelper tmp = null; + try { + tmp = new GLDynamicLookupHelper(new IOSEAGLDynamicLibraryBundleInfo()); + } catch (final GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } + } + if(null!=tmp && tmp.isLibComplete()) { + iosEAGLDynamicLookupHelper = tmp; + } + } + } + + defaultDevice = new IOSGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + + if(null!=iosEAGLDynamicLookupHelper) { + // Register our GraphicsConfigurationFactory implementations + // The act of constructing them causes them to be registered + IOSEAGLGraphicsConfigurationFactory.registerFactory(); + sharedMap = new HashMap<String, SharedResource>(); + } + } + + @Override + protected final boolean isComplete() { + return null != iosEAGLDynamicLookupHelper; + } + + @Override + protected final void shutdownImpl() { + if( DEBUG ) { + System.err.println("IOSEAGLDrawableFactory.shutdown"); + } + if(null != sharedMap) { + sharedMap.clear(); + sharedMap = null; + } + defaultDevice = null; + /** + * Pulling away the native library may cause havoc .. + * + macOSXCGLDynamicLookupHelper.destroy(); + */ + iosEAGLDynamicLookupHelper = null; + } + + @Override + public final GLDynamicLookupHelper getGLDynamicLookupHelper(final int majorVersion, final int contextOptions) { + return iosEAGLDynamicLookupHelper; + } + + private HashMap<String, SharedResource> sharedMap = new HashMap<String, SharedResource>(); + private IOSGraphicsDevice defaultDevice; + + static class SharedResource implements SharedResourceRunner.Resource { + // private IOSEAGLDrawable drawable; + // private IOSEAGLContext context; + private final GLRendererQuirks glRendererQuirks; + IOSGraphicsDevice device; + boolean valid; + boolean hasNPOTTextures; + boolean hasRECTTextures; + boolean hasAppleFloatPixels; + + SharedResource(final IOSGraphicsDevice device, final boolean valid, + final boolean hasNPOTTextures, final boolean hasRECTTextures, final boolean hasAppletFloatPixels + /* IOSEAGLDrawable draw, IOSEAGLContext ctx */, final GLRendererQuirks glRendererQuirks) { + // drawable = draw; + // this.context = ctx; + this.glRendererQuirks = glRendererQuirks; + this.device = device; + this.valid = valid; + this.hasNPOTTextures = hasNPOTTextures; + this.hasRECTTextures = hasRECTTextures; + this.hasAppleFloatPixels = hasAppletFloatPixels; + } + @Override + public final boolean isAvailable() { + return valid; + } + @Override + public final IOSGraphicsDevice getDevice() { return device; } + // final IOSEAGLContext getContext() { return context; } + final boolean isNPOTTextureAvailable() { return hasNPOTTextures; } + final boolean isRECTTextureAvailable() { return hasRECTTextures; } + final boolean isAppleFloatPixelsAvailable() { return hasAppleFloatPixels; } + @Override + public final AbstractGraphicsScreen getScreen() { + return null; + } + @Override + public final GLDrawableImpl getDrawable() { + return null; + } + @Override + public GLContextImpl getContext() { + return null; + } + @Override + public GLRendererQuirks getRendererQuirks(final GLProfile glp) { + return glRendererQuirks; + } + } + + @Override + public final AbstractGraphicsDevice getDefaultDevice() { + return defaultDevice; + } + + @Override + public final boolean getIsDeviceCompatible(final AbstractGraphicsDevice device) { + if(null!=iosEAGLDynamicLookupHelper && device instanceof IOSGraphicsDevice) { + return true; + } + return false; + } + + private final HashSet<String> devicesTried = new HashSet<String>(); + + private boolean getDeviceTried(final String connection) { + synchronized (devicesTried) { + return devicesTried.contains(connection); + } + } + private void addDeviceTried(final String connection) { + synchronized (devicesTried) { + devicesTried.add(connection); + } + } + private void removeDeviceTried(final String connection) { + synchronized (devicesTried) { + devicesTried.remove(connection); + } + } + + @Override + protected final SharedResource getOrCreateSharedResourceImpl(final AbstractGraphicsDevice adevice) { + final String connection = adevice.getConnection(); + SharedResource sr; + synchronized(sharedMap) { + sr = sharedMap.get(connection); + } + if(null==sr && !getDeviceTried(connection)) { + addDeviceTried(connection); + final IOSGraphicsDevice device = new IOSGraphicsDevice(adevice.getUnitID()); + GLDrawable drawable = null; + GLDrawable zeroDrawable = null; + GLContextImpl context = null; + boolean contextIsCurrent = false; + device.lock(); + try { + final GLProfile glp = GLProfile.get(device, GLProfile.GL_PROFILE_LIST_MAX_MOBILE, false); + if (null == glp) { + throw new GLException("Couldn't get default GLProfile for device: "+device); + } + final GLCapabilitiesImmutable caps = new GLCapabilities(glp); + // drawable = createSurfacelessFBODrawable(device, caps, 64, 64); + drawable = createSurfacelessDrawable(device, caps, 64, 64); + + drawable.setRealized(true); + + context = (IOSEAGLContext) drawable.createContext(null); + if (null == context) { + throw new GLException("Couldn't create shared context for drawable: "+drawable); + } + contextIsCurrent = GLContext.CONTEXT_NOT_CURRENT != context.makeCurrent(); + + final boolean allowsSurfacelessCtx; + final boolean hasNPOTTextures; + final boolean hasRECTTextures; + final boolean hasAppleFloatPixels; + final GLRendererQuirks glRendererQuirks; + if( contextIsCurrent ) { + // We allow probing surfaceless for even the compatible 2.1 context, + // which we probably have right here - since OSX may support this. + // Otherwise, we cannot map the quirk to the device. + if( probeSurfacelessCtx(context, false /* restoreDrawable */) ) { + allowsSurfacelessCtx = true; + zeroDrawable = context.getGLDrawable(); + } else { + allowsSurfacelessCtx = false; + } + final GL gl = context.getGL(); + hasNPOTTextures = gl.isNPOTTextureAvailable(); + hasRECTTextures = gl.isExtensionAvailable(GLExtensions.EXT_texture_rectangle); + hasAppleFloatPixels = gl.isExtensionAvailable(GLExtensions.APPLE_float_pixels); + glRendererQuirks = context.getRendererQuirks(); + } else { + allowsSurfacelessCtx = false; + hasNPOTTextures = false; + hasRECTTextures = false; + hasAppleFloatPixels = false; + glRendererQuirks = null; + } + sr = new SharedResource(device, contextIsCurrent, hasNPOTTextures, hasRECTTextures, hasAppleFloatPixels, glRendererQuirks); + if ( DEBUG_SHAREDCTX ) { + System.err.println("SharedDevice: " + device); + System.err.println("SharedContext: " + context + ", madeCurrent " + contextIsCurrent); + System.err.println(" NPOT "+hasNPOTTextures+", RECT "+hasRECTTextures+", FloatPixels "+hasAppleFloatPixels); + System.err.println(" allowsSurfacelessCtx "+allowsSurfacelessCtx); + System.err.println(" glRendererQuirks "+glRendererQuirks); + } + synchronized(sharedMap) { + sharedMap.put(connection, sr); + } + } catch (final Throwable t) { + throw new GLException("IOSEAGLDrawableFactory - Could not initialize shared resources for "+adevice, t); + } finally { + if( null != context ) { + try { + context.destroy(); + } catch (final GLException gle) { + if ( DEBUG_SHAREDCTX ) { + System.err.println("IOSEAGLDrawableFactory.createShared: INFO: destroy caught exception:"); + gle.printStackTrace(); + } + } + } + if( null != zeroDrawable ) { + zeroDrawable.setRealized(false); + } + if( null != drawable ) { + drawable.setRealized(false); + } + device.unlock(); + removeDeviceTried(connection); + } + } + return sr; + } + + @Override + protected final Thread getSharedResourceThread() { + return null; + } + + /** + * {@inheritDoc} + * <p> + * This factory never supports native desktop OpenGL profiles. + * </p> + */ + @Override + public final boolean hasOpenGLDesktopSupport() { return false; } + + /** + * {@inheritDoc} + * <p> + * This factory always supports native GLES profiles. + * </p> + */ + @Override + public final boolean hasOpenGLESSupport() { return true; } + + /** + * {@inheritDoc} + * <p> + * Always returns false. + * </p> + */ + @Override + public final boolean hasMajorMinorCreateContextARB() { return false; } + + @Override + protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(final AbstractGraphicsDevice device) { + return IOSEAGLGraphicsConfiguration.getAvailableCapabilities(this, device); + } + + @Override + protected GLDrawableImpl createOnscreenDrawableImpl(final NativeSurface target) { + if (target == null) { + throw new IllegalArgumentException("Null target"); + } + return new IOSOnscreenEAGLDrawable(this, target); + } + + @Override + protected GLDrawableImpl createOffscreenDrawableImpl(final NativeSurface target) { + throw new GLException("Only FBO is supported for offscreen"); + } + + @Override + public boolean canCreateGLPbuffer(final AbstractGraphicsDevice device, final GLProfile glp) { + return false; + } + + @Override + protected ProxySurface createMutableSurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested, + final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstreamHook) { + final IOSGraphicsDevice device; + if( createNewDevice || !(deviceReq instanceof IOSGraphicsDevice) ) { + device = new IOSGraphicsDevice(deviceReq.getUnitID()); + } else { + device = (IOSGraphicsDevice)deviceReq; + } + final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, 0); + final IOSEAGLGraphicsConfiguration config = IOSEAGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, true); + if(null == config) { + throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); + } + return new WrappedSurface(config, 0, upstreamHook, createNewDevice); + } + + @Override + public final ProxySurface createDummySurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { + chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, + new IOSDummyUpstreamSurfaceHook(width, height)); + } + + @Override + public final ProxySurface createSurfacelessImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { + chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new GenericUpstreamSurfacelessHook(width, height)); + } + + @Override + protected ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstream) { + final IOSGraphicsDevice device = new IOSGraphicsDevice(deviceReq.getUnitID()); + final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); + final IOSEAGLGraphicsConfiguration config = IOSEAGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, true); + return new WrappedSurface(config, windowHandle, upstream, true); + } + + @Override + protected GLContext createExternalGLContextImpl() { + throw new GLException("Not implemented"); + } + + @Override + public boolean canCreateExternalGLDrawable(final AbstractGraphicsDevice device) { + return false; + } + + @Override + protected GLDrawable createExternalGLDrawableImpl() { + throw new GLException("Not implemented"); + } + + //------------------------------------------------------ + // Gamma-related functionality + // + + private static final int GAMMA_RAMP_LENGTH = 256; + + /** Returns the length of the computed gamma ramp for this OS and + hardware. Returns 0 if gamma changes are not supported. */ + @Override + protected int getGammaRampLength(final NativeSurface surface) { + return GAMMA_RAMP_LENGTH; + } + + @Override + protected boolean setGammaRamp(final NativeSurface surface, final float[] ramp) { + // final FloatBuffer rampNIO = Buffers.newDirectFloatBuffer(ramp); + return false; // TODO CGL.setGammaRamp(ramp.length, rampNIO, rampNIO, rampNIO); + } + + @Override + protected Buffer getGammaRamp(final NativeSurface surface) { + return ShortBuffer.allocate(0); // return a dummy gamma ramp default for reset + } + + @Override + protected void resetGammaRamp(final NativeSurface surface, final Buffer originalGammaRamp) { + // TODO CGL.resetGammaRamp(); + } + + @Override + protected final void resetGammaRamp(final DeviceScreenID deviceScreenID, final Buffer originalGammaRamp) { + // TODO CGL.resetGammaRamp(); + } + +} diff --git a/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDynamicLibraryBundleInfo.java new file mode 100644 index 000000000..c418cd682 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLDynamicLibraryBundleInfo.java @@ -0,0 +1,83 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.opengl.ios.eagl; + +import java.util.ArrayList; +import java.util.List; + +import jogamp.opengl.GLDynamicLibraryBundleInfo; + +public final class IOSEAGLDynamicLibraryBundleInfo extends GLDynamicLibraryBundleInfo { + private static final List<String> glueLibNames; + static { + glueLibNames = new ArrayList<String>(); + glueLibNames.add("jogl_mobile"); + } + protected IOSEAGLDynamicLibraryBundleInfo() { + super(); + } + + @Override + public boolean shallLookupGlobal() { return true; } + + @Override + public final List<List<String>> getToolLibNames() { + final List<List<String>> libsList = new ArrayList<List<String>>(); + final List<String> libsGL = new ArrayList<String>(); + libsGL.add("OpenGLES"); // actually used '/Library/Frameworks/OpenGLES.framework/OpenGLES' + libsList.add(libsGL); + return libsList; + } + + @Override + public final List<String> getToolGetProcAddressFuncNameList() { + return null; + /** OSX manual says: NSImage use is discouraged + List res = new ArrayList(); + res.add("GetProcAddress"); // dummy + return res; */ + } + + @Override + public final long toolGetProcAddress(final long toolGetProcAddressHandle, final String funcName) { + // return EAGL.getProcAddress(funcName); + return 0; + } + + @Override + public final List<String> getGlueLibNames() { + return glueLibNames; + } + + @Override + public boolean useToolGetProcAdressFirst(final String funcName) { + return true; + } +} + diff --git a/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLGraphicsConfiguration.java new file mode 100644 index 000000000..18e597065 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLGraphicsConfiguration.java @@ -0,0 +1,62 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.opengl.ios.eagl; + +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLException; + +import com.jogamp.nativewindow.MutableGraphicsConfiguration; + +public class IOSEAGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { + + IOSEAGLGraphicsConfiguration(final AbstractGraphicsScreen screen, + final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested) { + super(screen, capsChosen, capsRequested); + } + + @Override + public Object clone() { + return super.clone(); + } + + protected static List<GLCapabilitiesImmutable> getAvailableCapabilities(final IOSEAGLDrawableFactory factory, final AbstractGraphicsDevice device) { + final IOSEAGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResourceImpl(device); + if(null == sharedResource) { + throw new GLException("Shared resource for device n/a: "+device); + } + // MacOSXGraphicsDevice osxDevice = sharedResource.getDevice(); + return new ArrayList<GLCapabilitiesImmutable>(0); + } +} + diff --git a/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLGraphicsConfigurationFactory.java new file mode 100644 index 000000000..3a4f1a354 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSEAGLGraphicsConfigurationFactory.java @@ -0,0 +1,87 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.opengl.ios.eagl; + +import jogamp.opengl.GLGraphicsConfigurationFactory; +import jogamp.opengl.GLGraphicsConfigurationUtil; + +import com.jogamp.nativewindow.AbstractGraphicsConfiguration; +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.nativewindow.CapabilitiesChooser; +import com.jogamp.nativewindow.CapabilitiesImmutable; +import com.jogamp.nativewindow.GraphicsConfigurationFactory; +import com.jogamp.opengl.GLCapabilitiesChooser; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLDrawableFactory; + + +public class IOSEAGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { + static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(com.jogamp.nativewindow.ios.IOSGraphicsDevice.class, GLCapabilitiesImmutable.class, new IOSEAGLGraphicsConfigurationFactory()); + } + private IOSEAGLGraphicsConfigurationFactory() { + } + + @Override + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final CapabilitiesChooser chooser, final AbstractGraphicsScreen absScreen, final int nativeVisualID) { + + if (absScreen == null) { + throw new IllegalArgumentException("AbstractGraphicsScreen is null"); + } + + if (! (capsChosen instanceof GLCapabilitiesImmutable) ) { + throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilities objects - chosen"); + } + + if (! (capsRequested instanceof GLCapabilitiesImmutable) ) { + throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilities objects - requested"); + } + + if (chooser != null && !(chooser instanceof GLCapabilitiesChooser)) { + throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilitiesChooser objects"); + } + + return chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, (GLCapabilitiesChooser)chooser, absScreen, false); + } + + static IOSEAGLGraphicsConfiguration chooseGraphicsConfigurationStatic(GLCapabilitiesImmutable capsChosen, + final GLCapabilitiesImmutable capsRequested, + final GLCapabilitiesChooser chooser, + final AbstractGraphicsScreen absScreen, final boolean usePBuffer) { + if (absScreen == null) { + throw new IllegalArgumentException("AbstractGraphicsScreen is null"); + } + final AbstractGraphicsDevice device = absScreen.getDevice(); + capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, GLDrawableFactory.getDesktopFactory(), device); + + return new IOSEAGLGraphicsConfiguration(absScreen, capsChosen, capsRequested); + } +} diff --git a/src/jogl/classes/jogamp/opengl/ios/eagl/IOSOnscreenEAGLDrawable.java b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSOnscreenEAGLDrawable.java new file mode 100644 index 000000000..04b80a858 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/ios/eagl/IOSOnscreenEAGLDrawable.java @@ -0,0 +1,45 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.opengl.ios.eagl; + +import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.opengl.GLContext; +import com.jogamp.opengl.GLDrawableFactory; + +public class IOSOnscreenEAGLDrawable extends IOSEAGLDrawable { + + protected IOSOnscreenEAGLDrawable(final GLDrawableFactory factory, final NativeSurface component) { + super(factory, component, false); + } + + @Override + public GLContext createContext(final GLContext shareWith) { + return new IOSEAGLContext(this, shareWith); + } + +} diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java index 5cf4f36a1..c5fc4e74a 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java @@ -42,6 +42,7 @@ public final class MacOSXCGLDynamicLibraryBundleInfo extends DesktopGLDynamicLib public final List<List<String>> getToolLibNames() { final List<List<String>> libsList = new ArrayList<List<String>>(); final List<String> libsGL = new ArrayList<String>(); + // libsGL.add("OpenGL"); // Actual canonical lib. TODO re-validate? libsGL.add("/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"); libsGL.add("GL"); libsList.add(libsGL); diff --git a/src/jogl/native/JVM_JNI8.c b/src/jogl/native/JVM_JNI8.c new file mode 100644 index 000000000..1131088cf --- /dev/null +++ b/src/jogl/native/JVM_JNI8.c @@ -0,0 +1,43 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include <stdio.h> //required by android to identify NULL +#include <jni.h> + +#if defined (JNI_VERSION_1_8) + +JNIEXPORT jint JNICALL JNI_OnLoad_jogl_mobile(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } +JNIEXPORT jint JNICALL JNI_OnLoad_jogl_desktop(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } +JNIEXPORT jint JNICALL JNI_OnLoad_jogl_cg(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } + +JNIEXPORT void JNICALL JNI_OnUnload_jogl_mobile(JavaVM *vm, void *reserved) { } +JNIEXPORT void JNICALL JNI_OnUnload_jogl_desktop(JavaVM *vm, void *reserved) { } +JNIEXPORT void JNICALL JNI_OnUnload_jogl_cg(JavaVM *vm, void *reserved) { } + +#endif /* defined (JNI_VERSION_1_8) */ + diff --git a/src/jogl/native/ios/IOSWindowSystemInterface.h b/src/jogl/native/ios/IOSWindowSystemInterface.h new file mode 100644 index 000000000..c50a663a0 --- /dev/null +++ b/src/jogl/native/ios/IOSWindowSystemInterface.h @@ -0,0 +1,42 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +#import <UIKit/UIKit.h> +#import <OpenGLES/EAGL.h> +#import <jni.h> + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +#import "ios-window-system.h" + diff --git a/src/jogl/native/ios/IOSWindowSystemInterface.m b/src/jogl/native/ios/IOSWindowSystemInterface.m new file mode 100644 index 000000000..95c10c269 --- /dev/null +++ b/src/jogl/native/ios/IOSWindowSystemInterface.m @@ -0,0 +1,119 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +#include <AvailabilityMacros.h> + +#import "IOSWindowSystemInterface.h" + +EAGLContext * eaglCreateContext(EAGLRenderingAPI api) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT("createEAGLContext.0: api %d\n", api); + + EAGLContext* ctx = [[EAGLContext alloc] initWithAPI:api]; + + DBG_PRINT("createEAGLContext.X: ctx: %p\n", ctx); + [pool release]; + return ctx; +} + +EAGLContext * eaglCreateContextShared(EAGLRenderingAPI api, EAGLSharegroup* sharegroup) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT("createEAGLContext.0: api %d, sharegroup %p\n", api, sharegroup); + + EAGLContext* ctx = [[EAGLContext alloc] initWithAPI:api sharegroup:sharegroup]; + + DBG_PRINT("createEAGLContext.X: ctx: %p\n", ctx); + [pool release]; + return ctx; +} + +Bool eaglDeleteContext(EAGLContext *ctx, Bool releaseOnMainThread) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT("deleteEAGLContext.0: ctx %p, releaseOnMainThread %d\n", ctx, releaseOnMainThread); + if(releaseOnMainThread && NO == [NSThread isMainThread]) { + [ctx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; + } else { + // ??? On OSX would hangs for ~10s for 1 of a shared context set or offscreen context, set releaseOnMainThread=true + [ctx release]; + } + [pool release]; + return true; +} + +EAGLRenderingAPI eaglGetRenderingAPI(EAGLContext* ctx) { + return [ctx API]; +} +EAGLSharegroup * eaglGetSharegroup(EAGLContext *ctx) { + return [ctx sharegroup]; +} +Bool eaglIsContextMultiThreaded(EAGLContext* ctx) { + return [ctx isMultiThreaded]; +} +void eaglSetContextMultiThreaded(EAGLContext* ctx, Bool v) { + [ctx setMultiThreaded: v]; +} + +EAGLContext* eaglGetCurrentContext(void) { + return [EAGLContext currentContext]; +} +Bool eaglMakeCurrentContext(EAGLContext* ctx) { + return [EAGLContext setCurrentContext: ctx]; +} +Bool eaglBindDrawableStorageToRenderbuffer(EAGLContext* ctx, int renderbufferTarget, CAEAGLLayer /* EAGLDrawable */ * drawable) { + return [ctx renderbufferStorage: renderbufferTarget fromDrawable: drawable]; +} +Bool eaglPresentRenderbuffer(EAGLContext* ctx, int renderbufferTarget) { + return [ctx presentRenderbuffer: renderbufferTarget]; +} + +#include <dlfcn.h> +Bool imagesInitialized = false; +static char libGLESStr[] = "/System/Library/Frameworks/OpenGLES.framework/Libraries/libGLES.dylib"; +static void * *libGLESImage; +void* getProcAddress(const char *procname) { + if (imagesInitialized == false) { + imagesInitialized = true; + libGLESImage = dlopen(libGLESStr, RTLD_LAZY | RTLD_GLOBAL); + } + if(NULL == libGLESImage) { + return NULL; + } + + char underscoreName[512] = "_"; + void * res = NULL; + strcat(underscoreName, procname); + + res = dlsym(libGLESImage, underscoreName); + if( NULL == res ) { + // try smth else .. + } + return res; +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java index 323bc8c86..8e00d318c 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java @@ -52,6 +52,7 @@ import jogamp.nativewindow.NativeWindowFactoryImpl; import jogamp.nativewindow.ToolkitProperties; import jogamp.nativewindow.ResourceToolkitLock; import jogamp.nativewindow.WrappedWindow; +import jogamp.nativewindow.ios.IOSUtil; import jogamp.nativewindow.macosx.OSXUtil; import jogamp.nativewindow.windows.GDIUtil; import jogamp.nativewindow.x11.X11Lib; @@ -65,6 +66,7 @@ import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.nativewindow.ios.IOSGraphicsDevice; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsDevice; @@ -100,6 +102,9 @@ public abstract class NativeWindowFactory { /** Mac OS X type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_MACOSX = ".macosx"; + /** iOS type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_IOS = ".iOS"; + /** Generic AWT type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ public static final String TYPE_AWT = ".awt"; @@ -120,6 +125,8 @@ public abstract class NativeWindowFactory { private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util"; /** {@link jogamp.nativewindow.macosx.OSXUtil} implements {@link ToolkitProperties}. */ private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; + /** {@link jogamp.nativewindow.ios.IOSUtil} implements {@link ToolkitProperties}. */ + private static final String IOSUtilClassName = "jogamp.nativewindow.ios.IOSUtil"; /** {@link jogamp.nativewindow.windows.GDIUtil} implements {@link ToolkitProperties}. */ private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil"; @@ -143,6 +150,8 @@ public abstract class NativeWindowFactory { return TYPE_ANDROID; case MACOS: return TYPE_MACOSX; + case IOS: + return TYPE_IOS; case WINDOWS: return TYPE_WINDOWS; case OPENKODE: @@ -204,6 +213,8 @@ public abstract class NativeWindowFactory { clazzName = GDIClassName; } else if( TYPE_MACOSX == nativeWindowingTypePure ) { clazzName = OSXUtilClassName; + } else if( TYPE_IOS == nativeWindowingTypePure ) { + clazzName = IOSUtilClassName; } else { clazzName = null; } @@ -294,6 +305,8 @@ public abstract class NativeWindowFactory { clazzName = GDIClassName; } else if( TYPE_MACOSX == nativeWindowingTypePure ) { clazzName = OSXUtilClassName; + } else if( TYPE_IOS == nativeWindowingTypePure ) { + clazzName = IOSUtilClassName; } else { clazzName = null; } @@ -677,6 +690,8 @@ public abstract class NativeWindowFactory { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + } else if( NativeWindowFactory.TYPE_IOS == nwt ) { + return new IOSGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); } else if( NativeWindowFactory.TYPE_EGL == nwt ) { final EGLGraphicsDevice device; if( own ) { @@ -742,6 +757,8 @@ public abstract class NativeWindowFactory { return GDIUtil.GetRelativeLocation(nw.getWindowHandle(), 0, 0, 0); } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { return OSXUtil.GetLocationOnScreen(nw.getWindowHandle(), 0, 0); + } else if( NativeWindowFactory.TYPE_IOS == nwt ) { + return IOSUtil.GetLocationOnScreen(nw.getWindowHandle(), 0, 0); /** * FIXME: Needs service provider interface (SPI) for TK dependent implementation } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/ios/IOSGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/ios/IOSGraphicsDevice.java new file mode 100644 index 000000000..0a4354c9d --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/ios/IOSGraphicsDevice.java @@ -0,0 +1,46 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.nativewindow.ios; + +import com.jogamp.nativewindow.*; + +/** Encapsulates a graphics device on IOS platforms. + */ +public class IOSGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { + /** Constructs a new IOSGraphicsDevice */ + public IOSGraphicsDevice(final int unitID) { + super(NativeWindowFactory.TYPE_IOS, AbstractGraphicsDevice.DEFAULT_CONNECTION, unitID); + } + + @Override + public Object clone() { + return super.clone(); + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java b/src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java index bffabdd5a..9d38b1f4b 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/javafx/JFXAccessor.java @@ -62,6 +62,7 @@ public class JFXAccessor { private static final String nwt; private static final boolean isOSX; + private static final boolean isIOS; private static final boolean isWindows; private static final boolean isX11; @@ -130,6 +131,7 @@ public class JFXAccessor { nwt = NativeWindowFactory.getNativeWindowType(false); isOSX = NativeWindowFactory.TYPE_MACOSX == nwt; + isIOS = NativeWindowFactory.TYPE_IOS == nwt; isWindows = NativeWindowFactory.TYPE_WINDOWS == nwt; isX11 = NativeWindowFactory.TYPE_X11 == nwt; diff --git a/src/nativewindow/classes/jogamp/nativewindow/ios/IOSDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/ios/IOSDummyUpstreamSurfaceHook.java new file mode 100644 index 000000000..a61287f8b --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ios/IOSDummyUpstreamSurfaceHook.java @@ -0,0 +1,83 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow.ios; + +import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.ProxySurface; +import com.jogamp.nativewindow.UpstreamSurfaceHook; + +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; + +public class IOSDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { + long uiWindow; + + /** + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, + * not the actual dummy surface height, + * The latter is platform specific and small + */ + public IOSDummyUpstreamSurfaceHook(final int width, final int height) { + super(width, height); + uiWindow = 0; + } + + @Override + public final void create(final ProxySurface s) { + if(0 == uiWindow && 0 == s.getSurfaceHandle()) { + uiWindow = IOSUtil.CreateUIWindow(0, 0, 64, 64); + if(0 == uiWindow) { + throw new NativeWindowException("Error UI window 0"); + } + final long uiView = IOSUtil.GetUIView(uiWindow, true); + if(0 == uiView) { + throw new NativeWindowException("Error UI view 0"); + } + s.setSurfaceHandle(uiView); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + } + + @Override + public final void destroy(final ProxySurface s) { + if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + if( 0 == uiWindow || 0 == s.getSurfaceHandle() ) { + throw new InternalError("Owns upstream surface, but no IOS view/window: "+s+", uiWindow 0x"+Long.toHexString(uiWindow)); + } + IOSUtil.DestroyUIWindow(uiWindow); + uiWindow = 0; + s.setSurfaceHandle(0); + s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + } + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/ios/IOSUtil.java b/src/nativewindow/classes/jogamp/nativewindow/ios/IOSUtil.java new file mode 100644 index 000000000..bd4b36239 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ios/IOSUtil.java @@ -0,0 +1,333 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow.ios; + +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.util.Insets; +import com.jogamp.nativewindow.util.Point; +import com.jogamp.common.util.Function; +import com.jogamp.common.util.FunctionTask; +import com.jogamp.common.util.InterruptedRuntimeException; +import com.jogamp.common.util.RunnableTask; + +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.ToolkitProperties; + +public class IOSUtil implements ToolkitProperties { + private static boolean isInit = false; + private static final boolean DEBUG = Debug.debug("IOSUtil"); + + /** FIXME HiDPI: OSX unique and maximum value {@value} */ + public static final int MAX_PIXELSCALE = 2; + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static synchronized void initSingleton() { + if(!isInit) { + if(DEBUG) { + System.out.println("IOSUtil.initSingleton()"); + } + if(!NWJNILibLoader.loadNativeWindow("ios")) { + throw new NativeWindowException("NativeWindow IOS native library load error."); + } + + if( !initIDs0() ) { + throw new NativeWindowException("IOS: Could not initialized native stub"); + } + isInit = true; + } + } + + /** + * Called by {@link NativeWindowFactory#shutdown()} + * @see ToolkitProperties + */ + public static void shutdown() { } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static boolean requiresToolkitLock() { return false; } + + /** + * Called by {@link NativeWindowFactory#initSingleton()} + * @see ToolkitProperties + */ + public static final boolean hasThreadingIssues() { return false; } + + public static boolean isCALayer(final long object) { + return 0 != object ? isCALayer0(object) : false; + } + + public static boolean isCAEAGLLayer(final long object) { + return 0 != object ? isCAEAGLLayer0(object) : false; + } + + public static boolean isUIView(final long object) { + return 0 != object ? isUIView0(object) : false; + } + + public static boolean isUIWindow(final long object) { + return 0 != object ? isUIWindow0(object) : false; + } + + /** + * @param windowOrView + * @param src_x + * @param src_y + * @return top-left client-area position in window units + */ + public static Point GetLocationOnScreen(final long windowOrView, final int src_x, final int src_y) { + return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); + } + + public static Insets GetInsets(final long windowOrView) { + return (Insets) GetInsets0(windowOrView); + } + + public static double GetPixelScaleByDisplayID(final int displayID) { + if( 0 != displayID ) { + return GetPixelScale1(displayID); + } else { + return 1.0; // default + } + } + public static double GetPixelScale(final long windowOrView) { + if( 0 != windowOrView ) { + return GetPixelScale2(windowOrView); + } else { + return 1.0; // default + } + } + + public static long CreateUIWindow(final int x, final int y, final int width, final int height) { + final long res[] = { 0 }; + RunOnMainThread(true, false /* kickNSApp */, new Runnable() { + @Override + public void run() { + res[0] = CreateUIWindow0(x, y, width, height); + } } ); + return res[0]; + } + public static void DestroyUIWindow(final long uiWindow) { + DestroyUIWindow0(uiWindow); + } + public static long GetCALayer(final long uiView) { + return 0 != uiView ? GetCALayer0(uiView) : 0; + } + public static long GetCAEAGLLayer(final long uiView) { + return 0 != uiView ? GetCAEAGLLayer0(uiView) : 0; + } + public static long GetUIView(final long uiWindow, final boolean onlyEAGL) { + return 0 != uiWindow ? GetUIView0(uiWindow, onlyEAGL) : 0; + } + public static long GetUIWindow(final long uiView) { + return 0 != uiView ? GetUIWindow0(uiView) : 0; + } + + /** + * Set the UIView's pixelScale / contentScale for HiDPI + * + * @param uiView the mutable UIView instance + * @param contentScaleFactor scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static void SetUIViewPixelScale(final long uiView, final float contentScaleFactor) { + SetUIViewPixelScale0(uiView, contentScaleFactor); + } + /** + * Get the UIView's pixelScale / contentScale for HiDPI + * + * @param uiView the UIView instance + * @return used scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static float GetUIViewPixelScale(final long uiView) { + return GetUIViewPixelScale0(uiView); + } + + /** + * Set root and sub CALayer pixelScale / contentScale for HiDPI + * + * @param rootCALayer the root surface layer, maybe null. + * @param subCALayer the client surface layer, maybe null. + * @param contentsScale scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static void SetCALayerPixelScale(final long rootCALayer, final long subCALayer, final float contentsScale) { + if( 0==rootCALayer && 0==subCALayer ) { + return; + } + SetCALayerPixelScale0(rootCALayer, subCALayer, contentsScale); + } + /** + * Get the CALayer's pixelScale / contentScale for HiDPI + * + * @param caLayer the CALayer instance + * @return used scale for HiDPI support: pixel-dim = window-dim x scale + */ + public static float GetCALayerPixelScale(final long caLayer) { + return GetCALayerPixelScale0(caLayer); + } + + /** + * Run on OSX UI main thread. + * <p> + * 'waitUntilDone' is implemented on Java site via lock/wait on {@link RunnableTask} to not freeze OSX main thread. + * </p> + * + * @param waitUntilDone + * @param kickNSApp if <code>true</code> issues {@link #KickUIApp()} + * @param runnable + */ + public static void RunOnMainThread(final boolean waitUntilDone, final boolean kickNSApp, final Runnable runnable) { + if( IsMainThread0() ) { + runnable.run(); // don't leave the JVM + } else { + // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, + // otherwise we may freeze the OSX main thread. + final Object sync = new Object(); + final RunnableTask rt = new RunnableTask( runnable, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); + synchronized(sync) { + RunOnMainThread0(kickNSApp, rt); + if( waitUntilDone ) { + while( rt.isInQueue() ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rt.getThrowable(); + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + } + } + } + + /** + * Run later on .. + * @param onMain if true, run on main-thread, otherwise on the current OSX thread. + * @param runnable + * @param delay delay to run the runnable in milliseconds + */ + public static void RunLater(final boolean onMain, final Runnable runnable, final int delay) { + RunLater0(onMain, false /* kickNSApp */, new RunnableTask( runnable, null, true, System.err ), delay); + } + + private static Runnable _nop = new Runnable() { @Override public void run() {}; }; + + /** Issues a {@link #RunOnMainThread(boolean, boolean, Runnable)} w/ an <i>NOP</i> runnable, while waiting until done and issuing {@link #KickUIApp()}. */ + public static void WaitUntilFinish() { + RunOnMainThread(true, true /* kickNSApp */, _nop); + } + + /** + * Run on OSX UI main thread. + * <p> + * 'waitUntilDone' is implemented on Java site via lock/wait on {@link FunctionTask} to not freeze OSX main thread. + * </p> + * + * @param waitUntilDone + * @param kickUIApp if <code>true</code> issues {@link #KickUIApp()} + * @param func + */ + public static <R,A> R RunOnMainThread(final boolean waitUntilDone, final boolean kickUIApp, final Function<R,A> func, final A... args) { + if( IsMainThread0() ) { + return func.eval(args); // don't leave the JVM + } else { + // Utilize Java side lock/wait and simply pass the Runnable async to OSX main thread, + // otherwise we may freeze the OSX main thread. + final Object sync = new Object(); + final FunctionTask<R,A> rt = new FunctionTask<R,A>( func, waitUntilDone ? sync : null, true, waitUntilDone ? null : System.err ); + synchronized(sync) { + rt.setArgs(args); + RunOnMainThread0(kickUIApp, rt); + if( waitUntilDone ) { + while( rt.isInQueue() ) { + try { + sync.wait(); + } catch (final InterruptedException ie) { + throw new InterruptedRuntimeException(ie); + } + final Throwable throwable = rt.getThrowable(); + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + } + return rt.getResult(); + } + } + + public static boolean IsMainThread() { + return IsMainThread0(); + } + + /** Returns the screen refresh rate in Hz. If unavailable, returns 60Hz. */ + public static int GetScreenRefreshRate(final int scrn_idx) { + return GetScreenRefreshRate0(scrn_idx); + } + + public static void CreateGLViewDemoA() { + CreateGLViewDemoA0(); + } + + private static native boolean initIDs0(); + private static native boolean isCALayer0(long object); + private static native boolean isCAEAGLLayer0(long object); + private static native boolean isUIView0(long object); + private static native boolean isUIWindow0(long object); + private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); + private static native Object GetInsets0(long windowOrView); + private static native double GetPixelScale1(int displayID); + private static native double GetPixelScale2(long windowOrView); + private static native long CreateUIWindow0(int x, int y, int width, int height); + private static native void DestroyUIWindow0(long uiWindow); + private static native long GetCALayer0(long uiView); + private static native long GetCAEAGLLayer0(long uiView); + private static native long GetUIView0(long uiWindow, boolean onlyEAGL); + private static native long GetUIWindow0(long uiView); + private static native void SetUIViewPixelScale0(final long uiView, final float contentScaleFactor); + private static native float GetUIViewPixelScale0(final long uiView); + private static native void SetCALayerPixelScale0(long rootCALayer, long subCALayer, float contentsScale); + private static native float GetCALayerPixelScale0(final long caLayer); + + private static native void RunOnMainThread0(boolean kickNSApp, Runnable runnable); + private static native void RunLater0(boolean onMain, boolean kickNSApp, Runnable runnable, int delay); + private static native void KickUIApp0(); + private static native boolean IsMainThread0(); + private static native int GetScreenRefreshRate0(int scrn_idx); + private static native void CreateGLViewDemoA0(); + +} diff --git a/src/nativewindow/native/JVM_JNI8.c b/src/nativewindow/native/JVM_JNI8.c new file mode 100644 index 000000000..a7b4e5d90 --- /dev/null +++ b/src/nativewindow/native/JVM_JNI8.c @@ -0,0 +1,47 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include <stdio.h> //required by android to identify NULL +#include <jni.h> + +#if defined (JNI_VERSION_1_8) + +JNIEXPORT jint JNICALL JNI_OnLoad_nativewindow_awt(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } +JNIEXPORT jint JNICALL JNI_OnLoad_nativewindow_x11(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } +JNIEXPORT jint JNICALL JNI_OnLoad_nativewindow_win32(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } +JNIEXPORT jint JNICALL JNI_OnLoad_nativewindow_macosx(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } +JNIEXPORT jint JNICALL JNI_OnLoad_nativewindow_ios(JavaVM *vm, void *reserved) { return JNI_VERSION_1_8; } + +JNIEXPORT void JNICALL JNI_OnUnload_nativewindow_awt(JavaVM *vm, void *reserved) { } +JNIEXPORT void JNICALL JNI_OnUnload_nativewindow_x11(JavaVM *vm, void *reserved) { } +JNIEXPORT void JNICALL JNI_OnUnload_nativewindow_win32(JavaVM *vm, void *reserved) { } +JNIEXPORT void JNICALL JNI_OnUnload_nativewindow_macosx(JavaVM *vm, void *reserved) { } +JNIEXPORT void JNICALL JNI_OnUnload_nativewindow_ios(JavaVM *vm, void *reserved) { } + +#endif /* defined (JNI_VERSION_1_8) */ + diff --git a/src/nativewindow/native/ios/CAEAGLLayered.h b/src/nativewindow/native/ios/CAEAGLLayered.h new file mode 100644 index 000000000..fe94dc907 --- /dev/null +++ b/src/nativewindow/native/ios/CAEAGLLayered.h @@ -0,0 +1,50 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#ifndef CAEAGL_LAYERED_H +#define CAEAGL_LAYERED_H 1 + +#import <UIKit/UIKit.h> +#import <QuartzCore/QuartzCore.h> + +#include "NativewindowCommon.h" + +@interface CAEAGLUIView : UIView +{ +} +// override ++ (Class)layerClass; + ++ (CAEAGLUIView*) findCAEAGLUIView: (UIWindow*) win + startIdx: (int) sidx; + ++ (UIView*) getUIView: (UIWindow*) win + startIdx: (int) sidx; +@end /* interface CAEAGLUIView */ + +#endif diff --git a/src/nativewindow/native/ios/CAEAGLLayered.m b/src/nativewindow/native/ios/CAEAGLLayered.m new file mode 100644 index 000000000..3d378e997 --- /dev/null +++ b/src/nativewindow/native/ios/CAEAGLLayered.m @@ -0,0 +1,66 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include "CAEAGLLayered.h" + +@implementation CAEAGLUIView +// override ++ (Class)layerClass { + return CAEAGLLayer.self; +} +/** +override class var layerClass : AnyClass { + return CAEAGLLayer.self +} +*/ ++ (CAEAGLUIView*) findCAEAGLUIView: (UIWindow*) win + startIdx: (int) sidx +{ + NSArray* subviews = [win subviews]; + if(NULL != subviews) { + for(int i=sidx; i<[subviews count]; i++) { + UIView* sub = [subviews objectAtIndex: i]; + if( [sub isKindOfClass:[CAEAGLUIView class]] ) { + return (CAEAGLUIView*)sub; + } + } + } + return (CAEAGLUIView*)NULL; +} ++ (UIView*) getUIView: (UIWindow*) win + startIdx: (int) sidx +{ + NSArray* subviews = [win subviews]; + if(NULL != subviews) { + if( sidx<[subviews count] ) { + return [subviews objectAtIndex: sidx]; + } + } + return (UIView*)NULL; +} +@end /* implementation CAEAGLUIView */ diff --git a/src/nativewindow/native/ios/IOSmisc.m b/src/nativewindow/native/ios/IOSmisc.m new file mode 100644 index 000000000..5826b9eef --- /dev/null +++ b/src/nativewindow/native/ios/IOSmisc.m @@ -0,0 +1,813 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> + +#include "CAEAGLLayered.h" + +#import "NativeWindowProtocols.h" + +#include "jogamp_nativewindow_ios_IOSUtil.h" + +// #define VERBOSE 1 +// +#ifdef VERBOSE + // #define DBG_PRINT(...) NSLog(@ ## __VA_ARGS__) + #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +// #define VERBOSE2 1 +// +#ifdef VERBOSE2 + #define DBG_PRINT2(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT2(...) +#endif + +// #define DBG_LIFECYCLE 1 + +static const char * const ClazzNameRunnable = "java/lang/Runnable"; +static jmethodID runnableRunID = NULL; + +static const char * const ClazzAnyCstrName = "<init>"; + +static const char * const ClazzNamePoint = "com/jogamp/nativewindow/util/Point"; +static const char * const ClazzNamePointCstrSignature = "(II)V"; +static jclass pointClz = NULL; +static jmethodID pointCstr = NULL; + +static const char * const ClazzNameInsets = "com/jogamp/nativewindow/util/Insets"; +static const char * const ClazzNameInsetsCstrSignature = "(IIII)V"; +static jclass insetsClz = NULL; +static jmethodID insetsCstr = NULL; + +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_ios_IOSUtil_initIDs0(JNIEnv *env, jclass _unused) { + if( NativewindowCommon_init(env) ) { + jclass c; + c = (*env)->FindClass(env, ClazzNamePoint); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't find %s", ClazzNamePoint); + } + pointClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==pointClz) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't use %s", ClazzNamePoint); + } + pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); + if(NULL==pointCstr) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't fetch %s.%s %s", + ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); + } + + c = (*env)->FindClass(env, ClazzNameInsets); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't find %s", ClazzNameInsets); + } + insetsClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==insetsClz) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't use %s", ClazzNameInsets); + } + insetsCstr = (*env)->GetMethodID(env, insetsClz, ClazzAnyCstrName, ClazzNameInsetsCstrSignature); + if(NULL==insetsCstr) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't fetch %s.%s %s", + ClazzNameInsets, ClazzAnyCstrName, ClazzNameInsetsCstrSignature); + } + + c = (*env)->FindClass(env, ClazzNameRunnable); + if(NULL==c) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't find %s", ClazzNameRunnable); + } + runnableRunID = (*env)->GetMethodID(env, c, "run", "()V"); + if(NULL==runnableRunID) { + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_ios_IOSUtil_initIDs0: can't fetch %s.run()V", ClazzNameRunnable); + } + } + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_ios_IOSUtil_isCAEAGLLayer0(JNIEnv *env, jclass _unused, jlong object) { + NSObject *nsObj = (NSObject*) (intptr_t) object; + jboolean u = [nsObj isKindOfClass:[CAEAGLLayer class]]; + DBG_PRINT( "isEAGLCALayer(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_ios_IOSUtil_isCALayer0(JNIEnv *env, jclass _unused, jlong object) { + NSObject *nsObj = (NSObject*) (intptr_t) object; + jboolean u = [nsObj isKindOfClass:[CALayer class]]; + DBG_PRINT( "isCALayer(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_ios_IOSUtil_isUIView0(JNIEnv *env, jclass _unused, jlong object) { + NSObject *nsObj = (NSObject*) (intptr_t) object; + jboolean u = [nsObj isKindOfClass:[UIView class]]; + DBG_PRINT( "isUIView(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + +JNIEXPORT jboolean JNICALL +Java_jogamp_nativewindow_ios_IOSUtil_isUIWindow0(JNIEnv *env, jclass _unused, jlong object) { + NSObject *nsObj = (NSObject*) (intptr_t) object; + jboolean u = [nsObj isKindOfClass:[UIWindow class]]; + DBG_PRINT( "isUIWindow(obj: %p): %s -> %d\n", nsObj, [[nsObj description] UTF8String], u); + return u; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: getLocationOnScreen0 + * Signature: (JII)Lcom/jogamp/nativewindow/util/Point; + */ +JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetLocationOnScreen0 + (JNIEnv *env, jclass unused, jlong winOrView, jint src_x, jint src_y) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + /** + * return location in 0/0 top-left space, + * OSX NSView is 0/0 bottom-left space naturally + * iOS UIView is 0/0 top-left space naturally + */ + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; + UIWindow* win = NULL; + + if( [nsObj isKindOfClass:[UIWindow class]] ) { + win = (UIWindow*) nsObj; + } else if( nsObj != NULL && [nsObj isKindOfClass:[UIView class]] ) { + UIView* view = (UIView*) nsObj; + win = [view window]; + if( NULL == win ) { + NativewindowCommon_throwNewRuntimeException(env, "view has null window, view %p\n", nsObj); + } + } else { + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); + } + CGPoint p = CGPointMake(src_x, src_y); + UIScreen* screen = [win screen]; + CGPoint pS = [win convertPoint: p toCoordinateSpace: screen.fixedCoordinateSpace]; + +#ifdef VERBOSE_ON + CGRect winFrame = [self frame]; + DBG_PRINT( "GetLocationOnScreen0(window: %p):: point-in[%d/%d], winFrame[%d/%d %dx%d] -> %d/%d\n", + win, + (int)p.x, (int)p.y, + (int)winFrame.origin.x, (int)winFrame.origin.y, (int)winFrame.size.width, (int)winFrame.size.height, + (int)pS.x, (int)pS.y); +#endif + + jobject res = (*env)->NewObject(env, pointClz, pointCstr, (jint)pS.x, (jint)pS.y); + + [pool release]; + + return res; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: getInsets0 + * Signature: (J)Lcom/jogamp/nativewindow/util/Insets; + */ +JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetInsets0 + (JNIEnv *env, jclass unused, jlong winOrView) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; + UIWindow* win = NULL; + jint il,ir,it,ib; + + if( [nsObj isKindOfClass:[UIWindow class]] ) { + win = (UIWindow*) nsObj; + } else if( nsObj != NULL && [nsObj isKindOfClass:[UIView class]] ) { + UIView* view = (UIView*) nsObj; + win = [view window]; + if( NULL == win ) { + NativewindowCommon_throwNewRuntimeException(env, "view has null window, view %p\n", nsObj); + } + } else { + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); + } + + UIEdgeInsets uiInsets = [win safeAreaInsets]; + il = uiInsets.left; + ir = uiInsets.right; + it = uiInsets.top; + ib = uiInsets.bottom; + /** + CGRect frameRect = [win frame]; + CGRect contentRect = [win contentRectForFrameRect: frameRect]; + + // note: this is a simplistic implementation which doesn't take + // into account DPI and scaling factor + CGFloat l = contentRect.origin.x - frameRect.origin.x; + il = (jint)l; // l + ir = (jint)(frameRect.size.width - (contentRect.size.width + l)); // r + it = (jint)(frameRect.size.height - contentRect.size.height); // t + ib = (jint)(contentRect.origin.y - frameRect.origin.y); // b + */ + + jobject res = (*env)->NewObject(env, insetsClz, insetsCstr, il, ir, it, ib); + + [pool release]; + + return res; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetPixelScale1 + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetPixelScale1 + (JNIEnv *env, jclass unused, jint displayID) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + CGFloat pixelScale = 1.0; // default + // UIScreen *screen = IOSUtil_getUIScreenByCGDirectDisplayID((CGDirectDisplayID)displayID); + UIScreen *screen = [UIScreen mainScreen]; + if( NULL != screen ) { +NS_DURING + // Available >= 10.7 + pixelScale = [screen scale]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + } + [pool release]; + + return (jdouble)pixelScale; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetPixelScale1 + * Signature: (J)D + */ +JNIEXPORT jdouble JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetPixelScale2 + (JNIEnv *env, jclass unused, jlong winOrView) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; + UIScreen *screen = NULL; + + if( [nsObj isKindOfClass:[UIWindow class]] ) { + UIWindow* win = (UIWindow*) nsObj; + screen = [win screen]; + } else if( nsObj != NULL && [nsObj isKindOfClass:[UIView class]] ) { + UIView* view = (UIView*) nsObj; + UIWindow* win = [view window]; + if( NULL == win ) { + NativewindowCommon_throwNewRuntimeException(env, "view has null window, view %p\n", nsObj); + } + screen = [win screen]; + } else { + NativewindowCommon_throwNewRuntimeException(env, "neither win nor view %p\n", nsObj); + } + + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen scale]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + + [pool release]; + + return (jdouble)pixelScale; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: CreateUIWindow0 + * Signature: (IIIIZ)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_ios_IOSUtil_CreateUIWindow0 + (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [CATransaction begin]; + CGRect boundsWin = CGRectMake(x, y, width, height); + CGRect boundsView = CGRectMake(0, 0, width, height); + + // Allocate the window + UIWindow *myWindow = [[[[UIWindow alloc] initWithFrame:boundsWin] autorelease] retain]; + myWindow.rootViewController = [[[UIViewController alloc] initWithNibName:nil bundle:nil] autorelease]; + [myWindow setBackgroundColor: [UIColor redColor]]; + + // n/a iOS [myWindow setPreservesContentDuringLiveResize: YES]; + + // FIXME invisible .. (we keep it visible for testing) + // FIXME [myWindow setOpaque: NO]; + // FIXME [myWindow setBackgroundColor: [UIColor clearColor]]; + [myWindow makeKeyAndVisible]; + + CAEAGLUIView *uiView = [[CAEAGLUIView alloc] initWithFrame:boundsView]; + CAEAGLLayer* l = (CAEAGLLayer*)[uiView layer]; + [l setOpaque: YES]; + + [myWindow addSubview: uiView]; + + [CATransaction commit]; + [pool release]; + return (jlong) ((intptr_t) myWindow); +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: DestroyUIWindow0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_ios_IOSUtil_DestroyUIWindow0 + (JNIEnv *env, jclass unused, jlong nsWindow) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [CATransaction begin]; + +NS_DURING + UIWindow* mWin = (UIWindow*) ((intptr_t) nsWindow); + [mWin resignKeyWindow]; + [mWin setHidden: YES]; + NSArray* subviews = [mWin subviews]; + if(NULL != subviews) { + for(int i=0; i<[subviews count]; i++) { + UIView* sub = [subviews objectAtIndex: i]; + [sub setHidden: YES]; + [sub release]; + } + } + [mWin release]; +NS_HANDLER + // On killing or terminating the process [UIWindow _close], rarely + // throws an NSRangeException while ordering out menu items +NS_ENDHANDLER + + [CATransaction commit]; + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetCALayer0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetCALayer0 + (JNIEnv *env, jclass unused, jlong view) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIView* uiView = (UIWindow*) ((intptr_t) view); + + jlong res = (jlong) ((intptr_t) (CALayer *) [uiView layer]); + + DBG_PRINT( "GetCALayer(view: %p): %p\n", uiView, (void*) (intptr_t) res); + + [pool release]; + return res; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetCAEAGLLayer0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetCAEAGLLayer0 + (JNIEnv *env, jclass unused, jlong view) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIView* uiView = (UIWindow*) ((intptr_t) view); + + CALayer* l = [uiView layer]; + jboolean isRes = [l isKindOfClass:[CAEAGLLayer class]]; + jlong res = isRes ? (jlong) ((intptr_t) l) : 0; + + DBG_PRINT( "GetCAEAGLLayer(view: %p): CALayer %p, CAEAGLLayer %p (%d)\n", uiView, l, (void*) (intptr_t) res, isRes); + + [pool release]; + return res; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetUIView0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetUIView0 + (JNIEnv *env, jclass unused, jlong window, jboolean onlyCAEAGLUIView) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIWindow* win = (UIWindow*) ((intptr_t) window); + jlong res; + + if( onlyCAEAGLUIView ) { + CAEAGLUIView* v0 = [CAEAGLUIView findCAEAGLUIView: win + startIdx: 0]; + res = (jlong) ((intptr_t) v0); + } else { + UIView* v0 = [CAEAGLUIView getUIView: win startIdx: 0]; + res = (jlong) ((intptr_t) v0); + } + + DBG_PRINT( "GetUIView(window: %p): %p\n", win, (void*) (intptr_t) res); + + [pool release]; + return res; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetUIWindow0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetUIWindow0 + (JNIEnv *env, jclass unused, jlong view) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIView* v = (UIView*) ((intptr_t) view); + + jlong res = (jlong) ((intptr_t) [v window]); + + DBG_PRINT( "GetUIWindow(view: %p): %p\n", v, (void*) (intptr_t) res); + + [pool release]; + return res; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: SetUIViewPixelScale0 + * Signature: (JF)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_ios_IOSUtil_SetUIViewPixelScale0 + (JNIEnv *env, jclass unused, jlong view, jfloat contentScale) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIView* v = (UIView*) ((intptr_t) view); + +NS_DURING + if( NULL != v ) { + [v setContentScaleFactor: (CGFloat)contentScale]; + } +NS_HANDLER +NS_ENDHANDLER + + [pool release]; +} +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetUIViewPixelScale0 + * Signature: (J)F + */ +JNIEXPORT jfloat JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetUIViewPixelScale0 + (JNIEnv *env, jclass unused, jlong view) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIView* v = (UIView*) ((intptr_t) view); + jfloat r = 0.0f; + +NS_DURING + if( NULL != v ) { + r = [v contentScaleFactor]; + } +NS_HANDLER +NS_ENDHANDLER + + [pool release]; + return r; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: SetCALayerPixelScale0 + * Signature: (JJF)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_ios_IOSUtil_SetCALayerPixelScale0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer, jfloat contentsScale) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + +NS_DURING + if( NULL != rootLayer ) { + [rootLayer setContentsScale: (CGFloat)contentsScale]; + } + if( NULL != subLayer ) { + [subLayer setContentsScale: (CGFloat)contentsScale]; + } +NS_HANDLER +NS_ENDHANDLER + + [CATransaction commit]; + + [pool release]; +} +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: GetCALayerPixelScale0 + * Signature: (J)F + */ +JNIEXPORT jfloat JNICALL Java_jogamp_nativewindow_ios_IOSUtil_GetCALayerPixelScale0 + (JNIEnv *env, jclass unused, jlong caLayer) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + CALayer* v = (CALayer*) ((intptr_t) caLayer); + jfloat r = 0.0f; + +NS_DURING + if( NULL != v ) { + r = [v contentsScale]; + } +NS_HANDLER +NS_ENDHANDLER + + [pool release]; + return r; +} + +@interface MainRunnable : NSObject + +{ + jobject runnableObj; +} + +- (id) initWithRunnable: (jobject)runnable; +- (void) jRun; + +#ifdef DBG_LIFECYCLE +- (id)retain; +- (oneway void)release; +- (void)dealloc; +#endif + + +@end + +@implementation MainRunnable + +- (id) initWithRunnable: (jobject)runnable +{ + runnableObj = runnable; + return [super init]; +} + +- (void) jRun +{ + int shallBeDetached = 0; + JNIEnv* env = NativewindowCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + DBG_PRINT2("MainRunnable.1 env: %d\n", (int)(NULL!=env)); + if(NULL!=env) { + DBG_PRINT2("MainRunnable.1.0\n"); + (*env)->CallVoidMethod(env, runnableObj, runnableRunID); + DBG_PRINT2("MainRunnable.1.1\n"); + (*env)->DeleteGlobalRef(env, runnableObj); + + DBG_PRINT2("MainRunnable.1.3\n"); + // detaching thread not required - daemon + // NativewindowCommon_ReleaseJNIEnv(shallBeDetached); + } + DBG_PRINT2("MainRunnable.X\n"); +} + +#ifdef DBG_LIFECYCLE + +- (id)retain +{ + DBG_PRINT2("MainRunnable::retain.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + id o = [super retain]; + DBG_PRINT2("MainRunnable::retain.X: %p (refcnt %d)\n", o, (int)[o retainCount]); + return o; +} + +- (oneway void)release +{ + DBG_PRINT2("MainRunnable::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [super release]; + // DBG_PRINT2("MainRunnable::release.X: %p (refcnt %d)\n", self, (int)[self retainCount]); +} + +- (void)dealloc +{ + DBG_PRINT2("MainRunnable::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + [super dealloc]; + // DBG_PRINT2("MainRunnable.dealloc.X: %p\n", self); +} + +#endif + +@end + +// #define UIApp [UIApplication sharedApplication] +// #define NSApp [NSApplication sharedApplication] + +static void RunOnThread (JNIEnv *env, jobject runnable, BOOL onMain, jint delayInMS) +{ + BOOL isMainThread = [NSThread isMainThread]; + BOOL forkOnMain = onMain && ( NO == isMainThread || 0 < delayInMS ); + // UIApplication * UIApp = [UIApplication sharedApplication]; + + DBG_PRINT2( "RunOnThread0: forkOnMain %d [onMain %d, delay %dms, isMainThread %d], UIApp %d, UIApp-isRunning %d\n", + (int)forkOnMain, (int)onMain, (int)delayInMS, (int)isMainThread, (int)(NULL!=UIApp), (int)([UIApp applicationState])); + + if ( forkOnMain ) { + jobject runnableObj = (*env)->NewGlobalRef(env, runnable); + + DBG_PRINT2( "RunOnThread.1.0\n"); + MainRunnable * mr = [[MainRunnable alloc] initWithRunnable: runnableObj]; + + if( onMain ) { + [mr performSelectorOnMainThread:@selector(jRun) withObject:nil waitUntilDone:NO]; + } else { + NSTimeInterval delay = (double)delayInMS/1000.0; + [mr performSelector:@selector(jRun) withObject:nil afterDelay:delay]; + } + DBG_PRINT2( "RunOnThread.1.1\n"); + + [mr release]; + DBG_PRINT2( "RunOnThread.1.2\n"); + + } else { + DBG_PRINT2( "RunOnThread.2\n"); + (*env)->CallVoidMethod(env, runnable, runnableRunID); + } + DBG_PRINT2( "RunOnThread.X\n"); +} + +static void IOSUtil_KickUIApp() { + // UIApplication * UIApp = [UIApplication sharedApplication]; + /*** iOS-FIXME: UIEvent creation and post n/a !!! + UIEvent* event = [UIEvent otherEventWithType: UIApplicationDefined + location: NSMakePoint(0,0) + modifierFlags: 0 + timestamp: 0.0 + windowNumber: 0 + context: nil + subtype: 0 + data1: 0 + data2: 0]; + [UIApp postEvent: event atStart: true]; + */ +} + +/** + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: RunOnMainThread0 + * Signature: (ZLjava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_ios_IOSUtil_RunOnMainThread0 + (JNIEnv *env, jclass unused, jboolean kickUIApp, jobject runnable) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, YES, 0); + if( kickUIApp ) { + IOSUtil_KickUIApp(); + } + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: RunLater0 + * Signature: (ZZLjava/lang/Runnable;I)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_ios_IOSUtil_RunLater0 + (JNIEnv *env, jclass unused, jboolean onMain, jboolean kickUIApp, jobject runnable, jint delay) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + RunOnThread (env, runnable, onMain ? YES : NO, delay); + if( kickUIApp ) { + IOSUtil_KickUIApp(); + } + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_ios_IOSUtil + * Method: IsMainThread0 + * Signature: (V)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_ios_IOSUtil_IsMainThread0 + (JNIEnv *env, jclass unused) +{ + return ( [NSThread isMainThread] == YES ) ? JNI_TRUE : JNI_FALSE ; +} + +#define EAGL_TEST 1 + +#ifdef EAGL_TEST +#include <OpenGLES/ES2/gl.h> +#include <OpenGLES/ES2/glext.h> + +@interface GLView : UIView +{ + CAEAGLLayer *glLayer; + EAGLContext *glContext; + GLuint renderbuffer; +} +@end +@implementation GLView ++ (Class)layerClass +{ + return [CAEAGLLayer class]; +} + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + [self initGL]; + [self render]; + } + + return self; +} + +- (void)render +{ + glClearColor(150.0/255.0, 200.0/255.0, 255.0/255.0, 1.0); + + glClear(GL_COLOR_BUFFER_BIT); + + [glContext presentRenderbuffer:GL_RENDERBUFFER]; +} + +- (void)initGL +{ + glLayer = (CAEAGLLayer *)self.layer; + glLayer.opaque = YES; + + glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + if (!glContext) { + NSLog(@"Unable to create EAGLContext"); + exit(1); + } + if (![EAGLContext setCurrentContext:glContext]) { + NSLog(@"Unable to set current EAGLContext"); + exit(1); + } + glGenRenderbuffers(1, &renderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); + [glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:glLayer]; + + GLuint framebuffer; + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); +} +@end +#endif /* EAGL_TEST */ + +JNIEXPORT void JNICALL Java_jogamp_nativewindow_ios_IOSUtil_CreateGLViewDemoA0 + (JNIEnv *env, jclass unused) +{ +#ifdef EAGL_TEST + CGRect boundsW2 = CGRectMake(500, 10, 320, 320); + CGRect boundsV2 = CGRectMake(0, 0, 320, 320); + UIWindow* window2 = [[[[UIWindow alloc] initWithFrame:boundsW2] autorelease] retain]; + window2.rootViewController = [[[UIViewController alloc] initWithNibName:nil bundle:nil] autorelease]; + [window2 setBackgroundColor: [UIColor redColor]]; + [window2 makeKeyAndVisible]; + + GLView *glView = [[GLView alloc] initWithFrame:boundsV2]; + [window2 addSubview:glView]; +#endif /* EAGL_TEST */ +} + diff --git a/src/nativewindow/native/ios/NativeWindowProtocols.h b/src/nativewindow/native/ios/NativeWindowProtocols.h new file mode 100644 index 000000000..b27afc70d --- /dev/null +++ b/src/nativewindow/native/ios/NativeWindowProtocols.h @@ -0,0 +1,59 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#ifndef NATIVEWINDOWPROTOCOLS_H +#define NATIVEWINDOWPROTOCOLS_H 1 + +/** + * CALayer size needs to be set using the AWT component size. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_SIZE ( 1 << 0 ) + +/** + * CALayer position needs to be set to zero. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_POSITION ( 1 << 1 ) + +/** + * CALayer position needs to be derived from AWT position. + * in relation to super CALayer. + * See detailed description in JAWTUtil.java and sync w/ changed. + */ +#define NW_DEDICATEDFRAME_QUIRK_LAYOUT ( 1 << 2 ) + +// n/a iOS #import <Foundation/NSGeometry.h> +#import <UIKit/UIGeometry.h> + +@protocol NWDedicatedFrame +- (void)setDedicatedFrame:(CGRect)dFrame quirks:(int)quirks; +@end + +#endif /* NATIVEWINDOWPROTOCOLS_H_ */ + diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index c04ba786e..fb15c43b9 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -81,41 +81,41 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { jclass c; c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNamePoint); + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't find %s", ClazzNamePoint); } pointClz = (jclass)(*env)->NewGlobalRef(env, c); (*env)->DeleteLocalRef(env, c); if(NULL==pointClz) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't use %s", ClazzNamePoint); + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't use %s", ClazzNamePoint); } pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); if(NULL==pointCstr) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.%s %s", + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't fetch %s.%s %s", ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } c = (*env)->FindClass(env, ClazzNameInsets); if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNameInsets); + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't find %s", ClazzNameInsets); } insetsClz = (jclass)(*env)->NewGlobalRef(env, c); (*env)->DeleteLocalRef(env, c); if(NULL==insetsClz) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't use %s", ClazzNameInsets); + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't use %s", ClazzNameInsets); } insetsCstr = (*env)->GetMethodID(env, insetsClz, ClazzAnyCstrName, ClazzNameInsetsCstrSignature); if(NULL==insetsCstr) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.%s %s", + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't fetch %s.%s %s", ClazzNameInsets, ClazzAnyCstrName, ClazzNameInsetsCstrSignature); } c = (*env)->FindClass(env, ClazzNameRunnable); if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't find %s", ClazzNameRunnable); + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't find %s", ClazzNameRunnable); } runnableRunID = (*env)->GetMethodID(env, c, "run", "()V"); if(NULL==runnableRunID) { - NativewindowCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch %s.run()V", ClazzNameRunnable); + NativewindowCommon_FatalError(env, "FatalError Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0: can't fetch %s.run()V", ClazzNameRunnable); } } return JNI_TRUE; diff --git a/src/newt/classes/jogamp/newt/driver/ios/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/ios/DisplayDriver.java new file mode 100644 index 000000000..d2bb6de02 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/ios/DisplayDriver.java @@ -0,0 +1,91 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.newt.driver.ios; + +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.ios.IOSGraphicsDevice; +import com.jogamp.nativewindow.util.PixelFormat; + +import jogamp.newt.DisplayImpl; +import jogamp.newt.NEWTJNILibLoader; + +public class DisplayDriver extends DisplayImpl { + + static { + NEWTJNILibLoader.loadNEWT(); + + if(!initUIApplication0()) { + throw new NativeWindowException("Failed to initialize native Application hook"); + } + if(!WindowDriver.initIDs0()) { + throw new NativeWindowException("Failed to initialize jmethodIDs"); + } + if(DEBUG) { + System.err.println("MacDisplay.init App and IDs OK "+Thread.currentThread().getName()); + } + } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + + public DisplayDriver() { + } + + @Override + public PixelFormat getNativePointerIconPixelFormat() { return PixelFormat.RGBA8888; } + + @Override + protected void dispatchMessagesNative() { + // nop + } + + @Override + protected void createNativeImpl() { + aDevice = new IOSGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + } + + @Override + protected void closeNativeImpl(final AbstractGraphicsDevice aDevice) { + aDevice.close(); + } + + /** + * {@inheritDoc} + * <p> + * NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly! + * </p> + */ + @Override + public final boolean getNativePointerIconForceDirectNIO() { return true; } + + private static native boolean initUIApplication0(); +} + diff --git a/src/newt/classes/jogamp/newt/driver/ios/MacKeyUtil.java b/src/newt/classes/jogamp/newt/driver/ios/MacKeyUtil.java new file mode 100644 index 000000000..e65602959 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/ios/MacKeyUtil.java @@ -0,0 +1,426 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.newt.driver.ios; + +import com.jogamp.newt.event.KeyEvent; + +public class MacKeyUtil { + + // + // KeyCodes (Layout Dependent) + // + private static final short kVK_ANSI_A = 0x00; + private static final short kVK_ANSI_S = 0x01; + private static final short kVK_ANSI_D = 0x02; + private static final short kVK_ANSI_F = 0x03; + private static final short kVK_ANSI_H = 0x04; + private static final short kVK_ANSI_G = 0x05; + private static final short kVK_ANSI_Z = 0x06; + private static final short kVK_ANSI_X = 0x07; + private static final short kVK_ANSI_C = 0x08; + private static final short kVK_ANSI_V = 0x09; + private static final short kVK_ANSI_B = 0x0B; + private static final short kVK_ANSI_Q = 0x0C; + private static final short kVK_ANSI_W = 0x0D; + private static final short kVK_ANSI_E = 0x0E; + private static final short kVK_ANSI_R = 0x0F; + private static final short kVK_ANSI_Y = 0x10; + private static final short kVK_ANSI_T = 0x11; + private static final short kVK_ANSI_1 = 0x12; + private static final short kVK_ANSI_2 = 0x13; + private static final short kVK_ANSI_3 = 0x14; + private static final short kVK_ANSI_4 = 0x15; + private static final short kVK_ANSI_6 = 0x16; + private static final short kVK_ANSI_5 = 0x17; + private static final short kVK_ANSI_Equal = 0x18; + private static final short kVK_ANSI_9 = 0x19; + private static final short kVK_ANSI_7 = 0x1A; + private static final short kVK_ANSI_Minus = 0x1B; + private static final short kVK_ANSI_8 = 0x1C; + private static final short kVK_ANSI_0 = 0x1D; + private static final short kVK_ANSI_RightBracket = 0x1E; + private static final short kVK_ANSI_O = 0x1F; + private static final short kVK_ANSI_U = 0x20; + private static final short kVK_ANSI_LeftBracket = 0x21; + private static final short kVK_ANSI_I = 0x22; + private static final short kVK_ANSI_P = 0x23; + private static final short kVK_ANSI_L = 0x25; + private static final short kVK_ANSI_J = 0x26; + private static final short kVK_ANSI_Quote = 0x27; + private static final short kVK_ANSI_K = 0x28; + private static final short kVK_ANSI_Semicolon = 0x29; + private static final short kVK_ANSI_Backslash = 0x2A; + private static final short kVK_ANSI_Comma = 0x2B; + private static final short kVK_ANSI_Slash = 0x2C; + private static final short kVK_ANSI_N = 0x2D; + private static final short kVK_ANSI_M = 0x2E; + private static final short kVK_ANSI_Period = 0x2F; + private static final short kVK_ANSI_Grave = 0x32; + private static final short kVK_ANSI_KeypadDecimal = 0x41; + private static final short kVK_ANSI_KeypadMultiply = 0x43; + private static final short kVK_ANSI_KeypadPlus = 0x45; + private static final short kVK_ANSI_KeypadClear = 0x47; + private static final short kVK_ANSI_KeypadDivide = 0x4B; + private static final short kVK_ANSI_KeypadEnter = 0x4C; + private static final short kVK_ANSI_KeypadMinus = 0x4E; + private static final short kVK_ANSI_KeypadEquals = 0x51; + private static final short kVK_ANSI_Keypad0 = 0x52; + private static final short kVK_ANSI_Keypad1 = 0x53; + private static final short kVK_ANSI_Keypad2 = 0x54; + private static final short kVK_ANSI_Keypad3 = 0x55; + private static final short kVK_ANSI_Keypad4 = 0x56; + private static final short kVK_ANSI_Keypad5 = 0x57; + private static final short kVK_ANSI_Keypad6 = 0x58; + private static final short kVK_ANSI_Keypad7 = 0x59; + private static final short kVK_ANSI_Keypad8 = 0x5B; + private static final short kVK_ANSI_Keypad9 = 0x5C; + + // + // KeyCodes (Layout Independent) + // + private static final short kVK_Return = 0x24; + private static final short kVK_Tab = 0x30; + private static final short kVK_Space = 0x31; + private static final short kVK_Delete = 0x33; + private static final short kVK_Escape = 0x35; + private static final short kVK_Command = 0x37; + private static final short kVK_Shift = 0x38; + private static final short kVK_CapsLock = 0x39; + private static final short kVK_Option = 0x3A; + private static final short kVK_Control = 0x3B; + private static final short kVK_RightShift = 0x3C; + private static final short kVK_RightOption = 0x3D; + private static final short kVK_RightControl = 0x3E; + // private static final short kVK_Function = 0x3F; + private static final short kVK_F17 = 0x40; + // private static final short kVK_VolumeUp = 0x48; + // private static final short kVK_VolumeDown = 0x49; + // private static final short kVK_Mute = 0x4A; + private static final short kVK_F18 = 0x4F; + private static final short kVK_F19 = 0x50; + private static final short kVK_F20 = 0x5A; + private static final short kVK_F5 = 0x60; + private static final short kVK_F6 = 0x61; + private static final short kVK_F7 = 0x62; + private static final short kVK_F3 = 0x63; + private static final short kVK_F8 = 0x64; + private static final short kVK_F9 = 0x65; + private static final short kVK_F11 = 0x67; + private static final short kVK_F13 = 0x69; + private static final short kVK_F16 = 0x6A; + private static final short kVK_F14 = 0x6B; + private static final short kVK_F10 = 0x6D; + private static final short kVK_F12 = 0x6F; + private static final short kVK_F15 = 0x71; + private static final short kVK_Help = 0x72; + private static final short kVK_Home = 0x73; + private static final short kVK_PageUp = 0x74; + private static final short kVK_ForwardDelete = 0x75; + private static final short kVK_F4 = 0x76; + private static final short kVK_End = 0x77; + private static final short kVK_F2 = 0x78; + private static final short kVK_PageDown = 0x79; + private static final short kVK_F1 = 0x7A; + private static final short kVK_LeftArrow = 0x7B; + private static final short kVK_RightArrow = 0x7C; + private static final short kVK_DownArrow = 0x7D; + private static final short kVK_UpArrow = 0x7E; + + // + // Key constants handled differently on Mac OS X than other platforms + // + private static final char NSUpArrowFunctionKey = 0xF700; + private static final char NSDownArrowFunctionKey = 0xF701; + private static final char NSLeftArrowFunctionKey = 0xF702; + private static final char NSRightArrowFunctionKey = 0xF703; + private static final char NSF1FunctionKey = 0xF704; + private static final char NSF2FunctionKey = 0xF705; + private static final char NSF3FunctionKey = 0xF706; + private static final char NSF4FunctionKey = 0xF707; + private static final char NSF5FunctionKey = 0xF708; + private static final char NSF6FunctionKey = 0xF709; + private static final char NSF7FunctionKey = 0xF70A; + private static final char NSF8FunctionKey = 0xF70B; + private static final char NSF9FunctionKey = 0xF70C; + private static final char NSF10FunctionKey = 0xF70D; + private static final char NSF11FunctionKey = 0xF70E; + private static final char NSF12FunctionKey = 0xF70F; + private static final char NSF13FunctionKey = 0xF710; + private static final char NSF14FunctionKey = 0xF711; + private static final char NSF15FunctionKey = 0xF712; + private static final char NSF16FunctionKey = 0xF713; + private static final char NSF17FunctionKey = 0xF714; + private static final char NSF18FunctionKey = 0xF715; + private static final char NSF19FunctionKey = 0xF716; + private static final char NSF20FunctionKey = 0xF717; + private static final char NSF21FunctionKey = 0xF718; + private static final char NSF22FunctionKey = 0xF719; + private static final char NSF23FunctionKey = 0xF71A; + private static final char NSF24FunctionKey = 0xF71B; + /** + private static final char NSF25FunctionKey = 0xF71C; + private static final char NSF26FunctionKey = 0xF71D; + private static final char NSF27FunctionKey = 0xF71E; + private static final char NSF28FunctionKey = 0xF71F; + private static final char NSF29FunctionKey = 0xF720; + private static final char NSF30FunctionKey = 0xF721; + private static final char NSF31FunctionKey = 0xF722; + private static final char NSF32FunctionKey = 0xF723; + private static final char NSF33FunctionKey = 0xF724; + private static final char NSF34FunctionKey = 0xF725; + private static final char NSF35FunctionKey = 0xF726; + */ + private static final char NSInsertFunctionKey = 0xF727; + private static final char NSDeleteFunctionKey = 0xF728; + private static final char NSHomeFunctionKey = 0xF729; + private static final char NSBeginFunctionKey = 0xF72A; + private static final char NSEndFunctionKey = 0xF72B; + private static final char NSPageUpFunctionKey = 0xF72C; + private static final char NSPageDownFunctionKey = 0xF72D; + private static final char NSPrintScreenFunctionKey = 0xF72E; + private static final char NSScrollLockFunctionKey = 0xF72F; + private static final char NSPauseFunctionKey = 0xF730; + // private static final char NSSysReqFunctionKey = 0xF731; + // private static final char NSBreakFunctionKey = 0xF732; + // private static final char NSResetFunctionKey = 0xF733; + private static final char NSStopFunctionKey = 0xF734; + /** + private static final char NSMenuFunctionKey = 0xF735; + private static final char NSUserFunctionKey = 0xF736; + private static final char NSSystemFunctionKey = 0xF737; + private static final char NSPrintFunctionKey = 0xF738; + private static final char NSClearLineFunctionKey = 0xF739; + private static final char NSClearDisplayFunctionKey = 0xF73A; + private static final char NSInsertLineFunctionKey = 0xF73B; + private static final char NSDeleteLineFunctionKey = 0xF73C; + private static final char NSInsertCharFunctionKey = 0xF73D; + private static final char NSDeleteCharFunctionKey = 0xF73E; + private static final char NSPrevFunctionKey = 0xF73F; + private static final char NSNextFunctionKey = 0xF740; + private static final char NSSelectFunctionKey = 0xF741; + private static final char NSExecuteFunctionKey = 0xF742; + private static final char NSUndoFunctionKey = 0xF743; + private static final char NSRedoFunctionKey = 0xF744; + private static final char NSFindFunctionKey = 0xF745; + private static final char NSHelpFunctionKey = 0xF746; + private static final char NSModeSwitchFunctionKey = 0xF747; + */ + + static short validateKeyCode(final short keyCode, final char keyChar) { + // OS X Virtual Keycodes + switch(keyCode) { + // + // KeyCodes (Layout Dependent) + // + case kVK_ANSI_A: return KeyEvent.VK_A; + case kVK_ANSI_S: return KeyEvent.VK_S; + case kVK_ANSI_D: return KeyEvent.VK_D; + case kVK_ANSI_F: return KeyEvent.VK_F; + case kVK_ANSI_H: return KeyEvent.VK_H; + case kVK_ANSI_G: return KeyEvent.VK_G; + case kVK_ANSI_Z: return KeyEvent.VK_Z; + case kVK_ANSI_X: return KeyEvent.VK_X; + case kVK_ANSI_C: return KeyEvent.VK_C; + case kVK_ANSI_V: return KeyEvent.VK_V; + case kVK_ANSI_B: return KeyEvent.VK_B; + case kVK_ANSI_Q: return KeyEvent.VK_Q; + case kVK_ANSI_W: return KeyEvent.VK_W; + case kVK_ANSI_E: return KeyEvent.VK_E; + case kVK_ANSI_R: return KeyEvent.VK_R; + case kVK_ANSI_Y: return KeyEvent.VK_Y; + case kVK_ANSI_T: return KeyEvent.VK_T; + case kVK_ANSI_1: return KeyEvent.VK_1; + case kVK_ANSI_2: return KeyEvent.VK_2; + case kVK_ANSI_3: return KeyEvent.VK_3; + case kVK_ANSI_4: return KeyEvent.VK_4; + case kVK_ANSI_6: return KeyEvent.VK_6; + case kVK_ANSI_5: return KeyEvent.VK_5; + case kVK_ANSI_Equal: return KeyEvent.VK_EQUALS; + case kVK_ANSI_9: return KeyEvent.VK_9; + case kVK_ANSI_7: return KeyEvent.VK_7; + case kVK_ANSI_Minus: return KeyEvent.VK_MINUS; + case kVK_ANSI_8: return KeyEvent.VK_8; + case kVK_ANSI_0: return KeyEvent.VK_0; + case kVK_ANSI_RightBracket: return KeyEvent.VK_CLOSE_BRACKET; + case kVK_ANSI_O: return KeyEvent.VK_O; + case kVK_ANSI_U: return KeyEvent.VK_U; + case kVK_ANSI_LeftBracket: return KeyEvent.VK_OPEN_BRACKET; + case kVK_ANSI_I: return KeyEvent.VK_I; + case kVK_ANSI_P: return KeyEvent.VK_P; + case kVK_ANSI_L: return KeyEvent.VK_L; + case kVK_ANSI_J: return KeyEvent.VK_J; + case kVK_ANSI_Quote: return KeyEvent.VK_QUOTE; + case kVK_ANSI_K: return KeyEvent.VK_K; + case kVK_ANSI_Semicolon: return KeyEvent.VK_SEMICOLON; + case kVK_ANSI_Backslash: return KeyEvent.VK_BACK_SLASH; + case kVK_ANSI_Comma: return KeyEvent.VK_COMMA; + case kVK_ANSI_Slash: return KeyEvent.VK_SLASH; + case kVK_ANSI_N: return KeyEvent.VK_N; + case kVK_ANSI_M: return KeyEvent.VK_M; + case kVK_ANSI_Period: return KeyEvent.VK_PERIOD; + case kVK_ANSI_Grave: return KeyEvent.VK_BACK_QUOTE; // KeyEvent.VK_DEAD_GRAVE + case kVK_ANSI_KeypadDecimal: return KeyEvent.VK_DECIMAL; + case kVK_ANSI_KeypadMultiply: return KeyEvent.VK_MULTIPLY; + case kVK_ANSI_KeypadPlus: return KeyEvent.VK_PLUS; + case kVK_ANSI_KeypadClear: return KeyEvent.VK_CLEAR; + case kVK_ANSI_KeypadDivide: return KeyEvent.VK_DIVIDE; + case kVK_ANSI_KeypadEnter: return KeyEvent.VK_ENTER; + case kVK_ANSI_KeypadMinus: return KeyEvent.VK_MINUS; + case kVK_ANSI_KeypadEquals: return KeyEvent.VK_EQUALS; + case kVK_ANSI_Keypad0: return KeyEvent.VK_0; + case kVK_ANSI_Keypad1: return KeyEvent.VK_1; + case kVK_ANSI_Keypad2: return KeyEvent.VK_2; + case kVK_ANSI_Keypad3: return KeyEvent.VK_3; + case kVK_ANSI_Keypad4: return KeyEvent.VK_4; + case kVK_ANSI_Keypad5: return KeyEvent.VK_5; + case kVK_ANSI_Keypad6: return KeyEvent.VK_6; + case kVK_ANSI_Keypad7: return KeyEvent.VK_7; + case kVK_ANSI_Keypad8: return KeyEvent.VK_8; + case kVK_ANSI_Keypad9: return KeyEvent.VK_9; + + // + // KeyCodes (Layout Independent) + // + case kVK_Return: return KeyEvent.VK_ENTER; + case kVK_Tab: return KeyEvent.VK_TAB; + case kVK_Space: return KeyEvent.VK_SPACE; + case kVK_Delete: return KeyEvent.VK_BACK_SPACE; + case kVK_Escape: return KeyEvent.VK_ESCAPE; + case kVK_Command: return KeyEvent.VK_WINDOWS; + case kVK_Shift: return KeyEvent.VK_SHIFT; + case kVK_CapsLock: return KeyEvent.VK_CAPS_LOCK; + case kVK_Option: return KeyEvent.VK_ALT; + case kVK_Control: return KeyEvent.VK_CONTROL; + case kVK_RightShift: return KeyEvent.VK_SHIFT; + case kVK_RightOption: return KeyEvent.VK_ALT_GRAPH; + case kVK_RightControl: return KeyEvent.VK_CONTROL; + // case kVK_Function: return KeyEvent.VK_F; + case kVK_F17: return KeyEvent.VK_F17; + // case kVK_VolumeUp: + // case kVK_VolumeDown: + // case kVK_Mute: + case kVK_F18: return KeyEvent.VK_F18; + case kVK_F19: return KeyEvent.VK_F19; + case kVK_F20: return KeyEvent.VK_F20; + case kVK_F5: return KeyEvent.VK_F5; + case kVK_F6: return KeyEvent.VK_F6; + case kVK_F7: return KeyEvent.VK_F7; + case kVK_F3: return KeyEvent.VK_F3; + case kVK_F8: return KeyEvent.VK_F8; + case kVK_F9: return KeyEvent.VK_F9; + case kVK_F11: return KeyEvent.VK_F11; + case kVK_F13: return KeyEvent.VK_F13; + case kVK_F16: return KeyEvent.VK_F16; + case kVK_F14: return KeyEvent.VK_F14; + case kVK_F10: return KeyEvent.VK_F10; + case kVK_F12: return KeyEvent.VK_F12; + case kVK_F15: return KeyEvent.VK_F15; + case kVK_Help: return KeyEvent.VK_HELP; + case kVK_Home: return KeyEvent.VK_HOME; + case kVK_PageUp: return KeyEvent.VK_PAGE_UP; + case kVK_ForwardDelete: return KeyEvent.VK_DELETE; + case kVK_F4: return KeyEvent.VK_F4; + case kVK_End: return KeyEvent.VK_END; + case kVK_F2: return KeyEvent.VK_F2; + case kVK_PageDown: return KeyEvent.VK_PAGE_DOWN; + case kVK_F1: return KeyEvent.VK_F1; + case kVK_LeftArrow: return KeyEvent.VK_LEFT; + case kVK_RightArrow: return KeyEvent.VK_RIGHT; + case kVK_DownArrow: return KeyEvent.VK_DOWN; + case kVK_UpArrow: return KeyEvent.VK_UP; + } + + switch (keyChar) { + case NSUpArrowFunctionKey: return KeyEvent.VK_UP; + case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; + case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; + case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; + case NSF1FunctionKey: return KeyEvent.VK_F1; + case NSF2FunctionKey: return KeyEvent.VK_F2; + case NSF3FunctionKey: return KeyEvent.VK_F3; + case NSF4FunctionKey: return KeyEvent.VK_F4; + case NSF5FunctionKey: return KeyEvent.VK_F5; + case NSF6FunctionKey: return KeyEvent.VK_F6; + case NSF7FunctionKey: return KeyEvent.VK_F7; + case NSF8FunctionKey: return KeyEvent.VK_F8; + case NSF9FunctionKey: return KeyEvent.VK_F9; + case NSF10FunctionKey: return KeyEvent.VK_F10; + case NSF11FunctionKey: return KeyEvent.VK_F11; + case NSF12FunctionKey: return KeyEvent.VK_F12; + case NSF13FunctionKey: return KeyEvent.VK_F13; + case NSF14FunctionKey: return KeyEvent.VK_F14; + case NSF15FunctionKey: return KeyEvent.VK_F15; + case NSF16FunctionKey: return KeyEvent.VK_F16; + case NSF17FunctionKey: return KeyEvent.VK_F17; + case NSF18FunctionKey: return KeyEvent.VK_F18; + case NSF19FunctionKey: return KeyEvent.VK_F19; + case NSF20FunctionKey: return KeyEvent.VK_F20; + case NSF21FunctionKey: return KeyEvent.VK_F21; + case NSF22FunctionKey: return KeyEvent.VK_F22; + case NSF23FunctionKey: return KeyEvent.VK_F23; + case NSF24FunctionKey: return KeyEvent.VK_F24; + case NSInsertFunctionKey: return KeyEvent.VK_INSERT; + case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; + case NSHomeFunctionKey: return KeyEvent.VK_HOME; + case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; + case NSEndFunctionKey: return KeyEvent.VK_END; + case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; + case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; + case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; + case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; + case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; + // Not handled: + // NSSysReqFunctionKey + // NSBreakFunctionKey + // NSResetFunctionKey + case NSStopFunctionKey: return KeyEvent.VK_STOP; + // Not handled: + // NSMenuFunctionKey + // NSUserFunctionKey + // NSSystemFunctionKey + // NSPrintFunctionKey + // NSClearLineFunctionKey + // NSClearDisplayFunctionKey + // NSInsertLineFunctionKey + // NSDeleteLineFunctionKey + // NSInsertCharFunctionKey + // NSDeleteCharFunctionKey + // NSPrevFunctionKey + // NSNextFunctionKey + // NSSelectFunctionKey + // NSExecuteFunctionKey + // NSUndoFunctionKey + // NSRedoFunctionKey + // NSFindFunctionKey + // NSHelpFunctionKey + // NSModeSwitchFunctionKey + } + + return (short) keyChar; // let's hope for the best (compatibility of keyChar/keyCode's) + } +} diff --git a/src/newt/classes/jogamp/newt/driver/ios/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/ios/ScreenDriver.java new file mode 100644 index 000000000..47280865d --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/ios/ScreenDriver.java @@ -0,0 +1,225 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.newt.driver.ios; + +import com.jogamp.nativewindow.DefaultGraphicsScreen; +import com.jogamp.nativewindow.util.Rectangle; + +import jogamp.nativewindow.ios.IOSUtil; +import jogamp.newt.MonitorModeProps; +import jogamp.newt.ScreenImpl; + +import com.jogamp.common.util.ArrayHashSet; +import com.jogamp.newt.Display; +import com.jogamp.newt.MonitorDevice; +import com.jogamp.newt.MonitorMode; +import com.jogamp.opengl.math.FloatUtil; + +public class ScreenDriver extends ScreenImpl { + + static { + DisplayDriver.initSingleton(); + } + + public ScreenDriver() { + } + + @Override + protected void createNativeImpl() { + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); + } + + @Override + protected void closeNativeImpl() { } + + private MonitorMode getMonitorModeImpl(final MonitorModeProps.Cache cache, final int crt_id, final int mode_idx) { + final int[] modeProps = getMonitorMode0(crt_id, mode_idx); + final MonitorMode res; + if (null == modeProps || 0 >= modeProps.length) { + res = null; + } else { + res = MonitorModeProps.streamInMonitorMode(null, cache, modeProps, 0); + } + return res; + } + + class CrtProps { + CrtProps() { + crtIDs = getMonitorDeviceIds0(); + count = crtIDs.length; + pixelScaleArray = new float[count]; + propsOrigArray = new int[count][]; + propsFixedArray = new int[count][]; + + // + // Gather whole topology of monitors (NSScreens) + // + for(int crtIdx=0; crtIdx<count; crtIdx++) { + final int crt_id = crtIDs[crtIdx]; + final float pixelScaleRaw = (float)IOSUtil.GetPixelScaleByDisplayID(crt_id); + pixelScaleArray[crtIdx] = FloatUtil.isZero(pixelScaleRaw, FloatUtil.EPSILON) ? 1.0f : pixelScaleRaw; + propsOrigArray[crtIdx] = getMonitorProps0(crt_id); + if ( null == propsOrigArray[crtIdx] ) { + throw new InternalError("Could not gather device props "+crtIdx+"/"+count+" -> "+Display.toHexString(crt_id)); + } + // copy orig -> fixed + final int propsLen = propsOrigArray[crtIdx].length; + propsFixedArray[crtIdx] = new int[propsLen]; + System.arraycopy(propsOrigArray[crtIdx], 0, propsFixedArray[crtIdx], 0, propsLen); + } + + // + // Fix scaled viewport w/ pixelScale of each monitorProps, + // i.e. size by its own pixelScale and x/y offset by querying it's neighbors. + // + for(int crtIdx=0; crtIdx<count; crtIdx++) { + final int[] thisMonitorProps = propsFixedArray[crtIdx]; + final int x = thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+0]; + final int y = thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+1]; + final float thisPixelScale = pixelScaleArray[crtIdx]; + thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+2] *= thisPixelScale; // fix width + thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+3] *= thisPixelScale; // fix height + if( 0 != x ) { + // find matching viewport width for x-offset to apply it's pixelSize + for(int i=0; i<count; i++) { + if( i != crtIdx && x == propsOrigArray[i][MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+2] ) { + thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+0] *= pixelScaleArray[i]; + break; + } + } + } + if( 0 != y ) { + // find matching viewport height for y-offset to apply it's pixelSize + for(int i=0; i<count; i++) { + if( i != crtIdx && y == propsOrigArray[i][MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+3] ) { + thisMonitorProps[MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT+1] *= pixelScaleArray[i]; + break; + } + } + } + } + } + int getIndex(final int crt_id) { + for(int i=0; i<count; i++) { + if( crt_id == crtIDs[i] ) { + return i; + } + } + return -1; + } + final int count; + final int[] crtIDs; + final float[] pixelScaleArray; + final int[][] propsOrigArray; + final int[][] propsFixedArray; + } + + @Override + protected final void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) { + final CrtProps crtProps = new CrtProps(); + + // + // Collect all monitorModes for all monitorDevices + // + for(int crtIdx=0; crtIdx<crtProps.count; crtIdx++) { + final int crt_id = crtProps.crtIDs[crtIdx]; + final ArrayHashSet<MonitorMode> supportedModes = + new ArrayHashSet<MonitorMode>(false, ArrayHashSet.DEFAULT_INITIAL_CAPACITY, ArrayHashSet.DEFAULT_LOAD_FACTOR); + int modeIdx = 0; + { + // Get all supported modes for this monitorDevice + MonitorMode mode; + while( true ) { + mode = getMonitorModeImpl(cache, crt_id, modeIdx); + if( null != mode ) { + if( mode.getSurfaceSize().getBitsPerPixel() >= 24 ) { // drop otherwise + supportedModes.getOrAdd(mode); + } + modeIdx++; // next mode on same monitor + } else { + break; // done with modes on this monitor + } + } + } + if( 0 >= modeIdx ) { + throw new InternalError("Could not gather single mode of device "+crtIdx+"/"+crtProps.count+" -> "+Display.toHexString(crt_id)); + } + final MonitorMode currentMode = getMonitorModeImpl(cache, crt_id, -1); + if ( null == currentMode ) { + throw new InternalError("Could not gather current mode of device "+crtIdx+"/"+crtProps.count+" -> "+Display.toHexString(crt_id)+", but gathered "+modeIdx+" modes"); + } + // merge monitor-props + supported modes + final float pixelScale = crtProps.pixelScaleArray[crtIdx]; + MonitorModeProps.streamInMonitorDevice(cache, this, currentMode, + new float[] { pixelScale, pixelScale }, + supportedModes, crtProps.propsFixedArray[crtIdx], 0, null); + } + } + + @Override + protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, final float[] pixelScale, final Rectangle viewportPU, final Rectangle viewportWU) { + final CrtProps crtProps = new CrtProps(); + final int crt_id = monitor.getId(); + if( 0 == crt_id ) { + throw new IllegalArgumentException("Invalid monitor id "+Display.toHexString(crt_id)); + } + final int crt_idx = crtProps.getIndex(crt_id); + if( 0 > crt_idx || crt_idx >= crtProps.count ) { + throw new IndexOutOfBoundsException("monitor id "+crt_idx+" not within [0.."+(crtProps.count-1)+"]"); + } + final int[] fixedMonitorProps = crtProps.propsFixedArray[crt_idx]; + int offset = MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT; + viewportPU.set(fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++]); + viewportWU.set(fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++], fixedMonitorProps[offset++]); + final float _pixelScale = crtProps.pixelScaleArray[crt_idx]; + pixelScale[0] = _pixelScale; + pixelScale[1] = _pixelScale; + return true; + } + + @Override + protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) { + return getMonitorModeImpl(null, monitor.getId(), -1); + } + + @Override + protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) { + return setMonitorMode0(monitor.getId(), mode.getId(), mode.getRotation()); + } + + @Override + protected int validateScreenIndex(final int idx) { + return 0; // big-desktop w/ multiple monitor attached, only one screen available + } + + private native int[] getMonitorDeviceIds0(); + private native int[] getMonitorProps0(int crt_id); + private native int[] getMonitorMode0(int crt_id, int mode_idx); + private native boolean setMonitorMode0(int crt_id, int nativeId, int rot); +} diff --git a/src/newt/classes/jogamp/newt/driver/ios/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/ios/WindowDriver.java new file mode 100644 index 000000000..2a257436a --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/ios/WindowDriver.java @@ -0,0 +1,812 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.newt.driver.ios; + +import com.jogamp.common.util.InterruptSource; +import com.jogamp.nativewindow.AbstractGraphicsConfiguration; +import com.jogamp.nativewindow.GraphicsConfigurationFactory; +import com.jogamp.nativewindow.NativeWindow; +import com.jogamp.nativewindow.NativeWindowException; +import com.jogamp.nativewindow.MutableSurface; +import com.jogamp.nativewindow.ScalableSurface; +import com.jogamp.nativewindow.VisualIDHolder; +import com.jogamp.nativewindow.util.Point; +import com.jogamp.nativewindow.util.PointImmutable; + +import jogamp.nativewindow.SurfaceScaleUtils; +import jogamp.nativewindow.ios.IOSUtil; +import jogamp.newt.ScreenImpl; +import jogamp.newt.WindowImpl; +import jogamp.newt.driver.DriverClearFocus; +import jogamp.newt.driver.DriverUpdatePosition; + +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.MonitorEvent; +import com.jogamp.opengl.math.FloatUtil; + +public class WindowDriver extends WindowImpl implements MutableSurface, DriverClearFocus, DriverUpdatePosition { + + static { + DisplayDriver.initSingleton(); + } + + public WindowDriver() { + } + + private boolean updatePixelScale(final boolean sendEvent, final boolean defer, final boolean deferOffThread, + final float newPixelScaleRaw, final float maxPixelScaleRaw) { + final float[] newPixelScale = new float[2]; + { + final float _newPixelScale = FloatUtil.isZero(newPixelScaleRaw, FloatUtil.EPSILON) ? ScalableSurface.IDENTITY_PIXELSCALE : newPixelScaleRaw; + newPixelScale[0]= _newPixelScale; + newPixelScale[1]= _newPixelScale; + final float _maxPixelScale = FloatUtil.isZero(maxPixelScaleRaw, FloatUtil.EPSILON) ? ScalableSurface.IDENTITY_PIXELSCALE : maxPixelScaleRaw; + maxPixelScale[0]= _maxPixelScale; + maxPixelScale[1]= _maxPixelScale; + } + // We keep minPixelScale at [1f, 1f]! + + if( SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, newPixelScale, minPixelScale, maxPixelScale, DEBUG_IMPLEMENTATION ? getClass().getName() : null) ) { + if( sendEvent ) { + if( deferOffThread ) { + superSizeChangedOffThread(defer, getWidth(), getHeight(), true); + } else { + super.sizeChanged(defer, getWidth(), getHeight(), true); + } + } else { + defineSize(getWidth(), getHeight()); + } + return true; + } else { + return false; + } + } + + private boolean updatePixelScaleByDisplayID(final boolean sendEvent) { + final float maxPixelScaleRaw = (float) IOSUtil.GetPixelScaleByDisplayID(getDisplayID()); + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.updatePixelScale.1: "+hasPixelScale[0]+", "+maxPixelScaleRaw+" (max)"); + } + return updatePixelScale(sendEvent, true /* defer */, false /*offthread */, maxPixelScaleRaw, maxPixelScaleRaw); + } + + private boolean updatePixelScaleByWindowHandle(final boolean sendEvent) { + final long handle = getWindowHandle(); + if( 0 != handle ) { + final float maxPixelScaleRaw = (float)IOSUtil.GetPixelScale(handle); + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.updatePixelScale.2: "+hasPixelScale[0]+", "+maxPixelScaleRaw+" (max)"); + } + return updatePixelScale(sendEvent, true /* defer */, false /*offthread */, maxPixelScaleRaw, maxPixelScaleRaw); + } else { + return false; + } + } + + /** Called from native code */ + protected void updatePixelScale(final boolean defer, final float newPixelScaleRaw, final float maxPixelScaleRaw) { + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.updatePixelScale.3: "+hasPixelScale[0]+" (has) -> "+newPixelScaleRaw+" (new), "+maxPixelScaleRaw+" (max), drop "+!isNativeValid()); + } + if( isNativeValid() ) { + updatePixelScale(true /* sendEvent*/, defer, true /*offthread */, newPixelScaleRaw, maxPixelScaleRaw); + } + } + + @Override + protected final void instantiationFinishedImpl() { + updatePixelScaleByDisplayID(false /* sendEvent*/); + } + + @Override + protected void setScreen(final ScreenImpl newScreen) { // never null ! + super.setScreen(newScreen); + updatePixelScaleByDisplayID(false /* sendEvent*/); // caller (reparent, ..) will send reshape event + } + + @Override + protected void monitorModeChanged(final MonitorEvent me, final boolean success) { + updatePixelScaleByWindowHandle(false /* sendEvent*/); // send reshape event itself + } + + @Override + public final boolean setSurfaceScale(final float[] pixelScale) { + super.setSurfaceScale(pixelScale); + + boolean changed = false; + if( isNativeValid() ) { + if( isOffscreenInstance ) { + final NativeWindow pWin = getParent(); + if( pWin instanceof ScalableSurface ) { + final ScalableSurface sSurf = (ScalableSurface)pWin; + sSurf.setSurfaceScale(reqPixelScale); + sSurf.getMaximumSurfaceScale(maxPixelScale); + sSurf.getMinimumSurfaceScale(minPixelScale); + final float[] pPixelScale = sSurf.getCurrentSurfaceScale(new float[2]); + changed = updatePixelScale(true /* sendEvent */, true /* defer */, true /*offthread */, pPixelScale[0], maxPixelScale[0]); // HiDPI: uniformPixelScale + } else { + // just notify updated pixelScale if offscreen + changed = updatePixelScale(true /* sendEvent */, true /* defer */, true /*offthread */, reqPixelScale[0], maxPixelScale[0]); // HiDPI: uniformPixelScale + } + } else { + // set pixelScale in native code, will issue an update updatePixelScale(..) + // hence we pre-query whether pixel-scale will change, without affecting current state 'hasPixelScale'! + final float[] _hasPixelScale = new float[2]; + System.arraycopy(hasPixelScale, 0, _hasPixelScale, 0, 2); + if( SurfaceScaleUtils.setNewPixelScale(_hasPixelScale, _hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG_IMPLEMENTATION ? getClass().getName() : null) ) { + IOSUtil.RunOnMainThread(true, false, new Runnable() { + @Override + public void run() { + setPixelScale0(getWindowHandle(), surfaceHandle, _hasPixelScale[0]); // HiDPI: uniformPixelScale + } + } ); + changed = true; + } + } + } + if( DEBUG_IMPLEMENTATION ) { + System.err.println("WindowDriver.setPixelScale: min["+minPixelScale[0]+", "+minPixelScale[1]+"], max["+ + maxPixelScale[0]+", "+maxPixelScale[1]+"], req["+ + reqPixelScale[0]+", "+reqPixelScale[1]+"] -> result["+ + hasPixelScale[0]+", "+hasPixelScale[1]+"] - changed "+changed+", realized "+isNativeValid()); + } + return changed; + } + + @Override + protected void createNativeImpl() { + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED); + if (null == cfg) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + setGraphicsConfiguration(cfg); + reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureMask(CHANGE_MASK_VISIBILITY, true)); + if ( !isNativeValid() ) { + throw new NativeWindowException("Error creating window"); + } + } + + @Override + protected void closeNativeImpl() { + try { + if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } + final long handle = getWindowHandle(); + visibleChanged(true, false); + setWindowHandle(0); + surfaceHandle = 0; + sscSurfaceHandle = 0; + isOffscreenInstance = false; + resizeAnimatorPaused = false; + if (0 != handle) { + IOSUtil.RunOnMainThread(false, true /* kickNSApp */, new Runnable() { + @Override + public void run() { + close0( handle ); + } }); + } + } catch (final Throwable t) { + if(DEBUG_IMPLEMENTATION) { + final Exception e = new Exception("Warning: closeNative failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } + } + + @Override + protected int lockSurfaceImpl() { + /** + * if( isOffscreenInstance ) { + * return LOCK_SUCCESS; + * } + */ + final long w = getWindowHandle(); + final long v = surfaceHandle; + if( 0 != v && 0 != w ) { + return lockSurface0(w, v) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; + } + return LOCK_SURFACE_NOT_READY; + } + + @Override + protected void unlockSurfaceImpl() { + /** + * if( isOffscreenInstance ) { + * return; + * } + */ + final long w = getWindowHandle(); + final long v = surfaceHandle; + if(0 != w && 0 != v) { + if( !unlockSurface0(w, v) ) { + throw new NativeWindowException("Failed to unlock surface, probably not locked!"); + } + } + } + + @Override + public final long getSurfaceHandle() { + return 0 != sscSurfaceHandle ? sscSurfaceHandle : surfaceHandle; + } + + @Override + public void setSurfaceHandle(final long surfaceHandle) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + } + sscSurfaceHandle = surfaceHandle; + if ( isNativeValid() ) { + if (0 != sscSurfaceHandle) { + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + orderOut0( 0 != getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() ); + } } ); + } /** this is done by recreation! + else if (isVisible()){ + IOSUtil.RunOnMainThread(false, new Runnable() { + public void run() { + orderFront0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() ); + } } ); + } */ + } + } + + @Override + protected void setTitleImpl(final String title) { + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + setTitle0(getWindowHandle(), title); + } } ); + } + + @Override + protected void requestFocusImpl(final boolean force) { + final boolean _isFullscreen = isFullscreen(); + final boolean _isOffscreenInstance = isOffscreenInstance; + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: requestFocusImpl(), isOffscreenInstance "+_isOffscreenInstance+", isFullscreen "+_isFullscreen); + } + if(!_isOffscreenInstance) { + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + requestFocus0(getWindowHandle(), force); + if(_isFullscreen) { + // 'NewtMacWindow::windowDidBecomeKey()' is not always called in fullscreen-mode! + focusChanged(false, true); + } + } } ); + } else { + focusChanged(false, true); + } + } + + @Override + public final void clearFocus() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: clearFocus(), isOffscreenInstance "+isOffscreenInstance); + } + if(!isOffscreenInstance) { + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + resignFocus0(getWindowHandle()); + } } ); + } else { + focusChanged(false, false); + } + } + + private boolean useParent(final NativeWindow parent) { return null != parent && 0 != parent.getWindowHandle(); } + + @Override + public void updatePosition(final int x, final int y) { + final long handle = getWindowHandle(); + if( 0 != handle && !isOffscreenInstance ) { + final NativeWindow parent = getParent(); + final boolean useParent = useParent(parent); + final Point p0S; + if( useParent ) { + p0S = getLocationOnScreenByParent(x, y, parent); + } else { + p0S = (Point) getLocationOnScreen0(handle, x, y); + } + if(DEBUG_IMPLEMENTATION) { + final int pX=parent.getX(), pY=parent.getY(); + System.err.println("MacWindow: updatePosition() parent["+useParent+" "+pX+"/"+pY+"] "+x+"/"+y+" -> "+x+"/"+y+" rel-client-pos, "+p0S+" screen-client-pos"); + } + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + setWindowClientTopLeftPoint0(getWindowHandle(), p0S.getX(), p0S.getY(), isVisible()); + } } ); + // no native event (fullscreen, some reparenting) + positionChanged(true, x, y); + } + } + + @Override + protected final int getSupportedReconfigMaskImpl() { + return minimumReconfigStateMask | + STATE_MASK_CHILDWIN | + STATE_MASK_UNDECORATED | + STATE_MASK_ALWAYSONTOP | + STATE_MASK_ALWAYSONBOTTOM | + STATE_MASK_STICKY | + STATE_MASK_RESIZABLE | + STATE_MASK_MAXIMIZED_VERT | + STATE_MASK_MAXIMIZED_HORZ | + STATE_MASK_POINTERVISIBLE | + STATE_MASK_POINTERCONFINED; + } + + @Override + protected boolean reconfigureWindowImpl(int _x, int _y, int _width, int _height, final int flags) { + final boolean _isOffscreenInstance = isOffscreenInstance(this, this.getParent()); + isOffscreenInstance = 0 != sscSurfaceHandle || _isOffscreenInstance; + final PointImmutable pClientLevelOnSreen; + if( isOffscreenInstance ) { + _x = 0; _y = 0; + pClientLevelOnSreen = new Point(0, 0); + } else { + final NativeWindow parent = getParent(); + if( useParent(parent) ) { + pClientLevelOnSreen = getLocationOnScreenByParent(_x, _y, parent); + } else { + if( 0 != ( ( CHANGE_MASK_MAXIMIZED_HORZ | CHANGE_MASK_MAXIMIZED_VERT ) & flags ) ) { + final int[] posSize = { _x, _y, _width, _height }; + reconfigMaximizedManual(flags, posSize, getInsets()); + _x = posSize[0]; + _y = posSize[1]; + _width = posSize[2]; + _height = posSize[3]; + } + pClientLevelOnSreen = new Point(_x, _y); + } + } + final int x=_x, y=_y; + final int width=_width, height=_height; + + final boolean hasFocus = hasFocus(); + + if(DEBUG_IMPLEMENTATION) { + final AbstractGraphicsConfiguration cWinCfg = this.getGraphicsConfiguration(); + final NativeWindow pWin = getParent(); + final AbstractGraphicsConfiguration pWinCfg = null != pWin ? pWin.getGraphicsConfiguration() : null; + System.err.println("MacWindow reconfig.0: "+x+"/"+y+" -> clientPosOnScreen "+pClientLevelOnSreen+" - "+width+"x"+height+ + ", "+getReconfigStateMaskString(flags)+ + ",\n\t parent type "+(null != pWin ? pWin.getClass().getName() : null)+ + ",\n\t this-chosenCaps "+(null != cWinCfg ? cWinCfg.getChosenCapabilities() : null)+ + ",\n\t parent-chosenCaps "+(null != pWinCfg ? pWinCfg.getChosenCapabilities() : null)+ + ", isOffscreenInstance(sscSurfaceHandle "+toHexString(sscSurfaceHandle)+ + ", ioi: "+_isOffscreenInstance+ + ") -> "+isOffscreenInstance); + // Thread.dumpStack(); + } + + if( 0 != ( CHANGE_MASK_VISIBILITY & flags) && + 0 == ( STATE_MASK_VISIBLE & flags) ) + { + if ( !isOffscreenInstance ) { + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + orderOut0(getWindowHandle()); + visibleChanged(true, false); + } } ); + } else { + visibleChanged(true, false); + } + } + final long oldWindowHandle = getWindowHandle(); + if( ( 0 == oldWindowHandle && 0 != ( STATE_MASK_VISIBLE & flags) ) || + 0 != ( CHANGE_MASK_PARENTING & flags) || + 0 != ( CHANGE_MASK_DECORATION & flags) || + 0 != ( CHANGE_MASK_ALWAYSONTOP & flags) || + 0 != ( CHANGE_MASK_ALWAYSONBOTTOM & flags) || + 0 != ( CHANGE_MASK_RESIZABLE & flags) || + 0 != ( CHANGE_MASK_FULLSCREEN & flags) ) { + if(isOffscreenInstance) { + createWindow(true, 0 != oldWindowHandle, pClientLevelOnSreen, 64, 64, flags); + } else { + createWindow(false, 0 != oldWindowHandle, pClientLevelOnSreen, width, height, flags); + } + // no native event (fullscreen, some reparenting) + updatePixelScaleByWindowHandle(false /* sendEvent */); + if( isOffscreenInstance) { + super.sizeChanged(false, width, height, true); + positionChanged(false, x, y); + } else { + updateSizePosInsets0(getWindowHandle(), false); + } + visibleChanged(false, 0 != ( STATE_MASK_VISIBLE & flags)); + if( hasFocus ) { + requestFocusImpl(true); + } + } else if( 0 != oldWindowHandle ) { + if( width>0 && height>0 ) { + if( !isOffscreenInstance ) { + IOSUtil.RunOnMainThread(true, false, new Runnable() { + @Override + public void run() { + setWindowClientTopLeftPointAndSize0(oldWindowHandle, + pClientLevelOnSreen.getX(), pClientLevelOnSreen.getY(), + width, height, 0 != ( STATE_MASK_VISIBLE & flags)); + } } ); + updateSizePosInsets0(oldWindowHandle, false); + } else { // else offscreen size is realized via recreation + // no native event (fullscreen, some reparenting) + super.sizeChanged(false, width, height, false); + positionChanged(false, x, y); + } + } + if( 0 != ( CHANGE_MASK_VISIBILITY & flags) && + 0 != ( STATE_MASK_VISIBLE & flags) ) + { + if( !isOffscreenInstance ) { + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + orderFront0(getWindowHandle()); + visibleChanged(true, true); + } } ); + } else { + visibleChanged(true, true); + } + } + } else { + throw new InternalError("Null windowHandle but no re-creation triggered, check visibility: "+getStateMaskString()); + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow reconfig.X: "+getLocationOnScreenImpl(0, 0)+" "+getWidth()+"x"+getHeight()+", insets "+getInsets()+", "+getStateMaskString()); + } + return true; + } + + @Override + protected Point getLocationOnScreenImpl(final int x, final int y) { + final NativeWindow parent = getParent(); + if( useParent(parent) ) { + return getLocationOnScreenByParent(x, y, parent); + } else { + final long windowHandle = getWindowHandle(); + if( !isOffscreenInstance && 0 != windowHandle ) { + return (Point) getLocationOnScreen0(windowHandle, x, y); + } else { + return new Point(x, y); + } + } + } + + private Point getLocationOnScreenByParent(final int x, final int y, final NativeWindow parent) { + return new Point(x, y).translate( parent.getLocationOnScreen(null) ); + } + + /** Callback for native screen position change event of the client area. */ + protected void screenPositionChanged(final boolean defer, final int newX, final int newY) { + // passed coordinates are in screen position of the client area + if( isNativeValid() ) { + final NativeWindow parent = getParent(); + if( !useParent(parent) || isOffscreenInstance ) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.positionChanged.0 (Screen Pos - TOP): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> "+newX+"/"+newY); + } + positionChanged(defer, newX, newY); + } else { + final Runnable action = new Runnable() { + public void run() { + // screen position -> rel child window position + final Point absPos = new Point(newX, newY); + final Point parentOnScreen = parent.getLocationOnScreen(null); + absPos.translate( parentOnScreen.scale(-1, -1) ); + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.positionChanged.1 (Screen Pos - CHILD): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> absPos "+newX+"/"+newY+", parentOnScreen "+parentOnScreen+" -> "+absPos); + } + positionChanged(false, absPos.getX(), absPos.getY()); + } }; + if( defer ) { + new InterruptSource.Thread(null, action).start(); + } else { + action.run(); + } + + } + } else if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.positionChanged.2 (Screen Pos - IGN): ("+getThreadName()+"): (defer: "+defer+") "+getX()+"/"+getY()+" -> "+newX+"/"+newY); + } + } + + @Override + protected void sizeChanged(final boolean defer, final int newWidth, final int newHeight, final boolean force) { + if(force || getWidth() != newWidth || getHeight() != newHeight) { + if( isNativeValid() && !isOffscreenInstance ) { + final NativeWindow parent = getParent(); + final boolean useParent = useParent(parent); + if( useParent ) { + final int x=getX(), y=getY(); + final Point p0S = getLocationOnScreenByParent(x, y, parent); + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: sizeChanged() parent["+useParent+" "+x+"/"+y+"] "+getX()+"/"+getY()+" "+newWidth+"x"+newHeight+" -> "+p0S+" screen-client-pos"); + } + IOSUtil.RunOnMainThread(false, false, new Runnable() { + @Override + public void run() { + setWindowClientTopLeftPoint0(getWindowHandle(), p0S.getX(), p0S.getY(), isVisible()); + } } ); + } + } + superSizeChangedOffThread(defer, newWidth, newHeight, force); + } + } + private void superSizeChangedOffThread(final boolean defer, final int newWidth, final int newHeight, final boolean force) { + if( defer ) { + new InterruptSource.Thread() { + public void run() { + WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force); + } }.start(); + } else { + WindowDriver.super.sizeChanged(false /* defer */, newWidth, newHeight, force); + } + } + + // + // Accumulated actions + // + + /** Triggered by implementation's WM events to update the client-area position, size and insets. */ + protected void sizeScreenPosInsetsChanged(final boolean defer, + final int newX, final int newY, + final int newWidth, final int newHeight, + final int left, final int right, final int top, final int bottom, + final boolean force, + final boolean withinLiveResize) { + final LifecycleHook lh = getLifecycleHook(); + if( withinLiveResize && !resizeAnimatorPaused && null!=lh ) { + resizeAnimatorPaused = lh.pauseRenderingAction(); + } + sizeChanged(defer, newWidth, newHeight, force); + screenPositionChanged(defer, newX, newY); + insetsChanged(defer, left, right, top, bottom); + if( !withinLiveResize && resizeAnimatorPaused ) { + resizeAnimatorPaused = false; + if( null!=lh ) { + lh.resumeRenderingAction(); + } + } + } + + @Override + protected final void doMouseEvent(final boolean enqueue, final boolean wait, final short eventType, final int modifiers, + final int x, final int y, final short button, final float[] rotationXYZ, final float rotationScale) { + super.doMouseEvent(enqueue, wait, eventType, modifiers, + SurfaceScaleUtils.scale(x, getPixelScaleX()), + SurfaceScaleUtils.scale(y, getPixelScaleY()), button, rotationXYZ, rotationScale); + } + + @Override + public final void sendKeyEvent(final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) { + throw new InternalError("XXX: Adapt Java Code to Native Code Changes"); + } + + @Override + public final void enqueueKeyEvent(final boolean wait, final short eventType, final int modifiers, final short _keyCode, final short _keySym, final char keyChar) { + throw new InternalError("XXX: Adapt Java Code to Native Code Changes"); + } + + protected final void enqueueKeyEvent(final boolean wait, final short eventType, int modifiers, final short _keyCode, final char keyChar, final char keySymChar) { + // Note that we send the key char for the key code on this + // platform -- we do not get any useful key codes out of the system + final short keyCode = MacKeyUtil.validateKeyCode(_keyCode, keyChar); + final short keySym; + { + final short _keySym = KeyEvent.NULL_CHAR != keySymChar ? KeyEvent.utf16ToVKey(keySymChar) : KeyEvent.VK_UNDEFINED; + keySym = KeyEvent.VK_UNDEFINED != _keySym ? _keySym : keyCode; + } + /** + { + final boolean isModifierKeyCode = KeyEvent.isModifierKey(keyCode); + System.err.println("*** handleKeyEvent: event "+KeyEvent.getEventTypeString(eventType)+ + ", keyCode 0x"+Integer.toHexString(_keyCode)+" -> 0x"+Integer.toHexString(keyCode)+ + ", keySymChar '"+keySymChar+"', 0x"+Integer.toHexString(keySymChar)+" -> 0x"+Integer.toHexString(keySym)+ + ", mods "+toHexString(modifiers)+ + ", was: pressed "+isKeyPressed(keyCode)+", isModifierKeyCode "+isModifierKeyCode+ + ", nativeValid "+isNativeValid()+", isOffscreen "+isOffscreenInstance); + } */ + + // OSX delivery order is PRESSED (t0), RELEASED (t1) and TYPED (t2) -> NEWT order: PRESSED (t0) and RELEASED (t1) + // Auto-Repeat: OSX delivers only PRESSED, inject auto-repeat RELEASE key _before_ PRESSED + switch(eventType) { + case KeyEvent.EVENT_KEY_RELEASED: + if( isKeyCodeTracked(keyCode) ) { + setKeyPressed(keyCode, false); + } + break; + case KeyEvent.EVENT_KEY_PRESSED: + if( isKeyCodeTracked(keyCode) ) { + if( setKeyPressed(keyCode, true) ) { + // key was already pressed + modifiers |= InputEvent.AUTOREPEAT_MASK; + super.enqueueKeyEvent(wait, KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keySym, keyChar); // RELEASED + } + } + break; + } + super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keySym, keyChar); + } + + protected int getDisplayID() { + if( !isOffscreenInstance ) { + return getDisplayID0(getWindowHandle()); + } + return 0; + } + + //---------------------------------------------------------------------- + // Internals only + // + + private void createWindow(final boolean offscreenInstance, final boolean recreate, + final PointImmutable pS, final int width, final int height, + final int flags) + { + final long parentWinHandle = getParentWindowHandle(); + final long preWinHandle = getWindowHandle(); + + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.createWindow on thread "+Thread.currentThread().getName()+ + ": offscreen "+offscreenInstance+", recreate "+recreate+ + ", pS "+pS+", "+width+"x"+height+", state "+getReconfigStateMaskString(flags)+ + ", preWinHandle "+toHexString(preWinHandle)+", parentWin "+toHexString(parentWinHandle)+ + ", surfaceHandle "+toHexString(surfaceHandle)); + // Thread.dumpStack(); + } + + try { + if( 0 != preWinHandle ) { + setWindowHandle(0); + if( 0 == surfaceHandle ) { + throw new NativeWindowException("Internal Error - create w/ window, but no Newt NSView"); + } + IOSUtil.RunOnMainThread(false, false /* kickNSApp */, new Runnable() { + @Override + public void run() { + changeContentView0(parentWinHandle, preWinHandle, 0); + close0( preWinHandle ); + } }); + } else { + if( 0 != surfaceHandle ) { + throw new NativeWindowException("Internal Error - create w/o window, but has Newt NSView"); + } + surfaceHandle = createView0(pS.getX(), pS.getY(), width, height); + if( 0 == surfaceHandle ) { + throw new NativeWindowException("Could not create native view "+Thread.currentThread().getName()+" "+this); + } + } + + final int windowStyle; + { + int ws = 0; + if( 0 != ( STATE_MASK_UNDECORATED & flags) || offscreenInstance ) { + ws = NSBorderlessWindowMask; + } else { + ws = NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask; + if( 0 != ( STATE_MASK_RESIZABLE & flags) ) { + ws |= NSResizableWindowMask; + } + } + windowStyle = ws; + } + // Blocking initialization on main-thread! + final long[] newWin = { 0 }; + IOSUtil.RunOnMainThread(true, false /* kickNSApp */, new Runnable() { + @Override + public void run() { + newWin[0] = createWindow0( pS.getX(), pS.getY(), width, height, + 0 != ( STATE_MASK_FULLSCREEN & flags), + windowStyle, + NSBackingStoreBuffered, surfaceHandle); + if ( newWin[0] != 0 ) { + final boolean isOpaque = getGraphicsConfiguration().getChosenCapabilities().isBackgroundOpaque() && !offscreenInstance; + initWindow0( parentWinHandle, newWin[0], pS.getX(), pS.getY(), width, height, reqPixelScale[0] /* HiDPI uniformPixelScale */, + isOpaque, + !offscreenInstance && 0 != ( STATE_MASK_ALWAYSONTOP & flags), + !offscreenInstance && 0 != ( STATE_MASK_ALWAYSONBOTTOM & flags), + !offscreenInstance && 0 != ( STATE_MASK_VISIBLE & flags), + surfaceHandle); + if( offscreenInstance ) { + orderOut0(0!=parentWinHandle ? parentWinHandle : newWin[0]); + } else { + setTitle0(newWin[0], getTitle()); + } + } + } }); + + if ( newWin[0] == 0 ) { + throw new NativeWindowException("Could not create native window "+Thread.currentThread().getName()+" "+this); + } + setWindowHandle( newWin[0] ); + } catch (final Exception ie) { + ie.printStackTrace(); + } + } + + protected static native boolean initIDs0(); + private native long createView0(int x, int y, int w, int h); + private native long createWindow0(int x, int y, int w, int h, boolean fullscreen, int windowStyle, int backingStoreType, long view); + /** Must be called on Main-Thread */ + private native void initWindow0(long parentWindow, long window, int x, int y, int w, int h, float reqPixelScale, + boolean opaque, boolean atop, boolean abottom, boolean visible, long view); + + private native int getDisplayID0(long window); + private native void setPixelScale0(long window, long view, float reqPixelScale); + private native boolean lockSurface0(long window, long view); + private native boolean unlockSurface0(long window, long view); + /** Must be called on Main-Thread */ + private native void requestFocus0(long window, boolean force); + /** Must be called on Main-Thread */ + private native void resignFocus0(long window); + /** Must be called on Main-Thread. In case this is a child window and parent is still visible, orderBack(..) is issued instead of orderOut(). */ + private native void orderOut0(long window); + /** Must be called on Main-Thread */ + private native void orderFront0(long window); + /** Must be called on Main-Thread */ + private native void close0(long window); + /** Must be called on Main-Thread */ + private native void setTitle0(long window, String title); + private native long contentView0(long window); + /** Must be called on Main-Thread */ + private native void changeContentView0(long parentWindowOrView, long window, long view); + /** Must be called on Main-Thread */ + private native void setWindowClientTopLeftPointAndSize0(long window, int x, int y, int w, int h, boolean display); + /** Must be called on Main-Thread */ + private native void setWindowClientTopLeftPoint0(long window, int x, int y, boolean display); + /** Triggers {@link #sizeScreenPosInsetsChanged(boolean, int, int, int, int, int, int, int, int, boolean)} */ + private native void updateSizePosInsets0(long window, boolean defer); + private static native Object getLocationOnScreen0(long windowHandle, int src_x, int src_y); + + // Window styles + private static final int NSBorderlessWindowMask = 0; + private static final int NSTitledWindowMask = 1 << 0; + private static final int NSClosableWindowMask = 1 << 1; + private static final int NSMiniaturizableWindowMask = 1 << 2; + private static final int NSResizableWindowMask = 1 << 3; + + // Window backing store types + private static final int NSBackingStoreRetained = 0; + private static final int NSBackingStoreNonretained = 1; + private static final int NSBackingStoreBuffered = 2; + + private volatile long surfaceHandle = 0; + private long sscSurfaceHandle = 0; + private boolean isOffscreenInstance = false; + private boolean resizeAnimatorPaused = false; +} diff --git a/src/newt/native/IOSNewtUIWindow.h b/src/newt/native/IOSNewtUIWindow.h new file mode 100644 index 000000000..27ca7f3c7 --- /dev/null +++ b/src/newt/native/IOSNewtUIWindow.h @@ -0,0 +1,152 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#import <UIKit/UIKit.h> +#import <QuartzCore/QuartzCore.h> +#import <pthread.h> +#import "jni.h" + +#include "NewtCommon.h" + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) ; fflush(stderr) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +// #define DBG_LIFECYCLE 1 + +@interface NewtUIView : UIView +{ + jobject javaWindowObject; + + volatile BOOL destroyNotifySent; + volatile int softLockCount; + pthread_mutex_t softLockSync; + + BOOL modsDown[4]; // shift, ctrl, alt/option, win/command +} + +- (id)initWithFrame:(CGRect)frameRect; + +#ifdef DBG_LIFECYCLE +- (void) release; +#endif +- (void) dealloc; + +/* Register or deregister (NULL) the java Window object, + ie, if NULL, no events are send */ +- (void) setJavaWindowObject: (jobject) javaWindowObj; +- (jobject) getJavaWindowObject; + +- (void) setDestroyNotifySent: (BOOL) v; +- (BOOL) getDestroyNotifySent; + +- (BOOL) softLock; +- (BOOL) softUnlock; + +- (void) drawRect:(CGRect)dirtyRect; +- (BOOL) acceptsFirstResponder; +- (BOOL) becomeFirstResponder; +- (BOOL) resignFirstResponder; + +- (void) sendMouseEvent: (UIEvent*) event eventType: (jshort) evType; +- (CGPoint) screenPos2NewtClientWinPos: (CGPoint) p; + +- (void) handleFlagsChanged:(NSUInteger) mods; +- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods; +- (void) sendKeyEvent: (UIEvent*) event eventType: (jshort) evType; +- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType; + +@end + +@interface NewtUIWindow : UIWindow +{ + BOOL realized; + jboolean withinLiveResize; +@public + BOOL hasPresentationSwitch; + NSUInteger defaultPresentationOptions; + NSUInteger fullscreenPresentationOptions; + BOOL isFullscreenWindow; + int cachedInsets[4]; // l, r, t, b +} + ++ (BOOL) initNatives: (JNIEnv*) env forClass: (jobject) clazz; + +- (id) initWithFrame: (CGRect) contentRect + styleMask: (NSUInteger) windowStyle + backing: (NSUInteger) bufferingType + defer: (BOOL) deferCreation + isFullscreenWindow:(BOOL)isfs; +#ifdef DBG_LIFECYCLE +- (void) release; +#endif +- (void) dealloc; +- (void) setRealized: (BOOL)v; +- (BOOL) isRealized; + +- (void) setAlwaysOn: (BOOL)top bottom:(BOOL)bottom; + +- (void) updateInsets: (JNIEnv*) env jwin: (jobject) javaWin; +- (void) updateSizePosInsets: (JNIEnv*) env jwin: (jobject) javaWin defer: (jboolean)defer; +- (void) attachToParent: (UIWindow*) parent; +- (void) detachFromParent: (UIWindow*) parent; + +- (CGPoint) newtRelClientTLWinPos2AbsTLScreenPos: (CGPoint) p; +- (CGSize) newtClientSize2TLSize: (CGSize) nsz; +- (CGPoint) getLocationOnScreen: (CGPoint) p; + +- (void) focusChanged: (BOOL) gained; + +- (void) flagsChanged: (UIEvent *) theEvent; +- (BOOL) acceptsMouseMovedEvents; +- (BOOL) acceptsFirstResponder; +- (BOOL) becomeFirstResponder; +- (BOOL) resignFirstResponder; +- (BOOL) canBecomeKeyWindow; +- (void) becomeKeyWindow; +- (void) resignKeyWindow; +- (void) windowDidBecomeKey: (NSNotification *) notification; +- (void) windowDidResignKey: (NSNotification *) notification; + +- (void) windowWillStartLiveResize: (NSNotification *) notification; +- (void) windowDidEndLiveResize: (NSNotification *) notification; +- (CGSize) windowWillResize: (UIWindow *)sender toSize:(CGSize)frameSize; +- (void) windowDidResize: (NSNotification*) notification; +- (void) sendResizeEvent; + +- (void) windowDidMove: (NSNotification*) notification; +- (BOOL) windowClosingImpl: (BOOL) force; +- (BOOL) windowShouldClose: (id) sender; +- (void) windowWillClose: (NSNotification*) notification; + +@end diff --git a/src/newt/native/IOSNewtUIWindow.m b/src/newt/native/IOSNewtUIWindow.m new file mode 100644 index 000000000..6c5031efc --- /dev/null +++ b/src/newt/native/IOSNewtUIWindow.m @@ -0,0 +1,783 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#import "IOSNewtUIWindow.h" +#import "InputEvent.h" +#import "KeyEvent.h" +#import "MouseEvent.h" + +#include <CoreFoundation/CoreFoundation.h> + +#include <math.h> + +#define PRINTF(...) NSLog(@ __VA_ARGS__) + +static jmethodID enqueueMouseEventID = NULL; +static jmethodID enqueueKeyEventID = NULL; +static jmethodID requestFocusID = NULL; + +static jmethodID insetsChangedID = NULL; +static jmethodID sizeChangedID = NULL; +static jmethodID sizeScreenPosInsetsChangedID = NULL; +static jmethodID updatePixelScaleID = NULL; +static jmethodID visibleChangedID = NULL; +static jmethodID screenPositionChangedID = NULL; +static jmethodID focusChangedID = NULL; +static jmethodID windowDestroyNotifyID = NULL; +static jmethodID windowRepaintID = NULL; + +// Need to enqueue all events to EDT, +// since we may operate on AWT-AppKit (Main Thread) +// and direct issuing 'requestFocus()' would deadlock: +// AWT-AppKit +// AWT-EventQueue-0 + +@implementation NewtUIView + +- (id)initWithFrame:(CGRect)frameRect +{ + id res = [super initWithFrame:frameRect]; + javaWindowObject = NULL; + + destroyNotifySent = NO; + softLockCount = 0; + + pthread_mutexattr_t softLockSyncAttr; + pthread_mutexattr_init(&softLockSyncAttr); + pthread_mutexattr_settype(&softLockSyncAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&softLockSync, &softLockSyncAttr); // recursive + + modsDown[0] = NO; // shift + modsDown[1] = NO; // ctrl + modsDown[2] = NO; // alt + modsDown[3] = NO; // win + + DBG_PRINT("NewtUIView::create: %p (refcnt %d)\n", res, (int)[res retainCount]); + return res; +} + +#ifdef DBG_LIFECYCLE +- (void) release +{ + DBG_PRINT("NewtUIView::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + [super release]; +} +#endif + +- (void) dealloc +{ + DBG_PRINT("NewtUIView::dealloc.0: %p (refcnt %d), ptrTrackingTag %d\n", self, (int)[self retainCount], (int)ptrTrackingTag); +#ifdef DBG_LIFECYCLE + NSLog(@"%@",[NSThread callStackSymbols]); +#endif + if( 0 < softLockCount ) { + NSLog(@"NewtUIView::dealloc: softLock still hold @ dealloc!\n"); + } + + pthread_mutex_destroy(&softLockSync); + DBG_PRINT("NewtUIView::dealloc.X: %p\n", self); + [super dealloc]; +} + +- (void) setJavaWindowObject: (jobject) javaWindowObj +{ + javaWindowObject = javaWindowObj; +} + +- (jobject) getJavaWindowObject +{ + return javaWindowObject; +} + +- (void) setDestroyNotifySent: (BOOL) v +{ + destroyNotifySent = v; +} + +- (BOOL) getDestroyNotifySent +{ + return destroyNotifySent; +} + +- (BOOL) softLock +{ + // DBG_PRINT("*************** softLock.0: %p\n", (void*)pthread_self()); + int err; + if( 0 != ( err = pthread_mutex_lock(&softLockSync) ) ) { + NSLog(@"NewtUIView::softLock failed: errCode %d - %@", err, [NSThread callStackSymbols]); + return NO; + } + softLockCount++; + // DBG_PRINT("*************** softLock.X: %p\n", (void*)pthread_self()); + return 0 < softLockCount; +} + +- (BOOL) softUnlock +{ + // DBG_PRINT("*************** softUnlock: %p\n", (void*)pthread_self()); + softLockCount--; + int err; + if( 0 != ( err = pthread_mutex_unlock(&softLockSync) ) ) { + softLockCount++; + NSLog(@"NewtUIView::softUnlock failed: Not locked by current thread - errCode %d - %@", err, [NSThread callStackSymbols]); + return NO; + } + return YES; +} + +- (void) drawRect:(CGRect)dirtyRect +{ + DBG_PRINT("*************** dirtyRect: %p %lf/%lf %lfx%lf\n", + javaWindowObject, dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height); + + if(NULL==javaWindowObject) { + DBG_PRINT("drawRect: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("drawRect: null JNIEnv\n"); + return; + } + + CGRect viewFrame = [self frame]; + + (*env)->CallVoidMethod(env, javaWindowObject, windowRepaintID, JNI_TRUE, // defer .. + (int)dirtyRect.origin.x, (int)viewFrame.size.height - (int)dirtyRect.origin.y, + (int)dirtyRect.size.width, (int)dirtyRect.size.height); + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +- (BOOL) acceptsFirstResponder +{ + return YES; +} + +- (BOOL) becomeFirstResponder +{ + DBG_PRINT( "*************** View.becomeFirstResponder\n"); + return [super becomeFirstResponder]; +} + +- (BOOL) resignFirstResponder +{ + DBG_PRINT( "*************** View.resignFirstResponder\n"); + return [super resignFirstResponder]; +} + +- (void) sendMouseEvent: (UIEvent*) event eventType: (jshort) evType +{ + if (javaWindowObject == NULL) { + DBG_PRINT("sendMouseEvent: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("sendMouseEvent: null JNIEnv\n"); + return; + } + jint javaMods[] = { 0 } ; + javaMods[0] = 0; // TODO mods2JavaMods([event modifierFlags]); + + // convert to 1-based button number (or use zero if no button is involved) + // TODO: detect mouse button when mouse wheel scrolled + jshort javaButtonNum = 1; + jfloat scrollDeltaY = 0.0f; + /** + switch ([event type]) { + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSLeftMouseDragged: + javaButtonNum = 1; + break; + case NSRightMouseDown: + case NSRightMouseUp: + case NSRightMouseDragged: + javaButtonNum = 3; + break; + case NSOtherMouseDown: + case NSOtherMouseUp: + case NSOtherMouseDragged: + javaButtonNum = 2; + break; + default: + javaButtonNum = 0; + break; + } */ + CGPoint location = CGPointMake(0,0); // TODO [self screenPos2NewtClientWinPos: [UIEvent mouseLocation]]; + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueMouseEventID, JNI_FALSE, + evType, javaMods[0], + (jint) location.x, (jint) location.y, + javaButtonNum, scrollDeltaY); + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +- (CGPoint) screenPos2NewtClientWinPos: (CGPoint) p +{ + CGRect viewFrame = [self frame]; + + CGRect r; + r.origin.x = p.x; + r.origin.y = p.y; + r.size.width = 0; + r.size.height = 0; + // CGRect rS = [[self window] convertRectFromScreen: r]; // 10.7 + CGPoint oS = r.origin; // TODO [[self window] convertScreenToBase: r.origin]; + oS.y = viewFrame.size.height - oS.y; // y-flip + return oS; +} + +- (void) handleFlagsChanged:(NSUInteger) mods +{ + // TODO [self handleFlagsChanged: NSShiftKeyMask keyIndex: 0 keyCode: kVK_Shift modifiers: mods]; + // TODO [self handleFlagsChanged: NSControlKeyMask keyIndex: 1 keyCode: kVK_Control modifiers: mods]; + // TODO [self handleFlagsChanged: NSAlternateKeyMask keyIndex: 2 keyCode: kVK_Option modifiers: mods]; + // TODO [self handleFlagsChanged: NSCommandKeyMask keyIndex: 3 keyCode: kVK_Command modifiers: mods]; +} + +- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods +{ + if ( NO == modsDown[keyIdx] && 0 != ( mods & keyMask ) ) { + modsDown[keyIdx] = YES; + [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_PRESSED]; + } else if ( YES == modsDown[keyIdx] && 0 == ( mods & keyMask ) ) { + modsDown[keyIdx] = NO; + [self sendKeyEvent: (jshort)keyCode characters: NULL modifiers: mods|keyMask eventType: (jshort)EVENT_KEY_RELEASED]; + } +} + +- (void) sendKeyEvent: (UIEvent*) event eventType: (jshort) evType +{ + jshort keyCode = 0; // TODO (jshort) [event keyCode]; + NSString* chars = NULL; // TODO [event charactersIgnoringModifiers]; + NSUInteger mods = 0; // TODO [event modifierFlags]; + [self sendKeyEvent: keyCode characters: chars modifiers: mods eventType: evType]; +} + +- (void) sendKeyEvent: (jshort) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jshort) evType +{ + if (javaWindowObject == NULL) { + DBG_PRINT("sendKeyEvent: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("sendKeyEvent: null JNIEnv\n"); + return; + } + + int i; + int len = NULL != chars ? [chars length] : 0; + jint javaMods = 0; // TODO mods2JavaMods(mods); + + if(len > 0) { + // printable chars + for (i = 0; i < len; i++) { + // Note: the key code in the UIEvent does not map to anything we can use + UniChar keyChar = (UniChar) [chars characterAtIndex: i]; + UniChar keySymChar = 0; // TODO CKCH_CharForKeyCode(keyCode); + + DBG_PRINT("sendKeyEvent: %d/%d code 0x%X, char 0x%X, mods 0x%X/0x%X -> keySymChar 0x%X\n", i, len, (int)keyCode, (int)keyChar, + (int)mods, (int)javaMods, (int)keySymChar); + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, + evType, javaMods, keyCode, (jchar)keyChar, (jchar)keySymChar); + } + } else { + // non-printable chars + jchar keyChar = (jchar) 0; + + DBG_PRINT("sendKeyEvent: code 0x%X\n", (int)keyCode); + + (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE, + evType, javaMods, keyCode, keyChar, keyChar); + } + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +@end + +@implementation NewtUIWindow + ++ (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz +{ + enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZSIIISF)V"); + enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZSISCC)V"); + sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); + updatePixelScaleID = (*env)->GetMethodID(env, clazz, "updatePixelScale", "(ZFF)V"); + visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); + insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); + sizeScreenPosInsetsChangedID = (*env)->GetMethodID(env, clazz, "sizeScreenPosInsetsChanged", "(ZIIIIIIIIZZ)V"); + screenPositionChangedID = (*env)->GetMethodID(env, clazz, "screenPositionChanged", "(ZII)V"); + focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); + windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "(Z)Z"); + windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); + if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && updatePixelScaleID && visibleChangedID && + insetsChangedID && sizeScreenPosInsetsChangedID && + screenPositionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) + { + // TODO CKCH_CreateDictionaries(); + return YES; + } + return NO; +} + +- (id) initWithFrame: (CGRect) contentRect + styleMask: (NSUInteger) windowStyle + backing: (NSUInteger) bufferingType + defer: (BOOL) deferCreation + isFullscreenWindow:(BOOL)isfs +{ + /** + id res = [super initWithContentRect: contentRect + styleMask: windowStyle + backing: bufferingType + defer: deferCreation]; + */ + id res = [super initWithFrame: contentRect]; + // OSX 10.6 + /** TODO + if ( [NSApp respondsToSelector:@selector(currentSystemPresentationOptions)] && + [NSApp respondsToSelector:@selector(setPresentationOptions:)] ) { + hasPresentationSwitch = YES; + defaultPresentationOptions = [NSApp currentSystemPresentationOptions]; + fullscreenPresentationOptions = + // NSApplicationPresentationDefault| + // NSApplicationPresentationAutoHideDock| + NSApplicationPresentationHideDock| + // NSApplicationPresentationAutoHideMenuBar| + NSApplicationPresentationHideMenuBar| + NSApplicationPresentationDisableAppleMenu| + // NSApplicationPresentationDisableProcessSwitching| + // NSApplicationPresentationDisableSessionTermination| + NSApplicationPresentationDisableHideApplication| + // NSApplicationPresentationDisableMenuBarTransparency| + // NSApplicationPresentationFullScreen| // OSX 10.7 + 0 ; + } else { + */ + hasPresentationSwitch = NO; + defaultPresentationOptions = 0; + fullscreenPresentationOptions = 0; + // } + + isFullscreenWindow = NO; // TODO isfs; + // Why is this necessary? Without it we don't get any of the + // delegate methods like resizing and window movement. + // TODO [self setDelegate: self]; + + cachedInsets[0] = 0; // l + cachedInsets[1] = 0; // r + cachedInsets[2] = 0; // t + cachedInsets[3] = 0; // b + + realized = YES; + withinLiveResize = JNI_FALSE; + DBG_PRINT("NewtWindow::create: %p, realized %d, hasPresentationSwitch %d[defaultOptions 0x%X, fullscreenOptions 0x%X], (refcnt %d)\n", + res, realized, (int)hasPresentationSwitch, (int)defaultPresentationOptions, (int)fullscreenPresentationOptions, (int)[res retainCount]); + return res; +} + +#ifdef DBG_LIFECYCLE +- (void) release +{ + DBG_PRINT("NewtWindow::release.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"%@",[NSThread callStackSymbols]); + [super release]; +} +#endif + +- (void) dealloc +{ + DBG_PRINT("NewtWindow::dealloc.0: %p (refcnt %d)\n", self, (int)[self retainCount]); +#ifdef DBG_LIFECYCLE + NSLog(@"%@",[NSThread callStackSymbols]); +#endif + + /** + NewtUIView* mView = (NewtUIView *)self; // TODO [self contentView]; + if( NULL != mView ) { + [mView release]; + } + */ + [super dealloc]; + DBG_PRINT("NewtWindow::dealloc.X: %p\n", self); +} + +- (void) setRealized: (BOOL)v +{ + realized = v; +} + +- (BOOL) isRealized +{ + return realized; +} + +- (void) setAlwaysOn: (BOOL)top bottom:(BOOL)bottom +{ + /** + if( top ) { + DBG_PRINT( "*************** setAlwaysOn -> top\n"); + [self setLevel: kCGMaximumWindowLevel]; + } else if ( bottom ) { + DBG_PRINT( "*************** setAlwaysOn -> bottom\n"); + [self setLevel: kCGDesktopIconWindowLevel]; // w/ input + } else { + DBG_PRINT( "*************** setAlwaysOn -> normal\n"); + [self setLevel:NSNormalWindowLevel]; + } */ +} + +- (void) updateInsets: (JNIEnv*) env jwin: (jobject) javaWin +{ + /** + CGRect frameRect = [self frame]; + CGRect contentRect = [self contentRectForFrameRect: frameRect]; + + // note: this is a simplistic implementation which doesn't take + // into account DPI and scaling factor + CGFloat l = contentRect.origin.x - frameRect.origin.x; + cachedInsets[0] = (int)l; // l + cachedInsets[1] = (int)(frameRect.size.width - (contentRect.size.width + l)); // r + cachedInsets[2] = (jint)(frameRect.size.height - contentRect.size.height); // t + cachedInsets[3] = (jint)(contentRect.origin.y - frameRect.origin.y); // b + */ + UIEdgeInsets uiInsets = [self safeAreaInsets]; + cachedInsets[0] = uiInsets.left; + cachedInsets[1] = uiInsets.right; + cachedInsets[2] = uiInsets.top; + cachedInsets[3] = uiInsets.bottom; + DBG_PRINT( "updateInsets: [ l %d, r %d, t %d, b %d ]\n", cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]); + + if( NULL != env && NULL != javaWin ) { + (*env)->CallVoidMethod(env, javaWin, insetsChangedID, JNI_FALSE, cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3]); + } +} + +- (void) updateSizePosInsets: (JNIEnv*) env jwin: (jobject) javaWin defer: (jboolean)defer +{ + // update insets on every window resize for lack of better hook place + [self updateInsets: NULL jwin:NULL]; + + CGRect frameRect = [self frame]; + + UIScreen* screen = [self screen]; + CGPoint pS = [self convertPoint: frameRect.origin toCoordinateSpace: screen.fixedCoordinateSpace]; + + DBG_PRINT( "updateSize: [ w %d, h %d ], liveResize %d\n", (jint) frameRect.size.width, (jint) frameRect.size.height, (jint)withinLiveResize); + DBG_PRINT( "updatePos: [ x %d, y %d ]\n", (jint) pS.x, (jint) pS.y); + + if( NULL != env && NULL != javaWin ) { + (*env)->CallVoidMethod(env, javaWin, sizeScreenPosInsetsChangedID, defer, + (jint) pS.x, (jint) pS.y, + (jint) frameRect.size.width, (jint) frameRect.size.height, + cachedInsets[0], cachedInsets[1], cachedInsets[2], cachedInsets[3], + JNI_FALSE, // force + withinLiveResize + ); + } +} + + +- (void) attachToParent: (UIWindow*) parent +{ + /** TODO + DBG_PRINT( "attachToParent.1\n"); + [parent addChildWindow: self ordered: UIWindowAbove]; + DBG_PRINT( "attachToParent.2\n"); + [self setParentWindow: parent]; + DBG_PRINT( "attachToParent.X\n"); + */ +} + +- (void) detachFromParent: (UIWindow*) parent +{ + /** TODO + DBG_PRINT( "detachFromParent.1\n"); + [self setParentWindow: nil]; + if(NULL != parent) { + DBG_PRINT( "detachFromParent.2\n"); + [parent removeChildWindow: self]; + } + DBG_PRINT( "detachFromParent.X\n"); + */ +} + +/** + * p rel client window position w/ top-left origin + * returns: abs screen position w/ bottom-left origin + */ +- (CGPoint) newtRelClientTLWinPos2AbsTLScreenPos: (CGPoint) p +{ + return [self getLocationOnScreen: p]; +} + +- (CGSize) newtClientSize2TLSize: (CGSize) nsz +{ + CGSize topSZ = { nsz.width, nsz.height + cachedInsets[2] + cachedInsets[3] }; // height + insets.top + insets.bottom + return topSZ; +} + +/** + * p rel client window position w/ top-left origin + * returns: location in 0/0 top-left space. + */ +- (CGPoint) getLocationOnScreen: (CGPoint) p +{ + UIScreen* screen = [self screen]; + CGPoint pS = [self convertPoint: p toCoordinateSpace: screen.fixedCoordinateSpace]; + +#ifdef VERBOSE_ON + CGRect winFrame = [self frame]; + DBG_PRINT( "getLocationOnScreen: point-in[%d/%d], winFrame[%d/%d %dx%d] -> %d/%d\n", + (int)p.x, (int)p.y, + (int)winFrame.origin.x, (int)winFrame.origin.y, (int)winFrame.size.width, (int)winFrame.size.height, + (int)pS.x, (int)pS.y); +#endif + + return pS; +} + +- (void) focusChanged: (BOOL) gained +{ + DBG_PRINT( "focusChanged: gained %d\n", gained); + NewtUIView* newtView = (NewtUIView *) self; // TODO [self contentView]; + jobject javaWindowObject = [newtView getJavaWindowObject]; + if (javaWindowObject == NULL) { + DBG_PRINT("focusChanged: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("focusChanged: null JNIEnv\n"); + return; + } + + (*env)->CallVoidMethod(env, javaWindowObject, focusChangedID, JNI_FALSE, (gained == YES) ? JNI_TRUE : JNI_FALSE); + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +- (void) flagsChanged:(UIEvent *) theEvent +{ + NSUInteger mods = [theEvent modifierFlags]; + NewtUIView* newtView = (NewtUIView *) [self contentView]; + if( [newtView isKindOfClass:[NewtUIView class]] ) { + [newtView handleFlagsChanged: mods]; + } +} + +- (BOOL) acceptsMouseMovedEvents +{ + return YES; +} + +- (BOOL) acceptsFirstResponder +{ + return YES; +} + +- (BOOL) becomeFirstResponder +{ + DBG_PRINT( "*************** Win.becomeFirstResponder\n"); + return [super becomeFirstResponder]; +} + +- (BOOL) resignFirstResponder +{ + DBG_PRINT( "*************** Win.resignFirstResponder\n"); + return [super resignFirstResponder]; +} + +- (BOOL) canBecomeKeyWindow +{ + // Even if the window is borderless, we still want it to be able + // to become the key window to receive keyboard events + return YES; +} + +- (void) becomeKeyWindow +{ + DBG_PRINT( "*************** becomeKeyWindow\n"); + [super becomeKeyWindow]; +} + +- (void) resignKeyWindow +{ + DBG_PRINT( "*************** resignKeyWindow: isFullscreen %d\n", (int)isFullscreenWindow); + if(!isFullscreenWindow) { + [super resignKeyWindow]; + } +} + +- (void) windowDidResignKey: (NSNotification *) notification +{ + DBG_PRINT( "*************** windowDidResignKey\n"); + // Implicit mouse exit by OS X + [self focusChanged: NO]; +} + +- (void) windowWillStartLiveResize: (NSNotification *) notification +{ + DBG_PRINT( "*************** windowWillStartLiveResize\n"); + withinLiveResize = JNI_TRUE; +} +- (void) windowDidEndLiveResize: (NSNotification *) notification +{ + DBG_PRINT( "*************** windowDidEndLiveResize\n"); + withinLiveResize = JNI_FALSE; + [self sendResizeEvent]; +} +- (CGSize) windowWillResize: (UIWindow *)sender toSize:(CGSize)frameSize +{ + DBG_PRINT( "*************** windowWillResize %lfx%lf\n", frameSize.width, frameSize.height); + return frameSize; +} +- (void)windowDidResize: (NSNotification*) notification +{ + DBG_PRINT( "*************** windowDidResize\n"); + [self sendResizeEvent]; +} + +- (void) sendResizeEvent +{ + jobject javaWindowObject = NULL; + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + + if( NULL == env ) { + DBG_PRINT("windowDidResize: null JNIEnv\n"); + return; + } + NewtUIView* newtView = (NewtUIView *) [self contentView]; + if( [newtView isKindOfClass:[NewtUIView class]] ) { + javaWindowObject = [newtView getJavaWindowObject]; + } + if( NULL != javaWindowObject ) { + [self updateSizePosInsets: env jwin: javaWindowObject defer:JNI_TRUE]; + } + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +- (void)windowDidMove: (NSNotification*) notification +{ + NewtUIView* newtView = (NewtUIView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtUIView class]] ) { + return; + } + jobject javaWindowObject = [newtView getJavaWindowObject]; + if (javaWindowObject == NULL) { + DBG_PRINT("windowDidMove: null javaWindowObject\n"); + return; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("windowDidMove: null JNIEnv\n"); + return; + } + + CGPoint p0 = { 0, 0 }; + p0 = [self getLocationOnScreen: p0]; + DBG_PRINT( "windowDidMove: [ x %d, y %d ]\n", (jint) p0.x, (jint) p0.y); + (*env)->CallVoidMethod(env, javaWindowObject, screenPositionChangedID, JNI_TRUE, (jint) p0.x, (jint) p0.y); + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); +} + +- (BOOL)windowShouldClose: (id) sender +{ + return [self windowClosingImpl: NO]; +} + +- (void)windowWillClose: (NSNotification*) notification +{ + [self windowClosingImpl: YES]; +} + +- (BOOL) windowClosingImpl: (BOOL) force +{ + jboolean closed = JNI_FALSE; + + NewtUIView* newtView = (NewtUIView *) [self contentView]; + if( ! [newtView isKindOfClass:[NewtUIView class]] ) { + return NO; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [newtView cursorHide: NO enter: -1]; + + if( false == [newtView getDestroyNotifySent] ) { + jobject javaWindowObject = [newtView getJavaWindowObject]; + DBG_PRINT( "*************** windowWillClose.0: %p\n", (void *)(intptr_t)javaWindowObject); + if (javaWindowObject == NULL) { + DBG_PRINT("windowWillClose: null javaWindowObject\n"); + [pool release]; + return NO; + } + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(1 /* asDaemon */, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("windowWillClose: null JNIEnv\n"); + [pool release]; + return NO; + } + [newtView setDestroyNotifySent: true]; // earmark assumption of being closed + closed = (*env)->CallBooleanMethod(env, javaWindowObject, windowDestroyNotifyID, force ? JNI_TRUE : JNI_FALSE); + if(!force && !closed) { + // not closed on java side, not force -> clear flag + [newtView setDestroyNotifySent: false]; + } + + // detaching thread not required - daemon + // NewtCommon_ReleaseJNIEnv(shallBeDetached); + DBG_PRINT( "*************** windowWillClose.X: %p, closed %d\n", (void *)(intptr_t)javaWindowObject, (int)closed); + } else { + DBG_PRINT( "*************** windowWillClose (skip)\n"); + } + [pool release]; + return JNI_TRUE == closed ? YES : NO ; +} + +@end + diff --git a/src/newt/native/IOSUIWindow.m b/src/newt/native/IOSUIWindow.m new file mode 100644 index 000000000..780c2344f --- /dev/null +++ b/src/newt/native/IOSUIWindow.m @@ -0,0 +1,1161 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#import <inttypes.h> + +#import "jogamp_newt_driver_ios_WindowDriver.h" +#import "IOSNewtUIWindow.h" + +#import "MouseEvent.h" +#import "KeyEvent.h" +#import "ScreenMode.h" + +#import <stdio.h> + +#ifdef DBG_PERF + #include "timespec.h" +#endif + +static const char * const ClazzNamePoint = "com/jogamp/nativewindow/util/Point"; +static const char * const ClazzAnyCstrName = "<init>"; +static const char * const ClazzNamePointCstrSignature = "(II)V"; +static jclass pointClz = NULL; +static jmethodID pointCstr = NULL; + +static NSString* jstringToNSString(JNIEnv* env, jstring jstr) +{ + const jchar* jstrChars = (*env)->GetStringChars(env, jstr, NULL); + NSString* str = [[NSString alloc] initWithCharacters: jstrChars length: (*env)->GetStringLength(env, jstr)]; + (*env)->ReleaseStringChars(env, jstr, jstrChars); + return str; +} + +static void setWindowClientTopLeftPoint(NewtUIWindow* mWin, jint x, jint y, BOOL doDisplay) { + DBG_PRINT( "setWindowClientTopLeftPoint.0 - window: %p %d/%d, display %d\n", mWin, (int)x, (int)y, (int)doDisplay); + CGPoint pS = CGPointMake(x, y); + CGRect rect = [mWin frame]; + rect.origin = pS; + + [mWin setFrame: rect]; + DBG_PRINT( "setWindowClientTopLeftPoint.X: %d/%d\n", (int)pS.x, (int)pS.y); + + if( doDisplay ) { + // TODO UIView* mView = [mWin contentView]; + // TODO [mWin invalidateCursorRectsForView: mView]; + } +} + +static void setWindowClientTopLeftPointAndSize(NewtUIWindow* mWin, jint x, jint y, jint width, jint height, BOOL doDisplay) { + DBG_PRINT( "setWindowClientTopLeftPointAndSize.0 - window: %p %d/%d %dx%d, display %d\n", mWin, (int)x, (int)y, (int)width, (int)height, (int)doDisplay); + CGRect rect = CGRectMake(x, y, width, height); + DBG_PRINT( "setWindowClientTopLeftPointAndSize.1: %d/%d %dx%d\n", (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height); + + // TODO [mWin setFrame: rect display:doDisplay]; + [mWin setFrame: rect]; + DBG_PRINT( "setWindowClientTopLeftPointAndSize.X: %d/%d %dx%d\n", (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height); + + // -> display:YES + // if( doDisplay ) { + // UIView* mView = [mWin contentView]; + // [mWin invalidateCursorRectsForView: mView]; + // } +} + +#ifdef VERBOSE_ON +static int getRetainCount(NSObject * obj) { + return ( NULL == obj ) ? -1 : (int)([obj retainCount]) ; +} +#endif + +static void setJavaWindowObject(JNIEnv *env, jobject newJavaWindowObject, NewtUIView *view, BOOL enable) { + DBG_PRINT( "setJavaWindowObject.0: View %p\n", view); + if( !enable) { + jobject globJavaWindowObject = [view getJavaWindowObject]; + if( NULL != globJavaWindowObject ) { + DBG_PRINT( "setJavaWindowObject.1: View %p - Clear old javaWindowObject %p\n", view, globJavaWindowObject); + (*env)->DeleteGlobalRef(env, globJavaWindowObject); + [view setJavaWindowObject: NULL]; + } + } else if( NULL != newJavaWindowObject ) { + DBG_PRINT( "setJavaWindowObject.2: View %p - Set new javaWindowObject %p\n", view, newJavaWindowObject); + jobject globJavaWindowObject = (*env)->NewGlobalRef(env, newJavaWindowObject); + [view setJavaWindowObject: globJavaWindowObject]; + } + DBG_PRINT( "setJavaWindowObject.X: View %p\n", view); +} + +static void changeContentView(JNIEnv *env, jobject javaWindowObject, UIView *pview, NewtUIWindow *win, NewtUIView *newView, BOOL setJavaWindow) { + UIView* oldUIView = NULL; // TODO [win contentView]; + NewtUIView* oldNewtUIView = NULL; +#ifdef VERBOSE_ON + int dbgIdx = 1; +#endif + + if( [oldUIView isKindOfClass:[NewtUIView class]] ) { + oldNewtUIView = (NewtUIView *) oldUIView; + } + + DBG_PRINT( "changeContentView.%d win %p, view (%p,%d (%d) -> %p,%d), parent view %p\n", + dbgIdx++, win, oldUIView, getRetainCount(oldUIView), NULL!=oldNewtUIView, newView, getRetainCount(newView), pview); + + if( NULL!=oldUIView ) { +NS_DURING + // Available >= 10.5 - Makes the menubar disapear + BOOL iifs = NO; // TODO [oldUIView isInFullScreenMode]; + if( iifs ) { + // TODO [oldUIView exitFullScreenModeWithOptions: NULL]; + } +NS_HANDLER +NS_ENDHANDLER + DBG_PRINT( "changeContentView.%d win %p, view (%p,%d (%d) -> %p,%d)\n", + dbgIdx++, win, oldUIView, getRetainCount(oldUIView), NULL!=oldNewtUIView, newView, getRetainCount(newView)); + + if( NULL != oldNewtUIView ) { + [oldNewtUIView setDestroyNotifySent: false]; + setJavaWindowObject(env, NULL, oldNewtUIView, NO); + } + // TODO [oldUIView removeFromSuperviewWithoutNeedingDisplay]; + } + DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d), isHidden %d, isHiddenOrHasHiddenAncestor: %d\n", + dbgIdx++, win, oldUIView, getRetainCount(oldUIView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]); + + if( NULL!=newView ) { + [newView setDestroyNotifySent: false]; + if( setJavaWindow ) { + setJavaWindowObject(env, javaWindowObject, newView, YES); + } + + DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d)\n", + dbgIdx++, win, oldUIView, getRetainCount(oldUIView), newView, getRetainCount(newView)); + + if(NULL!=pview) { + // TODO [pview addSubview: newView positioned: UIWindowAbove relativeTo: nil]; + } + } + DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d), isHidden %d, isHiddenOrHasHiddenAncestor: %d\n", + dbgIdx++, win, oldUIView, getRetainCount(oldUIView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]); + + // TODO [win setContentView: newView]; + + DBG_PRINT( "changeContentView.%d win %p, view (%p,%d -> %p,%d), isHidden %d, isHiddenOrHasHiddenAncestor: %d\n", + dbgIdx++, win, oldUIView, getRetainCount(oldUIView), newView, getRetainCount(newView), [newView isHidden], [newView isHiddenOrHasHiddenAncestor]); + + // make sure the insets are updated in the java object + [win updateInsets: env jwin:javaWindowObject]; + + DBG_PRINT( "changeContentView.X win %p, view (%p,%d -> %p,%d)\n", + win, oldUIView, getRetainCount(oldUIView), newView, getRetainCount(newView)); +} + +/* + * Class: jogamp_newt_driver_ios_DisplayDriver + * Method: initIDs + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_ios_DisplayDriver_initUIApplication0 + (JNIEnv *env, jclass clazz) +{ + static int initialized = 0; + + if(initialized) return JNI_TRUE; + initialized = 1; + + NewtCommon_init(env); + + // Initialize the shared NSApplication instance + [UIApplication sharedApplication]; + + // Need this when debugging, as it is necessary to attach gdb to + // the running java process -- "gdb java" doesn't work + // printf("Going to sleep for 10 seconds\n"); + // sleep(10); + + return (jboolean) JNI_TRUE; +} + +static void NewtScreen_dump() { +#ifdef VERBOSE_ON + NSArray *screens = [UIScreen screens]; + int i; + for(i=0; i<[screens count]; i++) { + UIScreen * screen = (UIScreen *) [screens objectAtIndex: i]; + CGRect screenFrame = [screen frame]; + CGRect screenVisibleFrame = [screen visibleFrame]; + CGFloat pixelScale = 1.0; // default + pixelScale = [screen scale]; // HiDPI scaling + UIWindowDepth depth = [screen depth]; // an (int) value! + DBG_PRINT( "UIScreen #%d (%p): Frame %lf/%lf %lfx%lf (vis %lf/%lf %lfx%lf), scale %lf, depth %d\n", + i, screen, + screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height, + screenVisibleFrame.origin.x, screenVisibleFrame.origin.y, screenVisibleFrame.size.width, screenVisibleFrame.size.height, + pixelScale, depth); + } +#endif +} + +// Duplicate each Mode by all possible rotations (4): +// For each real-mode: [mode, 0], [mode, 90], [mode, 180], [mode, 270] +#define ROTMODES_PER_REALMODE 1 + +/* + * Class: jogamp_newt_driver_ios_ScreenDriver + * Method: getMonitorDeviceIds0 + * Signature: ()I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_ios_ScreenDriver_getMonitorDeviceIds0 + (JNIEnv *env, jobject obj) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSArray *screens = [UIScreen screens]; + int count = [screens count]; + int32_t displayIDs[count]; + int i; + for(i=0; i<count; i++) { + // UIScreen * screen = (UIScreen *) [screens objectAtIndex: i]; + displayIDs[i] = i; // TODO no unique screen name? + } + jintArray properties = (*env)->NewIntArray(env, count); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", count); + } + (*env)->SetIntArrayRegion(env, properties, 0, count, displayIDs); + [pool release]; + return properties; +} + +/* + * Class: jogamp_newt_driver_ios_ScreenDriver + * Method: getMonitorProps0 + * Signature: (I)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_ios_ScreenDriver_getMonitorProps0 + (JNIEnv *env, jobject obj, jint crt_id) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + +#ifdef DBG_PERF + struct timespec t0, t1, td; + long td_ms; + timespec_now(&t0); +#endif + +#ifdef DBG_PERF + timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); + fprintf(stderr, "MacScreen_getMonitorProps0.1: %ld ms\n", td_ms); fflush(NULL); +#endif + NSArray *screens = [UIScreen screens]; + int count = [screens count]; + UIScreen * screen = (UIScreen *) [screens objectAtIndex: crt_id]; + if( NULL == screen ) { + [pool release]; + return NULL; + } + BOOL isPrimary = 0 == crt_id; +#ifdef DBG_PERF + timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); + fprintf(stderr, "MacScreen_getMonitorProps0.2: %ld ms\n", td_ms); fflush(NULL); +#endif + + UIScreenMode * screenMode = [screen currentMode]; + CGSize sizeMM = CGSizeMake(161.0, 228.0); // TODO ??? +#ifdef DBG_PERF + timespec_now(&t1); timespec_subtract(&td, &t1, &t0); td_ms = timespec_milliseconds(&td); + fprintf(stderr, "MacScreen_getMonitorProps0.3: %ld ms\n", td_ms); fflush(NULL); +#endif + + CGRect dBounds = [screen bounds]; +#ifdef VERBOSE_ON + DBG_PRINT( "getMonitorProps0: crt_id 0x%X (prim %d), top-left displayBounds[%d/%d %dx%d]\n", + (int)crt_id, isPrimary, + (int)dBounds.origin.x, (int)dBounds.origin.y, (int)dBounds.size.width, (int)dBounds.size.height); +#endif + + jsize propCount = MIN_MONITOR_DEVICE_PROPERTIES - 1 - NUM_MONITOR_MODE_PROPERTIES; + jint prop[ propCount ]; + int offset = 0; + prop[offset++] = propCount; + prop[offset++] = crt_id; + prop[offset++] = 0; // isClone + prop[offset++] = isPrimary ? 1 : 0; // isPrimary + prop[offset++] = (jint) sizeMM.width; + prop[offset++] = (jint) sizeMM.height; + prop[offset++] = (jint) dBounds.origin.x; // rotated viewport x (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.y; // rotated viewport y (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.width; // rotated viewport width (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (pixel units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.x; // rotated viewport x (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.origin.y; // rotated viewport y (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.width; // rotated viewport width (window units, will be fixed in java code) + prop[offset++] = (jint) dBounds.size.height; // rotated viewport height (window units, will be fixed in java code) + + jintArray properties = (*env)->NewIntArray(env, propCount); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", propCount); + } + (*env)->SetIntArrayRegion(env, properties, 0, propCount, prop); + + [pool release]; + + return properties; +} + +/* + * Class: jogamp_newt_driver_ios_ScreenDriver + * Method: getMonitorMode0 + * Signature: (II)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_ios_ScreenDriver_getMonitorMode0 + (JNIEnv *env, jobject obj, jint crt_id, jint mode_idx) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSArray<UIScreen*> *screens = [UIScreen screens]; + int count = [screens count]; + UIScreen * screen = (UIScreen *) [screens objectAtIndex: crt_id]; + if( NULL == screen ) { + [pool release]; + return NULL; + } + CGFloat pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen scale]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + + NSArray<UIScreenMode*> *availableModes = [screen availableModes]; + int numberOfAvailableModes = [availableModes count]; + CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes; + int currentCCWRot = 0; + jint ccwRot = 0; + int nativeId = 0; + UIScreenMode * mode = NULL; + +#ifdef VERBOSE_ON + if(0 >= mode_idx) { + // only for current mode (-1) and first mode (scanning) + DBG_PRINT( "getScreenMode0: crtID 0x%X (s %p, pscale %lf), mode %d, avail: %d/%d, current rot %d ccw\n", + (uint32_t)displayID, screen, pixelScale, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot); + } +#endif + + if(numberOfAvailableModesRots<=mode_idx) { + // n/a - end of modes + DBG_PRINT( "getScreenMode0: end of modes: mode %d, avail: %d/%d\n", + (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); + [pool release]; + return NULL; + } else if(-1 < mode_idx) { + // only at initialization time, where index >= 0 + nativeId = mode_idx / ROTMODES_PER_REALMODE; + ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90; + mode = (UIScreenMode*) [availableModes objectAtIndex: nativeId]; + } else { + // current mode + mode = [screen currentMode]; + ccwRot = 0; + nativeId = 0; + } + // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef + + CGSize mSize = [mode size]; + int mWidth = (int)mSize.width; + int mHeight = (int)mSize.height; + if( -1 == mode_idx ) { + mWidth *= (int)pixelScale; // accomodate HiDPI + mHeight *= (int)pixelScale; // accomodate HiDPI + } + + // swap width and height, since OSX reflects rotated dimension, we don't + if ( 90 == currentCCWRot || 270 == currentCCWRot ) { + int tempWidth = mWidth; + mWidth = mHeight; + mHeight = tempWidth; + } + + jint prop[ NUM_MONITOR_MODE_PROPERTIES_ALL ]; + int propIndex = 0; + + int refreshRate = 60; // TODO + int fRefreshRate = ( 0 < refreshRate ) ? refreshRate : 60; // default .. (experienced on OSX 10.6.8) + prop[propIndex++] = NUM_MONITOR_MODE_PROPERTIES_ALL; + prop[propIndex++] = mWidth; + prop[propIndex++] = mHeight; + prop[propIndex++] = 32; // TODO CGDDGetModeBitsPerPixel(mode); + prop[propIndex++] = fRefreshRate * 100; // Hz*100 + prop[propIndex++] = 0; // flags + prop[propIndex++] = nativeId; + prop[propIndex++] = ccwRot; + + DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %d / %d Hz, nativeId %d, rot %d ccw\n", + (int)mode_idx, (int)numberOfAvailableModesRots, (int)numberOfAvailableModes, + (int)prop[1], (int)prop[2], (int)prop[3], + (int)prop[4], refreshRate, (int)prop[6], (int)prop[7]); + + jintArray properties = (*env)->NewIntArray(env, NUM_MONITOR_MODE_PROPERTIES_ALL); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", NUM_MONITOR_MODE_PROPERTIES_ALL); + } + (*env)->SetIntArrayRegion(env, properties, 0, NUM_MONITOR_MODE_PROPERTIES_ALL, prop); + + // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef + [pool release]; + + return properties; +} + +/* + * Class: jogamp_newt_driver_ios_ScreenDriver + * Method: setMonitorMode0 + * Signature: (III)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_ios_ScreenDriver_setMonitorMode0 + (JNIEnv *env, jobject object, jint crt_id, jint nativeId, jint ccwRot) +{ + return false; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: initIDs + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_ios_WindowDriver_initIDs0 + (JNIEnv *env, jclass clazz) +{ + static int initialized = 0; + + if(initialized) return JNI_TRUE; + initialized = 1; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NewtScreen_dump(); + + jclass c; + c = (*env)->FindClass(env, ClazzNamePoint); + if(NULL==c) { + NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_ios_WindowDriver_initIDs0: can't find %s", ClazzNamePoint); + } + pointClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==pointClz) { + NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_ios_WindowDriver_initIDs0: can't use %s", ClazzNamePoint); + } + pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); + if(NULL==pointCstr) { + NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_ios_WindowDriver_initIDs0: can't fetch %s.%s %s", + ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); + } + + // Need this when debugging, as it is necessary to attach gdb to + // the running java process -- "gdb java" doesn't work + // printf("Going to sleep for 10 seconds\n"); + // sleep(10); + + BOOL res = [NewtUIWindow initNatives: env forClass: clazz]; + [pool release]; + + return (jboolean) res; +} + +/** + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: createView0 + * Signature: (IIII)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_ios_WindowDriver_createView0 + (JNIEnv *env, jobject jthis, jint x, jint y, jint w, jint h) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT( "createView0 - %p (this), %d/%d %dx%d (START)\n", + (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h); + + CGRect rectView = CGRectMake(0, 0, w, h); + NewtUIView *myView = [[NewtUIView alloc] initWithFrame: rectView] ; + DBG_PRINT( "createView0.X - new view: %p\n", myView); + + [pool release]; + + return (jlong) (intptr_t) myView; +} + +/** + * Method creates a deferred un-initialized Window, hence no special invocation required inside method. + * + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: createWindow0 + * Signature: (IIIIZIIJ)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_ios_WindowDriver_createWindow0 + (JNIEnv *env, jobject jthis, jint x, jint y, jint w, jint h, + jboolean fullscreen, jint styleMask, jint bufferingType, jlong jview) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtUIView* myView = (NewtUIView*) (intptr_t) jview ; + + DBG_PRINT( "createWindow0 - %p (this), %d/%d %dx%d, fs %d, style %X, buffType %X, view %p (START)\n", + (void*)(intptr_t)jthis, (int)x, (int)y, (int)w, (int)h, (int)fullscreen, + (int)styleMask, (int)bufferingType, myView); + (void)myView; + + if (fullscreen) { + // TODO styleMask = NSBorderlessWindowMask; + } + CGRect rectWin = CGRectMake(x, y, w, h); + + // Allocate the window + NewtUIWindow* myWindow = [[NewtUIWindow alloc] initWithContentRect: rectWin + styleMask: (NSUInteger) styleMask + backing: 0 // TODO (NSBackingStoreType) bufferingType + defer: YES + isFullscreenWindow: fullscreen]; + // DBG_PRINT( "createWindow0.1 - %p, isVisible %d\n", myWindow, [myWindow isVisible]); + + DBG_PRINT( "createWindow0.X - %p, isVisible %d\n", myWindow, [myWindow isVisible]); + + [pool release]; + + return (jlong) ((intptr_t) myWindow); +} + +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_ios_WindowDriver_getDisplayID0(JNIEnv *env, jobject jthis, jlong window) { + NewtUIWindow* myWindow = (NewtUIWindow*) ((intptr_t) window); + if( NULL == myWindow ) { + DBG_PRINT( "getDisplayID0 - NULL NEWT win - abort\n"); + return 0; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIScreen *screen = [myWindow screen]; + int32_t displayID = 0; // TODO (int32_t)NewtScreen_getCGDirectDisplayIDByUIScreen(screen); + [pool release]; + return (jint) displayID; +} + +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: initWindow0 + * Signature: (JJIIIIFZZZJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_initWindow0 + (JNIEnv *env, jobject jthis, jlong parent, jlong window, jint x, jint y, jint w, jint h, jfloat reqPixelScale, + jboolean opaque, jboolean atop, jboolean abottom, jboolean visible, jlong jview) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtUIWindow* myWindow = (NewtUIWindow*) ((intptr_t) window); + NewtUIView* myView = (NewtUIView*) (intptr_t) jview ; + BOOL fullscreen = myWindow->isFullscreenWindow; + + DBG_PRINT( "initWindow0 - %p (this), %p (parent), %p (window), %d/%d %dx%d, reqPixScale %f, opaque %d, atop %d, abottom %d, fs %d, visible %d, view %p (START)\n", + (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, (int)x, (int)y, (int)w, (int)h, (float)reqPixelScale, + (int) opaque, (int)atop, (int)abottom, (int)fullscreen, (int)visible, myView); + + // TODO [myWindow setReleasedWhenClosed: NO]; // We control UIWindow destruction! + // TODO [myWindow setPreservesContentDuringLiveResize: NO]; + + NSObject* nsParentObj = (NSObject*) ((intptr_t) parent); + UIWindow* parentWindow = NULL; + UIView* parentView = NULL; + if( nsParentObj != NULL && [nsParentObj isKindOfClass:[UIWindow class]] ) { + parentWindow = (UIWindow*) nsParentObj; + parentView = (UIView*)nsParentObj; + DBG_PRINT( "initWindow0 - Parent is UIWindow : %p (win) -> %p (view) \n", parentWindow, parentView); + } else if( nsParentObj != NULL && [nsParentObj isKindOfClass:[UIView class]] ) { + parentView = (UIView*) nsParentObj; + parentWindow = [parentView window]; + DBG_PRINT( "initWindow0 - Parent is UIView : %p -(view) > %p (win) \n", parentView, parentWindow); + } else { + DBG_PRINT( "initWindow0 - Parent is neither UIWindow nor UIView : %p\n", nsParentObj); + } + DBG_PRINT( "initWindow0 - is visible.1: %d\n", [myWindow isVisible]); + + // Remove animations for child windows + if(NULL != parentWindow) { + [UIView setAnimationsEnabled: NO]; + } + +#ifdef VERBOSE_ON + int dbgIdx = 1; +#endif + if(opaque) { + [myWindow setOpaque: YES]; + DBG_PRINT( "initWindow0.%d\n", dbgIdx++); + if (!fullscreen) { + // TODO [myWindow setShowsResizeIndicator: YES]; + } + DBG_PRINT( "initWindow0.%d\n", dbgIdx++); + } else { + [myWindow setOpaque: NO]; + [myWindow setBackgroundColor: [UIColor clearColor]]; + } + [myWindow setAlwaysOn: atop bottom:abottom]; + + // specify we want mouse-moved events + // TODO [myWindow setAcceptsMouseMovedEvents:YES]; + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + + // Set the content view + changeContentView(env, jthis, parentView, myWindow, myView, NO); + // TODO [myWindow setInitialFirstResponder: myView]; + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + + if(NULL!=parentWindow) { + [myWindow attachToParent: parentWindow]; + } + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d, visible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible], visible); + + // Immediately re-position this window based on an upper-left coordinate system + setWindowClientTopLeftPointAndSize(myWindow, x, y, w, h, NO); + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + + // TODO [myWindow setAllowsConcurrentViewDrawing: YES]; + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + + // TODO [myView setCanDrawConcurrently: YES]; + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + + // visible on front + if( visible ) { + // TODO [myWindow orderFront: myWindow]; + } + + DBG_PRINT( "initWindow0.%d - %p view %p, isVisible %d\n", + dbgIdx++, myWindow, myView, [myWindow isVisible]); + + // force surface creation + // [myView lockFocus]; + // [myView unlockFocus]; + + // Set the next responder to be the window so that we can forward + // right mouse button down events + // TODO [myView setNextResponder: myWindow]; + + DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); + + [myView setDestroyNotifySent: false]; + setJavaWindowObject(env, jthis, myView, YES); + + DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); + +NS_DURING + if( fullscreen ) { + /** + * See Bug 914: We don't use exclusive fullscreen anymore (capturing display) + * allowing ALT-TAB to allow process/app switching! + * Shall have no penalty on modern GPU and is also recommended, see bottom box @ + * <https://developer.apple.com/library/mac/documentation/graphicsimaging/Conceptual/QuartzDisplayServicesConceptual/Articles/DisplayCapture.html> + * + UIScreen *myScreen = NewtScreen_getUIScreenByCoord(x, y); + if( NULL != myScreen ) { + if ( [myView respondsToSelector:@selector(enterFullScreenMode:withOptions:)] ) { + // Available >= 10.5 - Makes the menubar disapear + [myView enterFullScreenMode: myScreen withOptions:NULL]; + } + } + */ + if( myWindow->hasPresentationSwitch ) { + DBG_PRINT( "initWindow0.%d - %p view %p, setPresentationOptions 0x%X\n", + dbgIdx++, myWindow, myView, (int)myWindow->fullscreenPresentationOptions); + // TODO [NSApp setPresentationOptions: myWindow->fullscreenPresentationOptions]; + } + } +NS_HANDLER +NS_ENDHANDLER + + DBG_PRINT( "initWindow0.%d - %p (this), %p (parent): new window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); + + [pool release]; + DBG_PRINT( "initWindow0.X - %p (this), %p (parent): new window: %p, view %p\n", + (void*)(intptr_t)jthis, (void*)(intptr_t)parent, myWindow, myView); +} + +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: setPixelScale0 + * Signature: (JJF)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_setPixelScale0 + (JNIEnv *env, jobject jthis, jlong window, jlong view, jfloat reqPixelScale) +{ + NewtUIWindow* myWindow = (NewtUIWindow*) ((intptr_t) window); + if( NULL == myWindow ) { + DBG_PRINT( "setPixelScale0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtUIView* myView = (NewtUIView*) (intptr_t) view ; +#ifdef VERBOSE_ON + int dbgIdx = 1; +#endif + DBG_PRINT( "setPixelScale0 - %p (this), %p (window), view %p, reqPixScale %f (START)\n", + (void*)(intptr_t)jthis, myWindow, myView, (float)reqPixelScale); + (void)myWindow; + + DBG_PRINT( "setPixelScale0.%d - %p (this), window: %p, view %p\n", + dbgIdx++, (void*)(intptr_t)jthis, myWindow, myView); + + [pool release]; + DBG_PRINT( "setPixelScale0.X - %p (this), window: %p, view %p\n", + (void*)(intptr_t)jthis, myWindow, myView); +} + +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: close0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_close0 + (JNIEnv *env, jobject unused, jlong window) +{ + NewtUIWindow* mWin = (NewtUIWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "windowClose.0 - NULL NEWT win - abort\n"); + return; + } + BOOL isNSWin = [mWin isKindOfClass:[UIWindow class]]; + BOOL isNewtWin = [mWin isKindOfClass:[NewtUIWindow class]]; + UIWindow *pWin = NULL; // TODO [mWin parentWindow]; + DBG_PRINT( "windowClose.0 - %p [isUIWindow %d, isNewtWin %d], parent %p\n", mWin, isNSWin, isNewtWin, pWin); + (void)isNSWin; // silence + if( !isNewtWin ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtUIWindow %p", mWin); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtUIView* mView = (NewtUIView *)mWin; // TODO [mWin contentView]; + BOOL fullscreen = mWin->isFullscreenWindow; + BOOL destroyNotifySent, isUIView, isNewtUIView; + if( NULL != mView ) { + isUIView = [mView isKindOfClass:[UIView class]]; + isNewtUIView = [mView isKindOfClass:[NewtUIView class]]; + destroyNotifySent = isNewtUIView ? [mView getDestroyNotifySent] : false; + } else { + isUIView = false; + isNewtUIView = false; + destroyNotifySent = false; + } + + DBG_PRINT( "windowClose.0 - %p, destroyNotifySent %d, view %p [isUIView %d, isNewtUIView %d], fullscreen %d, parent %p\n", + mWin, destroyNotifySent, mView, isUIView, isNewtUIView, (int)fullscreen, pWin); + + [mWin setRealized: NO]; + + if( isNewtUIView ) { + // cleanup view + [mView setDestroyNotifySent: true]; + setJavaWindowObject(env, NULL, mView, NO); + } + +NS_DURING + /** + * See Bug 914: We don't use exclusive fullscreen anymore (capturing display) + * See initWindow0(..) above .. + if(NULL!=mView) { + BOOL iifs; + if ( [mView respondsToSelector:@selector(isInFullScreenMode)] ) { + iifs = [mView isInFullScreenMode]; + } else { + iifs = NO; + } + if(iifs && [mView respondsToSelector:@selector(exitFullScreenModeWithOptions:)] ) { + [mView exitFullScreenModeWithOptions: NULL]; + } + } */ + // Note: mWin's release will also release it's mView! + DBG_PRINT( "windowClose.1a - %p view %p, fullscreen %d, hasPresSwitch %d, defaultPresentationOptions 0x%X\n", + mWin, mView, (int)fullscreen, (int)mWin->hasPresentationSwitch, (int)mWin->defaultPresentationOptions); + + if( fullscreen && mWin->hasPresentationSwitch ) { + DBG_PRINT( "windowClose.1b - %p view %p, setPresentationOptions 0x%X\n", + mWin, mView, (int)mWin->defaultPresentationOptions); + // TODO [NSApp setPresentationOptions: mWin->defaultPresentationOptions]; + } +NS_HANDLER +NS_ENDHANDLER + + if(NULL!=pWin) { + [mWin detachFromParent: pWin]; + } + // TODO [mWin orderOut: mWin]; + [mWin setHidden: YES]; // no release, close n/a, .. well: ref count counts :-( + + DBG_PRINT( "windowClose.2 - %p view %p, parent %p\n", mWin, mView, pWin); + + [mWin release]; + + DBG_PRINT( "windowClose.Xp\n"); + + [pool release]; +} + +/* + * Class: Java_jogamp_newt_driver_ios_WindowDriver + * Method: lockSurface0 + * Signature: (JJ)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_ios_WindowDriver_lockSurface0 + (JNIEnv *env, jclass clazz, jlong window, jlong view) +{ + NewtUIWindow *mWin = (NewtUIWindow*) ((intptr_t) window); + if(NO == [mWin isRealized]) { + return JNI_FALSE; + } + NewtUIView * mView = (NewtUIView *) ((intptr_t) view); + return [mView softLock] == YES ? JNI_TRUE : JNI_FALSE; + /** deadlocks, since we render independent of focus + return [mView lockFocusIfCanDraw] == YES ? JNI_TRUE : JNI_FALSE; */ +} + +/* + * Class: Java_jogamp_newt_driver_ios_WindowDriver + * Method: unlockSurface0 + * Signature: (JJ)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_ios_WindowDriver_unlockSurface0 + (JNIEnv *env, jclass clazz, jlong window, jlong view) +{ + // NewtUIWindow *mWin = (NewtUIWindow*) ((intptr_t) window); + (void) window; + NewtUIView * mView = (NewtUIView *) ((intptr_t) view); + return [mView softUnlock] == YES ? JNI_TRUE : JNI_FALSE; + /** deadlocks, since we render independent of focus + [mView unlockFocus]; */ +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: requestFocus0 + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_requestFocus0 + (JNIEnv *env, jobject window, jlong w, jboolean force) +{ + UIWindow* mWin = (UIWindow*) ((intptr_t) w); + if( NULL == mWin ) { + DBG_PRINT( "requestFocus - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; +#ifdef VERBOSE_ON + BOOL hasFocus = [mWin isKeyWindow]; +#endif + DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", mWin, force, hasFocus); + + // TODO [mWin setAcceptsMouseMovedEvents: YES]; + // TODO [mWin makeFirstResponder: nil]; + // TODO [mWin orderFrontRegardless]; + [mWin makeKeyWindow]; + + DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", mWin, force); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: resignFocus0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_resignFocus0 + (JNIEnv *env, jobject window, jlong w) +{ + UIWindow* mWin = (UIWindow*) ((intptr_t) w); + if( NULL == mWin ) { + DBG_PRINT( "resignFocus0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIWindow* pWin = NULL; // TODO [mWin parentWindow]; + BOOL hasFocus = [mWin isKeyWindow]; + + DBG_PRINT( "resignFocus0 - window: %p, parent %p, hasFocus %d (START)\n", mWin, pWin, hasFocus ); + if( hasFocus ) { + if(NULL != pWin) { + // [mWin makeFirstResponder: pWin]; + [pWin makeKeyWindow]; + } else { + [pWin resignKeyWindow]; + } + } + DBG_PRINT( "resignFocus0 - window: %p (END)\n", mWin); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: orderFront0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_orderFront0 + (JNIEnv *env, jobject unused, jlong window) +{ + UIWindow* mWin = (UIWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "orderFront0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIWindow* pWin = NULL; // TODO [mWin parentWindow]; + + DBG_PRINT( "orderFront0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]); + + if( NULL == pWin ) { + // TODO [mWin orderFrontRegardless]; + } else { + // TODO [mWin orderWindow: UIWindowAbove relativeTo: [pWin windowNumber]]; + } + + DBG_PRINT( "orderFront0 - window: (parent %p) %p (END)\n", pWin, mWin); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: orderOut + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_orderOut0 + (JNIEnv *env, jobject unused, jlong window) +{ + UIWindow* mWin = (UIWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "orderOut0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIWindow* pWin = NULL; // TODO [mWin parentWindow]; + + DBG_PRINT( "orderOut0 - window: (parent %p) %p visible %d (START)\n", pWin, mWin, [mWin isVisible]); + + if( NULL == pWin ) { + // TODO [mWin orderOut: mWin]; + } else { + // TODO [mWin orderWindow: UIWindowOut relativeTo: [pWin windowNumber]]; + } + + DBG_PRINT( "orderOut0 - window: (parent %p) %p (END)\n", pWin, mWin); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: setTitle0 + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_setTitle0 + (JNIEnv *env, jobject unused, jlong window, jstring title) +{ + UIWindow* win = (UIWindow*) ((intptr_t) window); + if( NULL == win ) { + DBG_PRINT( "setTitle0 - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT( "setTitle0 - window: %p (START)\n", win); + + NSString* str = jstringToNSString(env, title); + [str autorelease]; + // TODO [win setTitle: str]; + + DBG_PRINT( "setTitle0 - window: %p (END)\n", win); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: contentView0 + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_ios_WindowDriver_contentView0 + (JNIEnv *env, jobject unused, jlong window) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + UIWindow* win = (UIWindow*) ((intptr_t) window); + UIView* nsView = (UIView*)win; // TODO [win contentView]; + NewtUIView* newtView = NULL; + + if( [nsView isKindOfClass:[NewtUIView class]] ) { + newtView = (NewtUIView *) nsView; + } + + DBG_PRINT( "contentView0 - window: %p, view: %p, newtView %p\n", win, nsView, newtView); + + jlong res = (jlong) ((intptr_t) nsView); + + [pool release]; + return res; +} + +/** + * Method is called on Main-Thread, hence no special invocation required inside method. + * + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: changeContentView + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_changeContentView0 + (JNIEnv *env, jobject jthis, jlong parentWindowOrView, jlong window, jlong jview) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NewtUIView* newView = (NewtUIView *) ((intptr_t) jview); + NewtUIWindow* win = (NewtUIWindow*) ((intptr_t) window); + + DBG_PRINT( "changeContentView0.0 - win %p, view (%p,%d)\n", + win, newView, getRetainCount(newView)); + + NSObject *nsParentObj = (NSObject*) ((intptr_t) parentWindowOrView); + UIView* pView = NULL; + if( NULL != nsParentObj ) { + if( [nsParentObj isKindOfClass:[UIWindow class]] ) { + UIWindow * pWin = (UIWindow*) nsParentObj; + pView = (UIView*)pWin; // TODO [pWin contentView]; + } else if( [nsParentObj isKindOfClass:[UIView class]] ) { + pView = (UIView*) nsParentObj; + } + } + + changeContentView(env, jthis, pView, win, newView, YES); + + DBG_PRINT( "changeContentView0.X\n"); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: updateSizePosInsets0 + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_updateSizePosInsets0 + (JNIEnv *env, jobject jthis, jlong window, jboolean defer) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtUIWindow* mWin = (NewtUIWindow*) ((intptr_t) window); + + DBG_PRINT( "updateSizePosInsets - window: %p, defer %d (START)\n", mWin, (int)defer); + + [mWin updateSizePosInsets: env jwin:jthis defer:defer]; + + DBG_PRINT( "updateSizePosInsets - window: %p, defer %d (END)\n", mWin, (int)defer); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: setWindowClientTopLeftPointAndSize0 + * Signature: (JIIIIZ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_setWindowClientTopLeftPointAndSize0 + (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jint w, jint h, jboolean display) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NewtUIWindow* mWin = (NewtUIWindow*) ((intptr_t) window); + + DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (START)\n", mWin); + + setWindowClientTopLeftPointAndSize(mWin, x, y, w, h, display); + + DBG_PRINT( "setWindowClientTopLeftPointAndSize - window: %p (END)\n", mWin); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: setWindowClientTopLeftPoint0 + * Signature: (JIIZ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_ios_WindowDriver_setWindowClientTopLeftPoint0 + (JNIEnv *env, jobject unused, jlong window, jint x, jint y, jboolean display) +{ + NewtUIWindow* mWin = (NewtUIWindow*) ((intptr_t) window); + if( NULL == mWin ) { + DBG_PRINT( "setWindowClientTopLeftPoint - NULL NEWT win - abort\n"); + return; + } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (START)\n", mWin); + + setWindowClientTopLeftPoint(mWin, x, y, display); + + DBG_PRINT( "setWindowClientTopLeftPoint - window: %p (END)\n", mWin); + + [pool release]; +} + +/* + * Class: jogamp_newt_driver_ios_WindowDriver + * Method: getLocationOnScreen0 + * Signature: (JII)Lcom/jogamp/nativewindow/util/Point; + */ +JNIEXPORT jobject JNICALL Java_jogamp_newt_driver_ios_WindowDriver_getLocationOnScreen0 + (JNIEnv *env, jclass unused, jlong win, jint src_x, jint src_y) +{ + NewtUIWindow *mWin = (NewtUIWindow*) (intptr_t) win; + if( NULL == mWin ) { + DBG_PRINT( "getLocationOnScreen0 - NULL NEWT win - abort\n"); + return NULL; + } + if( ![mWin isKindOfClass:[NewtUIWindow class]] ) { + NewtCommon_throwNewRuntimeException(env, "Not a NewtUIWindow %p", mWin); + return NULL; + } + CGPoint p0 = [mWin getLocationOnScreen: CGPointMake(src_x, src_y)]; + return (*env)->NewObject(env, pointClz, pointCstr, (jint)p0.x, (jint)p0.y); +} + diff --git a/src/newt/native/JVM_JNI8.c b/src/newt/native/JVM_JNI8.c new file mode 100644 index 000000000..c023cb0f0 --- /dev/null +++ b/src/newt/native/JVM_JNI8.c @@ -0,0 +1,42 @@ +/** + * Copyright 2019 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include <stdio.h> //required by android to identify NULL +#include <jni.h> + +#if defined (JNI_VERSION_1_8) + +JNIEXPORT jint JNICALL JNI_OnLoad_newt(JavaVM *vm, void *reserved) { + return JNI_VERSION_1_8; +} + +JNIEXPORT void JNICALL JNI_OnUnload_newt(JavaVM *vm, void *reserved) { +} + +#endif /* defined (JNI_VERSION_1_8) */ + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateOnOffscrnCapsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateOnOffscrnCapsNEWT.java index 4f666920a..c24254b89 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateOnOffscrnCapsNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableDelegateOnOffscrnCapsNEWT.java @@ -235,11 +235,11 @@ public class TestGLAutoDrawableDelegateOnOffscrnCapsNEWT extends UITestCase { @Test public void testAvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); + GLDrawableFactory f = GLDrawableFactory.getFactory(false); if(null != f) { System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); } - f = GLDrawableFactory.getEGLFactory(); + f = GLDrawableFactory.getFactory(true); if(null != f) { System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryES2OffscrnCapsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryES2OffscrnCapsNEWT.java index 7cef9e448..1ca099cb1 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryES2OffscrnCapsNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryES2OffscrnCapsNEWT.java @@ -155,18 +155,6 @@ public class TestGLAutoDrawableFactoryES2OffscrnCapsNEWT extends UITestCase { } @Test - public void testAvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - f = GLDrawableFactory.getEGLFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - } - - @Test public void testES2OffScreenAutoDblBuf() throws InterruptedException { final GLCapabilities reqGLCaps = getCaps(GLProfile.GLES2); if(null == reqGLCaps) return; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGL2OffscrnCapsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGL2OffscrnCapsNEWT.java index a23e81d69..26ef2b0af 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGL2OffscrnCapsNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGL2OffscrnCapsNEWT.java @@ -155,18 +155,6 @@ public class TestGLAutoDrawableFactoryGL2OffscrnCapsNEWT extends UITestCase { } @Test - public void testAvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - f = GLDrawableFactory.getEGLFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - } - - @Test public void testGL2OffScreenAutoDblBuf() throws InterruptedException { final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2); if(null == reqGLCaps) return; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java index 9934ae862..0e132526c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLProfileDeviceNEWT.java @@ -129,21 +129,21 @@ public class TestGLAutoDrawableFactoryGLProfileDeviceNEWT extends UITestCase { @Test public void test00AvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); + GLDrawableFactory f = GLDrawableFactory.getFactory(false); if(null != f) { System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); } - f = GLDrawableFactory.getEGLFactory(); + f = GLDrawableFactory.getFactory(true); if(null != f) { System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); } } @Test - public void test01ES2OnEGL() throws InterruptedException { - final GLDrawableFactory factory = GLDrawableFactory.getEGLFactory(); + public void test01ES2OnMobile() throws InterruptedException { + final GLDrawableFactory factory = GLDrawableFactory.getFactory(true); if( null == factory ) { - System.err.println("EGL Factory n/a"); + System.err.println("Mobile Factory n/a"); return; } final AbstractGraphicsDevice prodDevice = factory.getDefaultDevice(); @@ -163,10 +163,10 @@ public class TestGLAutoDrawableFactoryGLProfileDeviceNEWT extends UITestCase { } @Test - public void test02GLOnEGL() throws InterruptedException { - final GLDrawableFactory factory = GLDrawableFactory.getEGLFactory(); + public void test02GLOnMobile() throws InterruptedException { + final GLDrawableFactory factory = GLDrawableFactory.getFactory(true); if( null == factory ) { - System.err.println("EGL Factory n/a"); + System.err.println("Mobile Factory n/a"); return; } final AbstractGraphicsDevice prodDevice = factory.getDefaultDevice(); @@ -189,7 +189,7 @@ public class TestGLAutoDrawableFactoryGLProfileDeviceNEWT extends UITestCase { @Test public void test11ES2OnDesktop() throws InterruptedException { - final GLDrawableFactory deskFactory = GLDrawableFactory.getDesktopFactory(); + final GLDrawableFactory deskFactory = GLDrawableFactory.getFactory(false); if( null == deskFactory ) { System.err.println("Desktop Factory n/a"); return; @@ -217,7 +217,7 @@ public class TestGLAutoDrawableFactoryGLProfileDeviceNEWT extends UITestCase { @Test public void test12GLOnDesktop() throws InterruptedException { - final GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory(); + final GLDrawableFactory factory = GLDrawableFactory.getFactory(false); if( null == factory ) { System.err.println("Desktop Factory n/a"); return; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLnBitmapCapsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLnBitmapCapsNEWT.java index 6a7b09be1..efbb847db 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLnBitmapCapsNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableFactoryGLnBitmapCapsNEWT.java @@ -146,18 +146,6 @@ public class TestGLAutoDrawableFactoryGLnBitmapCapsNEWT extends UITestCase { System.out.println("Fin Drawable: "+glad); } - @Test - public void testAvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - f = GLDrawableFactory.getEGLFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - } - // Might be reduced to !double-buff @Test public void testGL2OffScreenBitmapDblBuf() throws InterruptedException { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java index 6138ce6ee..f521f45ec 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT.java @@ -245,18 +245,6 @@ public class TestGLAutoDrawableGLCanvasOnOffscrnCapsAWT extends UITestCase { } @Test - public void testAvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - f = GLDrawableFactory.getEGLFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - } - - @Test public void testGL2OnScreenDblBuf() throws InterruptedException { final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2); if(null == reqGLCaps) return; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java index 34148501d..d4bd227db 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT.java @@ -188,18 +188,6 @@ public class TestGLAutoDrawableGLWindowOnOffscrnCapsNEWT extends UITestCase { } @Test - public void testAvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - f = GLDrawableFactory.getEGLFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - } - - @Test public void testGL2OnScreenSglBuf() throws InterruptedException { final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2); if(null == reqGLCaps) return; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java index ce968751e..339d27a3e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT.java @@ -258,18 +258,6 @@ public class TestGLAutoDrawableNewtCanvasAWTOnOffscrnCapsAWT extends UITestCase } @Test - public void testAvailableInfo() { - GLDrawableFactory f = GLDrawableFactory.getDesktopFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - f = GLDrawableFactory.getEGLFactory(); - if(null != f) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(f.getDefaultDevice(), null, true).toString()); - } - } - - @Test public void testGL2OnScreenDblBuf() throws InterruptedException { final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2); if(null == reqGLCaps) return; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile00NEWT.java index edb681d01..987dcaf9c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile00NEWT.java @@ -67,7 +67,7 @@ public class TestGLProfile00NEWT extends UITestCase { public void test11DumpDesktopGLInfo() throws InterruptedException { Assert.assertTrue("JOGL is not initialized ...", GLProfile.isInitialized()); System.err.println("Desktop"); - final GLDrawableFactory desktopFactory = GLDrawableFactory.getDesktopFactory(); + final GLDrawableFactory desktopFactory = GLDrawableFactory.getFactory(false); if( null != desktopFactory ) { System.err.println(JoglVersion.getDefaultOpenGLInfo(desktopFactory.getDefaultDevice(), null, false)); System.err.println(Platform.getNewline()+Platform.getNewline()+Platform.getNewline()); @@ -77,12 +77,12 @@ public class TestGLProfile00NEWT extends UITestCase { } @Test - public void test12DumpEGLGLInfo() throws InterruptedException { + public void test12DumpMobileGLInfo() throws InterruptedException { Assert.assertTrue("JOGL is not initialized ...", GLProfile.isInitialized()); - System.err.println("EGL"); - final GLDrawableFactory eglFactory = GLDrawableFactory.getEGLFactory(); - if( null != eglFactory ) { - System.err.println(JoglVersion.getDefaultOpenGLInfo(eglFactory.getDefaultDevice(), null, false)); + System.err.println("ES"); + final GLDrawableFactory esFactory = GLDrawableFactory.getFactory(true); + if( null != esFactory ) { + System.err.println(JoglVersion.getDefaultOpenGLInfo(esFactory.getDefaultDevice(), null, false)); } else { System.err.println("\tNULL"); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java index 2921e8102..f2f35012d 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java @@ -54,11 +54,11 @@ public class TestGLProfile01NEWT extends GLProfile0XBase { System.err.println(JoglVersion.getInstance()); System.err.println(NewtVersion.getInstance()); - final GLDrawableFactory deskFactory = GLDrawableFactory.getDesktopFactory(); + final GLDrawableFactory deskFactory = GLDrawableFactory.getFactory(false); if( null != deskFactory ) { System.err.println(JoglVersion.getDefaultOpenGLInfo(deskFactory.getDefaultDevice(), null, true).toString()); } - final GLDrawableFactory eglFactory = GLDrawableFactory.getEGLFactory(); + final GLDrawableFactory eglFactory = GLDrawableFactory.getFactory(true); if( null != eglFactory ) { System.err.println(JoglVersion.getDefaultOpenGLInfo(eglFactory.getDefaultDevice(), null, true).toString()); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java index 0987b2978..3c2607249 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedExternalContextAWT.java @@ -47,7 +47,7 @@ public class TestSharedExternalContextAWT { System.err.println("Master Thread Start: "+Thread.currentThread().getName()); final GLProfile glProfile = GLProfile.getDefault(); final GLCapabilities caps = new GLCapabilities(glProfile); - final GLAutoDrawable buffer = GLDrawableFactory.getDesktopFactory().createOffscreenAutoDrawable( + final GLAutoDrawable buffer = GLDrawableFactory.getFactory(false).createOffscreenAutoDrawable( GLProfile.getDefaultDevice(), caps, null, 512, 512 ); // The listener will set up the context sharing in its init() method. @@ -127,7 +127,7 @@ public class TestSharedExternalContextAWT { System.err.println(); System.err.println(); System.err.println("Master (orig) Ct: "+drawable.getContext()); // Create the external context on the caller thread. - final GLContext master = GLDrawableFactory.getDesktopFactory().createExternalGLContext(); + final GLContext master = GLDrawableFactory.getFactory(false).createExternalGLContext(); System.err.println(); System.err.println(); System.err.println("External Context: "+master); @@ -137,7 +137,7 @@ public class TestSharedExternalContextAWT { // FIXME: We actually need to hook into GLContext make-current lock // masterLock.lock(); try { - fOffscreenDrawable = GLDrawableFactory.getDesktopFactory().createOffscreenAutoDrawable( + fOffscreenDrawable = GLDrawableFactory.getFactory(false).createOffscreenAutoDrawable( GLProfile.getDefaultDevice(), new GLCapabilities(GLProfile.getDefault()), null, // new DefaultGLCapabilitiesChooser(), |