diff options
Diffstat (limited to 'src/jogl')
15 files changed, 641 insertions, 212 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java index af16348a8..7589b3776 100644 --- a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java +++ b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java @@ -129,7 +129,14 @@ public class JoglVersion extends JogampVersion { public static StringBuilder getGLInfo(final GL gl, final StringBuilder sb) { return getGLInfo(gl, sb, false); } - public static StringBuilder getGLInfo(final GL gl, StringBuilder sb, final boolean withCapabilitiesAndExtensionInfo) { + public static StringBuilder getGLInfo(final GL gl, final StringBuilder sb, final boolean withCapabilitiesAndExtensionInfo) { + return getGLInfo(gl, sb, true, withCapabilitiesAndExtensionInfo, withCapabilitiesAndExtensionInfo); + } + + public static StringBuilder getGLInfo(final GL gl, StringBuilder sb, + final boolean withAvailabilityInfo, + final boolean withCapabilitiesInfo, + final boolean withExtensionInfo) { final AbstractGraphicsDevice device = gl.getContext().getGLDrawable().getNativeSurface() .getGraphicsConfiguration().getScreen().getDevice(); if(null==sb) { @@ -139,12 +146,14 @@ public class JoglVersion extends JogampVersion { sb.append(VersionUtil.SEPERATOR).append(Platform.getNewline()); sb.append(device.getClass().getSimpleName()).append("[type ") .append(device.getType()).append(", connection ").append(device.getConnection()).append("]: ").append(Platform.getNewline()); - GLProfile.glAvailabilityToString(device, sb, "\t", 1); + if( withAvailabilityInfo ) { + GLProfile.glAvailabilityToString(device, sb, "\t", 1); + } sb.append(Platform.getNewline()); - sb = getGLStrings(gl, sb, withCapabilitiesAndExtensionInfo); + sb = getGLStrings(gl, sb, withExtensionInfo); - if( withCapabilitiesAndExtensionInfo ) { + if( withCapabilitiesInfo ) { sb = getAllAvailableCapabilitiesInfo(device, sb); } return sb; diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java index 11d217535..5f59f7e6d 100644 --- a/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java @@ -173,7 +173,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final RecursiveLock lock = LockFactory.createRecursiveLock(); private final GLDrawableHelper helper = new GLDrawableHelper(); - private AWTGraphicsConfiguration awtConfig; private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle private volatile GLContextImpl context; // volatile: avoid locking for read-only access @@ -187,9 +186,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private final GLCapabilitiesImmutable capsReqUser; private final GLCapabilitiesChooser chooser; private int additionalCtxCreationFlags = 0; - private final GraphicsDevice device; private boolean shallUseOffscreenLayer = false; + private volatile GraphicsDevice awtDeviceReq; // one time user req. + private volatile AWTGraphicsConfiguration awtConfig; private volatile boolean isShowing; private final HierarchyListener hierarchyListener = new HierarchyListener() { @Override @@ -270,16 +270,8 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing setShallUseOffscreenLayer(true); // trigger offscreen layer - if supported } - if(null==device) { - final GraphicsConfiguration gc = super.getGraphicsConfiguration(); - if(null!=gc) { - this.device = gc.getDevice(); - } else { - this.device = null; - } - } else { - this.device = device; - } + // One time user AWT GraphicsDevice request + awtDeviceReq = device; // instantiation will be issued in addNotify() this.chooser = chooser; @@ -330,124 +322,111 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing /** - * Overridden to choose a GraphicsConfiguration on a parent container's - * GraphicsDevice because both devices + * {@inheritDoc} + * <p> + * Overridden to choose a {@link GraphicsConfiguration} from a parent container's + * {@link GraphicsDevice}. + * </p> + * <p> + * Method also intercepts {@link GraphicsConfiguration} changes regarding to + * its capabilities and its {@link GraphicsDevice}. This may happen in case + * the display changes its configuration or the component is moved to another screen. + * </p> */ @Override public GraphicsConfiguration getGraphicsConfiguration() { - /* - * Workaround for problems with Xinerama and java.awt.Component.checkGD - * when adding to a container on a different graphics device than the - * one that this Canvas is associated with. - * - * GC will be null unless: - * - A native peer has assigned it. This means we have a native - * peer, and are already comitted to a graphics configuration. - * - This canvas has been added to a component hierarchy and has - * an ancestor with a non-null GC, but the native peer has not - * yet been created. This means we can still choose the GC on - * all platforms since the peer hasn't been created. - */ - final GraphicsConfiguration gc = super.getGraphicsConfiguration(); - - if( Beans.isDesignTime() ) { - return gc; - } - - /* - * chosen is only non-null on platforms where the GLDrawableFactory - * returns a non-null GraphicsConfiguration (in the GLCanvas - * constructor). - * - * if gc is from this Canvas' native peer then it should equal chosen, - * otherwise it is from an ancestor component that this Canvas is being - * added to, and we go into this block. - */ - GraphicsConfiguration chosen = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null; - - if (gc != null && chosen != null && !chosen.equals(gc)) { - /* - * Check for compatibility with gc. If they differ by only the - * device then return a new GCconfig with the super-class' GDevice - * (and presumably the same visual ID in Xinerama). - * + /** + * parentGC will be null unless: + * - A native peer has assigned it. This means we have a native + * peer, and are already committed to a graphics configuration. + * - This canvas has been added to a component hierarchy and has + * an ancestor with a non-null GC, but the native peer has not + * yet been created. This means we can still choose the GC on + * all platforms since the peer hasn't been created. */ - if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) { - /* - * Here we select a GraphicsConfiguration on the alternate - * device that is presumably identical to the chosen - * configuration, but on the other device. - * - * Should really check to ensure that we select a configuration - * with the same X visual ID for Xinerama screens, otherwise the - * GLDrawable may have the wrong visual ID (I don't think this - * ever gets updated). May need to add a method to - * X11GLDrawableFactory to do this in a platform specific - * manner. - * - * However, on platforms where we can actually get into this - * block, both devices should have the same visual list, and the - * same configuration should be selected here. - */ - final AWTGraphicsConfiguration config = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(), - (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(), - chooser, gc.getDevice()); - final GraphicsConfiguration compatible = config.getAWTGraphicsConfiguration(); - final boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities()); - if(DEBUG) { - System.err.println(getThreadName()+": Info:"); - System.err.println("Created Config (n): HAVE GC "+chosen); - System.err.println("Created Config (n): THIS GC "+gc); - System.err.println("Created Config (n): Choosen GC "+compatible); - System.err.println("Created Config (n): HAVE CF "+awtConfig); - System.err.println("Created Config (n): Choosen CF "+config); - System.err.println("Created Config (n): EQUALS CAPS "+equalCaps); - // Thread.dumpStack(); - } + final GraphicsConfiguration parentGC = super.getGraphicsConfiguration(); - if (compatible != null) { - /* - * Save the new GC for equals test above, and to return to - * any outside callers of this method. - */ - chosen = compatible; - - if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) { - // complete destruction! - destroyImpl( true ); - // recreation! - awtConfig = config; - createJAWTDrawableAndContext(); - validateGLDrawable(); - } else { - awtConfig = config; + if( Beans.isDesignTime() ) { + return parentGC; + } + final GraphicsConfiguration oldGC = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null; + + if ( null != parentGC && null != oldGC && !oldGC.equals(parentGC) ) { + // Previous oldGC != parentGC of native peer + + if ( !oldGC.getDevice().getIDstring().equals(parentGC.getDevice().getIDstring()) ) { + // Previous oldGC's GraphicsDevice != parentGC's GraphicsDevice of native peer + + /** + * Here we select a GraphicsConfiguration on the alternate device. + * In case the new configuration differs (-> !equalCaps), + * we might need a reconfiguration, + */ + final AWTGraphicsConfiguration newConfig = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(), + (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(), + chooser, parentGC.getDevice()); + final GraphicsConfiguration newGC = newConfig.getAWTGraphicsConfiguration(); + final boolean equalCaps = newConfig.getChosenCapabilities().equals(awtConfig.getChosenCapabilities()); + if(DEBUG) { + System.err.println(getThreadName()+": getGraphicsConfiguration() Info: Changed GC and GD"); + System.err.println("Created Config (n): Old GC "+oldGC); + System.err.println("Created Config (n): Old GD "+oldGC.getDevice().getIDstring()); + System.err.println("Created Config (n): Parent GC "+parentGC); + System.err.println("Created Config (n): Parent GD "+parentGC.getDevice().getIDstring()); + System.err.println("Created Config (n): New GC "+newGC); + System.err.println("Created Config (n): New GD "+newGC.getDevice().getIDstring()); + System.err.println("Created Config (n): Old CF "+awtConfig); + System.err.println("Created Config (n): New CF "+newConfig); + System.err.println("Created Config (n): EQUALS CAPS "+equalCaps); + // Thread.dumpStack(); + } + if ( null != newGC ) { + if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) { + // complete destruction! + destroyImpl( true ); + // recreation! + setAWTGraphicsConfiguration(newConfig); + createJAWTDrawableAndContext(); + validateGLDrawable(); + } else { + setAWTGraphicsConfiguration(newConfig); + } + /** + * Return the newGC, which covers the desired capabilities and is compatible + * with the available GC's of its devices. + */ + if(DEBUG) { + System.err.println(getThreadName()+": Info: getGraphicsConfiguration - end.01: newGC "+newGC); + } + return newGC; + } else { + if(DEBUG) { + System.err.println(getThreadName()+": Info: getGraphicsConfiguration - end.00: oldGC "+oldGC); + } + } } - } + /** + * If a new GC was _not_ found/defined above, + * method returns oldGC as selected in the constructor or first addNotify(). + * This may cause an exception in Component.checkGD when adding to a + * container, and is the desired behavior. + */ + return oldGC; + } else if (null == parentGC) { + /** + * The parentGC is null, which means we have no native peer, and are not + * part of a (realized) component hierarchy. So we return the + * desired visual that was selected in the constructor (possibly + * null). + */ + return oldGC; + } else { + /** + * Otherwise we have not explicitly selected a GC in the constructor, so + * just return what Canvas would have. + */ + return parentGC; } - - /* - * If a compatible GC was not found in the block above, this will - * return the GC that was selected in the constructor (and might - * cause an exception in Component.checkGD when adding to a - * container, but in this case that would be the desired behavior). - * - */ - return chosen; - } else if (gc == null) { - /* - * The GC is null, which means we have no native peer, and are not - * part of a (realized) component hierarchy. So we return the - * desired visual that was selected in the constructor (possibly - * null). - */ - return chosen; - } - - /* - * Otherwise we have not explicitly selected a GC in the constructor, so - * just return what Canvas would have. - */ - return gc; } @Override @@ -606,20 +585,35 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } else { /** * 'super.addNotify()' determines the GraphicsConfiguration, - * while calling this class's overriden 'getGraphicsConfiguration()' method + * while calling this class's overridden 'getGraphicsConfiguration()' method * after which it creates the native peer. * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration * is being used in getGraphicsConfiguration(). * This code order also allows recreation, ie re-adding the GLCanvas. */ - awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device); - if(null==awtConfig) { - throw new GLException("Error: NULL AWTGraphicsConfiguration"); - } // before native peer is valid: X11 disableBackgroundErase(); + final GraphicsDevice awtDevice; + if(null==awtDeviceReq) { + // Query AWT GraphicsDevice from parent tree, default + final GraphicsConfiguration gc = super.getGraphicsConfiguration(); + if(null==gc) { + throw new GLException("Error: NULL AWT GraphicsConfiguration"); + } + awtDevice = gc.getDevice(); + } else { + // Use one time user AWT GraphicsDevice request + awtDevice = awtDeviceReq; + awtDeviceReq = null; + } + final AWTGraphicsConfiguration awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, awtDevice); + if(null==awtConfig) { + throw new GLException("Error: NULL AWTGraphicsConfiguration"); + } + setAWTGraphicsConfiguration(awtConfig); + // issues getGraphicsConfiguration() and creates the native peer super.addNotify(); @@ -775,6 +769,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing return false; } + private void setAWTGraphicsConfiguration(final AWTGraphicsConfiguration config) { + // Cache awtConfig + awtConfig = config; + if( null != jawtWindow ) { + // Notify JAWTWindow .. + jawtWindow.setAWTGraphicsConfiguration(config); + } + } + /** <p>Overridden to track when this component is removed from a container. Subclasses which override this method must call super.removeNotify() in their removeNotify() method in order to @@ -1394,7 +1397,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post GraphicsDevice: "+adeviceMsg+", result: "+closed); } } - awtConfig=null; + awtConfig = null; } }; @@ -1546,10 +1549,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing if( Beans.isDesignTime() ) { return null; } - - final AbstractGraphicsScreen aScreen = null != device ? - AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT): - AWTGraphicsScreen.createDefault(); + if( null == device ) { + throw new GLException("Error: NULL AWT GraphicsDevice"); + } + final AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT); AWTGraphicsConfiguration config = null; if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java index a04055430..7f630f9d5 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java @@ -35,6 +35,7 @@ import jogamp.opengl.Debug; import com.jogamp.common.os.Platform; import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.opengl.math.geom.Frustum; /** * Basic Float math utility functions. @@ -491,18 +492,18 @@ public final class FloatUtil { * @param zNear * @param zFar * @return given matrix for chaining - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, - * or if left == right, or bottom == top, or zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * or {@code left == right}, or {@code bottom == top}. */ public static float[] makeFrustum(final float[] m, final int m_offset, final boolean initM, final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException { - if( zNear <= 0.0f || zFar < 0.0f ) { - throw new GLException("GL_INVALID_VALUE: zNear and zFar must be positive, and zNear>0"); + if( zNear <= 0.0f || zFar <= zNear ) { + throw new GLException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar); } - if( left == right || top == bottom || zNear == zFar ) { - throw new GLException("GL_INVALID_VALUE: top,bottom and left,right and zNear,zFar must not be equal"); + if( left == right || top == bottom) { + throw new GLException("GL_INVALID_VALUE: top,bottom and left,right must not be equal"); } if( initM ) { // m[m_offset+0+4*0] = 1f; @@ -565,14 +566,15 @@ public final class FloatUtil { * @param zNear * @param zFar * @return given matrix for chaining - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * @see #makeFrustum(float[], int, boolean, float, float, float, float, float, float) */ public static float[] makePerspective(final float[] m, final int m_off, final boolean initM, final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException { final float top = tan(fovy_rad/2f) * zNear; // use tangent of half-fov ! - final float bottom = -1.0f * top; - final float left = aspect * bottom; - final float right = aspect * top; + final float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear + final float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear + final float right = aspect * top; // aspect * fovhvTan.top * zNear return makeFrustum(m, m_off, initM, left, right, bottom, top, zNear, zFar); } @@ -591,7 +593,9 @@ public final class FloatUtil { * @param zNear * @param zFar * @return given matrix for chaining - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * @see #makeFrustum(float[], int, boolean, float, float, float, float, float, float) + * @see Frustum#updateByFovDesc(float[], int, boolean, Frustum.FovDesc) */ public static float[] makePerspective(final float[] m, final int m_offset, final boolean initM, final FovHVHalves fovhv, final float zNear, final float zFar) throws GLException { diff --git a/src/jogl/classes/com/jogamp/opengl/math/FovHVHalves.java b/src/jogl/classes/com/jogamp/opengl/math/FovHVHalves.java index 26ed57009..5d7907f2f 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/FovHVHalves.java +++ b/src/jogl/classes/com/jogamp/opengl/math/FovHVHalves.java @@ -35,13 +35,13 @@ package com.jogamp.opengl.math; * </p> */ public final class FovHVHalves { - /** Half horizontal FOV from center to left. */ + /** Half horizontal FOV from center to left, either in {@link #inTangents} or radians. */ public final float left; - /** Half horizontal FOV from center to right. */ + /** Half horizontal FOV from center to right, either in {@link #inTangents} or radians. */ public final float right; - /** Half vertical FOV from center to top. */ + /** Half vertical FOV from center to top, either in {@link #inTangents} or radians. */ public final float top; - /** Half vertical FOV from center to bottom. */ + /** Half vertical FOV from center to bottom, either in {@link #inTangents} or radians. */ public final float bottom; /** If true, values are in tangent, otherwise radians.*/ public final boolean inTangents; @@ -67,7 +67,7 @@ public final class FovHVHalves { } /** - * Returns a symmetrical centered {@link FovHVHalves} instance in tangents, using: + * Returns a symmetrical centered {@link FovHVHalves} instance in {@link #inTangents}, using: * <pre> halfHorizFovTan = tan( horizontalFov / 2f ); halfVertFovTan = tan( verticalFov / 2f ); @@ -82,7 +82,7 @@ public final class FovHVHalves { } /** - * Returns a symmetrical centered {@link FovHVHalves} instance in tangents, using: + * Returns a symmetrical centered {@link FovHVHalves} instance in {@link #inTangents}, using: * <pre> top = bottom = tan( verticalFov / 2f ); left = right = aspect * top; @@ -99,7 +99,7 @@ public final class FovHVHalves { } /** - * Returns a custom symmetry {@link FovHVHalves} instance in tangents, using: + * Returns a custom symmetry {@link FovHVHalves} instance {@link #inTangents}, using: * <pre> left = tan( horizontalFov * horizCenterFromLeft ) right = tan( horizontalFov * ( 1f - horizCenterFromLeft ) ) @@ -121,7 +121,7 @@ public final class FovHVHalves { } /** - * Returns a custom symmetry {@link FovHVHalves} instance in tangents, + * Returns a custom symmetry {@link FovHVHalves} instance {@link #inTangents}, * via computing the <code>horizontalFov</code> using: * <pre> halfVertFovTan = tan( verticalFov / 2f ); @@ -157,10 +157,10 @@ public final class FovHVHalves { } } - /** Returns the full horizontal FOV, i.e. {@link #left} + {@link #right}. */ + /** Returns the full horizontal FOV, i.e. {@link #left} + {@link #right}, either in {@link #inTangents} or radians. */ public final float horzFov() { return left+right; } - /** Returns the full vertical FOV, i.e. {@link #top} + {@link #bottom}. */ + /** Returns the full vertical FOV, i.e. {@link #top} + {@link #bottom}, either in {@link #inTangents} or radians. */ public final float vertFov() { return top+bottom; } public final String toString() { diff --git a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java b/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java index 421bb909f..a080d4442 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java +++ b/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java @@ -147,8 +147,9 @@ public class Matrix4 { * @param top * @param zNear * @param zFar - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, - * or if left == right, or bottom == top, or zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * or {@code left == right}, or {@code bottom == top}. + * @see FloatUtil#makeFrustum(float[], int, boolean, float, float, float, float, float, float) */ public final void makeFrustum(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException { multMatrix( FloatUtil.makeFrustum(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar) ); @@ -159,7 +160,8 @@ public class Matrix4 { * @param aspect * @param zNear * @param zFar - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * @see FloatUtil#makePerspective(float[], int, boolean, float, float, float, float) */ public final void makePerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException { multMatrix( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_rad, aspect, zNear, zFar) ); diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java index b73bad613..8b0fa559e 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java +++ b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java @@ -30,6 +30,8 @@ package com.jogamp.opengl.math.geom; import jogamp.common.os.PlatformPropsImpl; import com.jogamp.common.os.Platform; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.FovHVHalves; /** * Providing frustum {@link #getPlanes() planes} derived by different inputs @@ -77,6 +79,35 @@ import com.jogamp.common.os.Platform; * </p> */ public class Frustum { + /** + * {@link Frustum} description by {@link #fovhv} and {@link #zNear}, {@link #zFar}. + */ + public static class FovDesc { + /** Field of view in both directions, may not be centered, either {@link FovHVHalves#inTangents} or radians. */ + public final FovHVHalves fovhv; + /** Near Z */ + public final float zNear; + /** Far Z */ + public final float zFar; + /** + * @param fovhv field of view in both directions, may not be centered, either {@link FovHVHalves#inTangents} or radians + * @param zNear + * @param zFar + * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}. + */ + public FovDesc(final FovHVHalves fovhv, final float zNear, final float zFar) throws IllegalArgumentException { + if( zNear <= 0.0f || zFar <= zNear ) { + throw new IllegalArgumentException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar); + } + this.fovhv = fovhv; + this.zNear = zNear; + this.zFar = zFar; + } + public final String toString() { + return "FrustumFovDesc["+fovhv.toStringInDegrees()+", Z["+zNear+" - "+zFar+"]]"; + } + } + /** Normalized planes[l, r, b, t, n, f] */ protected final Plane[] planes = new Plane[6]; @@ -176,19 +207,47 @@ public class Frustum { */ public final void updateByPlanes(final Plane[] src) { for (int i = 0; i < 6; ++i) { - final Plane p0 = planes[i]; - final float[] p0_n = p0.n; - final Plane p1 = src[i]; - final float[] p1_n = p1.n; - p0_n[0] = p1_n[0]; - p0_n[1] = p1_n[1]; - p0_n[2] = p1_n[2]; - p0.d = p1.d; + final Plane pD = planes[i]; + final Plane pS = src[i]; + pD.d = pS.d; + System.arraycopy(pS.n, 0, pD.n, 0, 3); } } /** * Calculate the frustum planes in world coordinates + * using the passed {@link FovDesc}. + * <p> + * Operation Details: + * <ul> + * <li>The given {@link FovDesc} will be transformed + * into the given float[16] as a perspective matrix (column major order) first, + * see {@link FloatUtil#makePerspective(float[], int, boolean, FovHVHalves, float, float)}.</li> + * <li>Then the float[16] perspective matrix is used to {@link #updateByPMV(float[], int)} this instance.</li> + * </ul> + * </p> + * <p> + * Frustum plane's normals will point to the inside of the viewing frustum, + * as required by this class. + * </p> + * + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @param initM if true, given matrix will be initialized w/ identity matrix, + * otherwise only the frustum fields are set. + * @param fovDesc {@link Frustum} {@link FovDesc} + * @return given matrix for chaining + * @see FloatUtil#makePerspective(float[], int, boolean, FovHVHalves, float, float) + */ + public float[] updateByFovDesc(final float[] m, final int m_offset, final boolean initM, + final FovDesc fovDesc) { + FloatUtil.makePerspective(m, m_offset, initM, fovDesc.fovhv, fovDesc.zNear, fovDesc.zFar); + updateByPMV(m, 0); + return m; + } + + /** + * Calculate the frustum planes in world coordinates * using the passed float[16] as premultiplied P*MV (column major order). * <p> * Frustum plane's normals will point to the inside of the viewing frustum, diff --git a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java index 57f9301b8..196acf9ab 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java +++ b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java @@ -663,8 +663,9 @@ public final class PMVMatrix implements GLMatrixFunc { /** * {@inheritDoc} * - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, - * or if left == right, or bottom == top, or zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * or {@code left == right}, or {@code bottom == top}. + * @see FloatUtil#makeFrustum(float[], int, boolean, float, float, float, float, float, float) */ @Override public final void glFrustumf(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException { @@ -682,7 +683,8 @@ public final class PMVMatrix implements GLMatrixFunc { * @param aspect aspect ratio width / height * @param zNear * @param zFar - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * @see FloatUtil#makePerspective(float[], int, boolean, float, float, float, float) */ public final void gluPerspective(final float fovy_deg, final float aspect, final float zNear, final float zFar) throws GLException { glMultMatrixf( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_deg * FloatUtil.PI / 180.0f, aspect, zNear, zFar), 0 ); diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java index 6052c3b49..e1db3f7a3 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java @@ -189,7 +189,7 @@ public class ShaderCode { * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. * @param count number of shaders * @param context class used to help resolving the source location - * @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code> + * @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code> * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance * which can be edited later on at the costs of a String conversion when passing to * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}. @@ -200,7 +200,8 @@ public class ShaderCode { * @throws IllegalArgumentException if <code>count</code> and <code>sourceFiles.length</code> do not match * @see #readShaderSource(Class, String) */ - public static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context, final String[] sourceFiles, final boolean mutableStringBuilder) { + public static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context, + final String[] sourceFiles, final boolean mutableStringBuilder) { if(null != gl && !ShaderUtil.isShaderCompilerAvailable(gl)) { return null; } @@ -227,6 +228,53 @@ public class ShaderCode { } /** + * Creates a complete {@link ShaderCode} object while reading all shader sources from {@link Uri} <code>sourceLocations</code> + * via {@link #readShaderSource(Uri, boolean)}. + * + * @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed. + * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, + * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * @param count number of shaders + * @param sourceLocations array of {@link Uri} source locations, organized as <code>sourceFiles[count]</code> -> <code>shaderSources[count][1]</code> + * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance + * which can be edited later on at the costs of a String conversion when passing to + * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}. + * If <code>false</code> method returns an immutable <code>String</code> instance, + * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)} + * at no additional costs. + * + * @throws IllegalArgumentException if <code>count</code> and <code>sourceFiles.length</code> do not match + * @see #readShaderSource(Uri, boolean) + * @since 2.3.2 + */ + public static ShaderCode create(final GL2ES2 gl, final int type, final int count, + final Uri[] sourceLocations, final boolean mutableStringBuilder) { + if(null != gl && !ShaderUtil.isShaderCompilerAvailable(gl)) { + return null; + } + + CharSequence[][] shaderSources = null; + if(null!=sourceLocations) { + // sourceFiles.length and count is validated in ctor + shaderSources = new CharSequence[sourceLocations.length][1]; + for(int i=0; i<sourceLocations.length; i++) { + try { + shaderSources[i][0] = readShaderSource(sourceLocations[i], mutableStringBuilder); + } catch (final IOException ioe) { + throw new RuntimeException("readShaderSource("+sourceLocations[i]+") error: ", ioe); + } + if(null == shaderSources[i][0]) { + shaderSources = null; + } + } + } + if(null==shaderSources) { + return null; + } + return new ShaderCode(type, count, shaderSources); + } + + /** * Creates a complete {@link ShaderCode} object while reading the shader binary of <code>binaryFile</code>, * which location is resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}. * @@ -259,6 +307,37 @@ public class ShaderCode { } /** + * Creates a complete {@link ShaderCode} object while reading the shader binary from {@link Uri} <code>binLocations</code> + * via {@link #readShaderBinary(Uri)}. + * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, + * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * @param count number of shaders + * @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}. + * @param binLocations {@link Uri} binary location + * + * @see #readShaderBinary(Uri) + * @see ShaderUtil#getShaderBinaryFormats(GL) + * @since 2.3.2 + */ + public static ShaderCode create(final int type, final int count, int binFormat, final Uri binLocation) { + ByteBuffer shaderBinary = null; + if(null!=binLocation && 0<=binFormat) { + try { + shaderBinary = readShaderBinary(binLocation); + } catch (final IOException ioe) { + throw new RuntimeException("readShaderBinary("+binLocation+") error: ", ioe); + } + if(null == shaderBinary) { + binFormat = -1; + } + } + if(null==shaderBinary) { + return null; + } + return new ShaderCode(type, count, binFormat, shaderBinary); + } + + /** * Returns a unique suffix for shader resources as follows: * <ul> * <li>Source<ul> @@ -327,7 +406,8 @@ public class ShaderCode { * whatever is available first. * <p> * The source and binary location names are expected w/o suffixes which are - * resolved and appended using {@link #getFileSuffix(boolean, int)}. + * resolved and appended using the given {@code srcSuffixOpt} and {@code binSuffixOpt} + * if not {@code null}, otherwise {@link #getFileSuffix(boolean, int)} determines the suffixes. * </p> * <p> * Additionally, the binary resource is expected within a subfolder of <code>binRoot</code> @@ -358,9 +438,11 @@ public class ShaderCode { * Your invocation in org/test/glsl/MyShaderTest.java: * * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(), - * "shader", new String[] { "vertex" }, "shader/bin", "vertex"); + * "shader", new String[] { "vertex" }, null, + * "shader/bin", "vertex", null, true); * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(), - * "shader", new String[] { "vertex" }, "shader/bin", "fragment"); + * "shader", new String[] { "vertex" }, null, + * "shader/bin", "fragment", null, true); * ShaderProgram sp0 = new ShaderProgram(); * sp0.add(gl, vp0, System.err); * sp0.add(gl, fp0, System.err); @@ -380,8 +462,12 @@ public class ShaderCode { * @param context class used to help resolving the source and binary location * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional * @param srcBasenames basenames w/o path or suffix relative to <code>srcRoot</code> for the shader's source code + * @param srcSuffixOpt optional custom suffix for shader's source file, + * if {@code null} {@link #getFileSuffix(boolean, int)} is being used. * @param binRoot relative <i>root</i> path for <code>binBasenames</code> * @param binBasename basename w/o path or suffix relative to <code>binRoot</code> for the shader's binary code + * @param binSuffixOpt optional custom suffix for shader's binary file, + * if {@code null} {@link #getFileSuffix(boolean, int)} is being used. * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance * which can be edited later on at the costs of a String conversion when passing to * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}. @@ -397,9 +483,12 @@ public class ShaderCode { * @see #getFileSuffix(boolean, int) * @see ShaderUtil#getShaderBinaryFormats(GL) * @see #getBinarySubPath(int) + * + * @since 2.3.2 */ public static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context, - final String srcRoot, final String[] srcBasenames, final String binRoot, final String binBasename, + final String srcRoot, final String[] srcBasenames, final String srcSuffixOpt, + final String binRoot, final String binBasename, final String binSuffixOpt, final boolean mutableStringBuilder) { ShaderCode res = null; final String srcPath[]; @@ -408,7 +497,7 @@ public class ShaderCode { if( null!=srcBasenames && ShaderUtil.isShaderCompilerAvailable(gl) ) { srcPath = new String[srcBasenames.length]; - final String srcSuffix = getFileSuffix(false, type); + final String srcSuffix = null != srcSuffixOpt ? srcSuffixOpt : getFileSuffix(false, type); if( null != srcRoot && srcRoot.length() > 0 ) { for(int i=0; i<srcPath.length; i++) { srcPath[i] = srcRoot + '/' + srcBasenames[i] + "." + srcSuffix; @@ -428,7 +517,7 @@ public class ShaderCode { } if( null!=binBasename ) { final Set<Integer> binFmts = ShaderUtil.getShaderBinaryFormats(gl); - final String binSuffix = getFileSuffix(true, type); + final String binSuffix = null != binSuffixOpt ? binSuffixOpt : getFileSuffix(true, type); for(final Iterator<Integer> iter=binFmts.iterator(); iter.hasNext(); ) { final int bFmt = iter.next().intValue(); final String bFmtPath = getBinarySubPath(bFmt); @@ -445,7 +534,162 @@ public class ShaderCode { } /** - * Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String, boolean)}. + * Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)}. + * <p> + * Convenient creation method for instantiating a complete {@link ShaderCode} object + * either from source code using {@link #create(GL2ES2, int, int, Class, String[])}, + * or from a binary code using {@link #create(int, int, Class, int, String)}, + * whatever is available first. + * </p> + * <p> + * The source and binary location names are expected w/o suffixes which are + * resolved and appended using {@link #getFileSuffix(boolean, int)}. + * </p> + * <p> + * Additionally, the binary resource is expected within a subfolder of <code>binRoot</code> + * which reflects the vendor specific binary format, see {@link #getBinarySubPath(int)}. + * All {@link ShaderUtil#getShaderBinaryFormats(GL)} are being iterated + * using the binary subfolder, the first existing resource is being used. + * </p> + * + * Example: + * <pre> + * Your std JVM layout (plain or within a JAR): + * + * org/test/glsl/MyShaderTest.class + * org/test/glsl/shader/vertex.vp + * org/test/glsl/shader/fragment.fp + * org/test/glsl/shader/bin/nvidia/vertex.bvp + * org/test/glsl/shader/bin/nvidia/fragment.bfp + * + * Your Android APK layout: + * + * classes.dex + * assets/org/test/glsl/shader/vertex.vp + * assets/org/test/glsl/shader/fragment.fp + * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp + * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp + * ... + * + * Your invocation in org/test/glsl/MyShaderTest.java: + * + * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(), + * "shader", new String[] { "vertex" }, "shader/bin", "vertex", true); + * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(), + * "shader", new String[] { "vertex" }, "shader/bin", "fragment", true); + * ShaderProgram sp0 = new ShaderProgram(); + * sp0.add(gl, vp0, System.err); + * sp0.add(gl, fp0, System.err); + * st.attachShaderProgram(gl, sp0, true); + * </pre> + * A simplified entry point is {@link #create(GL2ES2, int, Class, String, String, String, boolean)}. + * + * <p> + * The location is finally being resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}. + * </p> + * + * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used), + * or to determine the shader binary format (if <code>binary</code> is used). + * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, + * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * @param count number of shaders + * @param context class used to help resolving the source and binary location + * @param srcRoot relative <i>root</i> path for <code>srcBasenames</code> optional + * @param srcBasenames basenames w/o path or suffix relative to <code>srcRoot</code> for the shader's source code + * @param binRoot relative <i>root</i> path for <code>binBasenames</code> + * @param binBasename basename w/o path or suffix relative to <code>binRoot</code> for the shader's binary code + * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance + * which can be edited later on at the costs of a String conversion when passing to + * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}. + * If <code>false</code> method returns an immutable <code>String</code> instance, + * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)} + * at no additional costs. + * + * @throws IllegalArgumentException if <code>count</code> and <code>srcBasenames.length</code> do not match + * + * @see #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean) + * @see #readShaderSource(Class, String) + * @see #getFileSuffix(boolean, int) + * @see ShaderUtil#getShaderBinaryFormats(GL) + * @see #getBinarySubPath(int) + */ + public static ShaderCode create(final GL2ES2 gl, final int type, final int count, final Class<?> context, + final String srcRoot, final String[] srcBasenames, + final String binRoot, final String binBasename, + final boolean mutableStringBuilder) { + return create(gl, type, count, context, srcRoot, srcBasenames, null, + binRoot, binBasename, null, mutableStringBuilder); + } + + /** + * Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean)}. + * <p> + * Example: + * <pre> + * Your std JVM layout (plain or within a JAR): + * + * org/test/glsl/MyShaderTest.class + * org/test/glsl/shader/vertex.vp + * org/test/glsl/shader/fragment.fp + * org/test/glsl/shader/bin/nvidia/vertex.bvp + * org/test/glsl/shader/bin/nvidia/fragment.bfp + * + * Your Android APK layout: + * + * classes.dex + * assets/org/test/glsl/shader/vertex.vp + * assets/org/test/glsl/shader/fragment.fp + * assets/org/test/glsl/shader/bin/nvidia/vertex.bvp + * assets/org/test/glsl/shader/bin/nvidia/fragment.bfp + * ... + * + * Your invocation in org/test/glsl/MyShaderTest.java: + * + * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), + * "shader", "shader/bin", "vertex", null, null, true); + * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), + * "shader", "shader/bin", "fragment", null, null, true); + * ShaderProgram sp0 = new ShaderProgram(); + * sp0.add(gl, vp0, System.err); + * sp0.add(gl, fp0, System.err); + * st.attachShaderProgram(gl, sp0, true); + * </pre> + * </p> + * + * @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used), + * or to determine the shader binary format (if <code>binary</code> is used). + * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER}, {@link GL3#GL_GEOMETRY_SHADER}, + * {@link GL4#GL_TESS_CONTROL_SHADER} or {@link GL4#GL_TESS_EVALUATION_SHADER}. + * @param context class used to help resolving the source and binary location + * @param srcRoot relative <i>root</i> path for <code>basename</code> optional + * @param binRoot relative <i>root</i> path for <code>basename</code> + * @param basename basename w/o path or suffix relative to <code>srcRoot</code> and <code>binRoot</code> + * for the shader's source and binary code. + * @param srcSuffixOpt optional custom suffix for shader's source file, + * if {@code null} {@link #getFileSuffix(boolean, int)} is being used. + * @param binSuffixOpt optional custom suffix for shader's binary file, + * if {@code null} {@link #getFileSuffix(boolean, int)} is being used. + * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance + * which can be edited later on at the costs of a String conversion when passing to + * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}. + * If <code>false</code> method returns an immutable <code>String</code> instance, + * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)} + * at no additional costs. + * @throws IllegalArgumentException if <code>count</code> is not 1 + * + * @see #create(GL2ES2, int, int, Class, String, String[], String, String, String, String, boolean) + * @since 2.3.2 + */ + public static ShaderCode create(final GL2ES2 gl, final int type, final Class<?> context, + final String srcRoot, final String binRoot, + final String basename, final String srcSuffixOpt, final String binSuffixOpt, + final boolean mutableStringBuilder) { + return create(gl, type, 1, context, srcRoot, new String[] { basename }, srcSuffixOpt, + binRoot, basename, binSuffixOpt, mutableStringBuilder ); + } + + /** + * Simplified variation of {@link #create(GL2ES2, int, Class, String, String, String, String, String, boolean)}. * <p> * Example: * <pre> @@ -469,9 +713,9 @@ public class ShaderCode { * Your invocation in org/test/glsl/MyShaderTest.java: * * ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), - * "shader", "shader/bin", "vertex"); + * "shader", "shader/bin", "vertex", true); * ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), - * "shader", "shader/bin", "fragment"); + * "shader", "shader/bin", "fragment", true); * ShaderProgram sp0 = new ShaderProgram(); * sp0.add(gl, vp0, System.err); * sp0.add(gl, fp0, System.err); @@ -496,12 +740,11 @@ public class ShaderCode { * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)} * at no additional costs. * @throws IllegalArgumentException if <code>count</code> is not 1 - * - * @see #create(GL2ES2, int, int, Class, String, String[], String, String) */ public static ShaderCode create(final GL2ES2 gl, final int type, final Class<?> context, - final String srcRoot, final String binRoot, final String basename, final boolean mutableStringBuilder) { - return create(gl, type, 1, context, srcRoot, new String[] { basename }, binRoot, basename, mutableStringBuilder ); + final String srcRoot, final String binRoot, final String basename, + final boolean mutableStringBuilder) { + return ShaderCode.create(gl, type, context, srcRoot, binRoot, basename, null, null, mutableStringBuilder); } /** @@ -815,7 +1058,6 @@ public class ShaderCode { } } - @SuppressWarnings("resource") private static int readShaderSource(final Class<?> context, final URLConnection conn, final StringBuilder result, int lineno) throws IOException { if(DEBUG_CODE) { if(0 == lineno) { @@ -858,10 +1100,11 @@ public class ShaderCode { } /** + * Reads shader source located in <code>conn</code>. * - * @param context - * @param conn - * @param result + * @param context class used to help resolve the source location, may be {@code null} + * @param conn the {@link URLConnection} of the shader source + * @param result {@link StringBuilder} sink for the resulting shader source code * @throws IOException */ public static void readShaderSource(final Class<?> context, final URLConnection conn, final StringBuilder result) throws IOException { @@ -899,6 +1142,28 @@ public class ShaderCode { } /** + * Reads shader source located from {@link Uri#absolute} {@link Uri} <code>sourceLocation</code>. + * @param sourceLocation {@link Uri} location of shader source + * @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance + * which can be edited later on at the costs of a String conversion when passing to + * {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}. + * If <code>false</code> method returns an immutable <code>String</code> instance, + * which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)} + * at no additional costs. + * @throws IOException + * @since 2.3.2 + */ + public static CharSequence readShaderSource(final Uri sourceLocation, final boolean mutableStringBuilder) throws IOException { + final URLConnection conn = IOUtil.openURL(sourceLocation.toURL(), "ShaderCode "); + if (conn == null) { + return null; + } + final StringBuilder result = new StringBuilder(); + readShaderSource(null, conn, result); + return mutableStringBuilder ? result : result.toString(); + } + + /** * Reads shader binary located in <code>path</code>, * either relative to the <code>context</code> class or absolute <i>as-is</i>. * <p> @@ -925,6 +1190,25 @@ public class ShaderCode { } } + /** + * Reads shader binary located from {@link Uri#absolute} {@link Uri} <code>binLocation</code>. + * @param binLocation {@link Uri} location of shader binary + * @throws IOException + * @since 2.3.2 + */ + public static ByteBuffer readShaderBinary(final Uri binLocation) throws IOException { + final URLConnection conn = IOUtil.openURL(binLocation.toURL(), "ShaderCode "); + if (conn == null) { + return null; + } + final BufferedInputStream bis = new BufferedInputStream( conn.getInputStream() ); + try { + return IOUtil.copyStream2ByteBuffer( bis ); + } finally { + IOUtil.close(bis, false); + } + } + // Shall we use: #ifdef GL_FRAGMENT_PRECISION_HIGH .. #endif for using highp in fragment shader if avail ? /** Default precision of {@link GL#isGLES2() ES2} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es2_default_precision_vp} */ public static final String es2_default_precision_vp = "\nprecision highp float;\nprecision highp int;\n/*precision lowp sampler2D;*/\n/*precision lowp samplerCube;*/\n"; diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java index 075da340b..43a6cfc58 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java +++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java @@ -30,7 +30,7 @@ package com.jogamp.opengl.util.stereo; import com.jogamp.opengl.math.FovHVHalves; /** - * Constant parameter for one eye. + * Constant single eye parameter of the viewer, relative to its {@link ViewerPose}. */ public final class EyeParameter { /** Eye number, <code>0</code> for the left eye and <code>1</code> for the right eye. */ @@ -39,7 +39,7 @@ public final class EyeParameter { /** float[3] eye position vector used to define eye height in meter relative to <i>actor</i>. */ public final float[] positionOffset; - /** Field of view in both directions, may not be centered, either in radians or tangent. */ + /** Field of view in both directions, may not be centered, either {@link FovHVHalves#inTangents} or radians. */ public final FovHVHalves fovhv; /** IPD related horizontal distance from nose to pupil in meter. */ diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java new file mode 100644 index 000000000..b795927cd --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java @@ -0,0 +1,51 @@ +/** + * Copyright 2015 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.util.stereo; + +import com.jogamp.opengl.math.geom.Frustum; + +/** + * Constant parameter of the positioning sensor to locate the {@link ViewerPose}. + */ +public final class LocationSensorParameter { + /** The {@link Frustum} of the location sensor. */ + public final Frustum frustum; + /** The {@link Frustum}'s {@link Frustum.FovDesc} description of the location sensor. */ + public final Frustum.FovDesc frustumDesc; + /** The {@link Frustum}'s float[16] projection matrix of the location sensor. */ + public final float[] frustumProjMat; + + public LocationSensorParameter(final Frustum.FovDesc fovDesc) { + this.frustumDesc = fovDesc; + this.frustum = new Frustum(); + this.frustumProjMat = frustum.updateByFovDesc(new float[16], 0, true, fovDesc); + } + public final String toString() { + return "LocationSensor["+frustumDesc+"]"; + } +}
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java index 68d0f4b39..b6112650a 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java +++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java @@ -117,6 +117,23 @@ public interface StereoDevice { public FovHVHalves[] getDefaultFOV(); /** + * Returns the {@link LocationSensorParameter} of the device + * if {@link #SENSOR_POSITION} is {@link #getSupportedSensorBits() supported}, + * otherwise returns {@code null}. + */ + public LocationSensorParameter getLocationSensorParams(); + + + /** + * Sets the location sensor's origin of this device to the current position. + * <p> + * In case {@link #SENSOR_POSITION} is not {@link #getSupportedSensorBits() supported}, + * this method is a no-op. + * </p> + */ + public void resetLocationSensorOrigin(); + + /** * Start desired and required sensors. Returns true if action was successful, otherwise false. * <p> * Method fails if required sensors are not {@link #getSupportedSensorBits() supported}. diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java index 40411ac88..10ee4c994 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java +++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java @@ -30,7 +30,7 @@ package com.jogamp.opengl.util.stereo; import com.jogamp.opengl.math.Quaternion; /** - * Position and orientation of viewer. + * {@link #position} and {@link #orientation} of viewer. */ public final class ViewerPose { /** diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 401ea29c6..8f4105f98 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -422,7 +422,7 @@ public abstract class GLContextImpl extends GLContext { lastCtxReleaseStack = new Throwable(msg); if( TRACE_SWITCH ) { System.err.println(msg); - // ExceptionUtils.dumpStackTrace(System.err, 0, 10); + // ExceptionUtils.dumpStack(System.err, 0, 10); } } } @@ -773,7 +773,7 @@ public abstract class GLContextImpl extends GLContext { } if ( DEBUG_TRACE_SWITCH ) { System.err.println(getThreadName() + ": Create GL context "+(created?"OK":"FAILED")+": For " + getClass().getName()+" - "+getGLVersion()+" - "+getTraceSwitchMsg()); - // ExceptionUtils.dumpStackTrace(System.err, 0, 10); + // ExceptionUtils.dumpStack(System.err, 0, 10); } if(!created) { return CONTEXT_NOT_CURRENT; diff --git a/src/jogl/classes/jogamp/opengl/ProjectFloat.java b/src/jogl/classes/jogamp/opengl/ProjectFloat.java index ee9560214..5ec5a8e3f 100644 --- a/src/jogl/classes/jogamp/opengl/ProjectFloat.java +++ b/src/jogl/classes/jogamp/opengl/ProjectFloat.java @@ -170,7 +170,8 @@ public class ProjectFloat { * @param aspect * @param zNear * @param zFar - * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. + * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} + * @see FloatUtil#makePerspective(float[], int, boolean, float, float, float, float) */ public void gluPerspective(final GLMatrixFunc gl, final float fovy_deg, final float aspect, final float zNear, final float zFar) throws GLException { gl.glMultMatrixf(FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_deg * FloatUtil.PI / 180.0f, aspect, zNear, zFar), 0); diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java index 491535dc1..bfe93b59c 100644 --- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java +++ b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java @@ -36,6 +36,7 @@ import com.jogamp.nativewindow.util.RectangleImmutable; import com.jogamp.opengl.math.FovHVHalves; import com.jogamp.opengl.util.stereo.StereoDeviceConfig; import com.jogamp.opengl.util.stereo.EyeParameter; +import com.jogamp.opengl.util.stereo.LocationSensorParameter; import com.jogamp.opengl.util.stereo.StereoDevice; import com.jogamp.opengl.util.stereo.StereoDeviceFactory; import com.jogamp.opengl.util.stereo.StereoDeviceRenderer; @@ -163,31 +164,27 @@ public class GenericStereoDevice implements StereoDevice { } @Override - public boolean isValid() { - return true; - } + public boolean isValid() { return true; } @Override - public final PointImmutable getPosition() { - return surfacePos; - } + public final PointImmutable getPosition() { return surfacePos; } @Override - public final DimensionImmutable getSurfaceSize() { - return config.surfaceSizeInPixels; - } + public final DimensionImmutable getSurfaceSize() { return config.surfaceSizeInPixels; } @Override public int getRequiredRotation() { return 0; } @Override - public float[] getDefaultEyePositionOffset() { - return config.defaultEyeParam[0].positionOffset; - } + public float[] getDefaultEyePositionOffset() { return config.defaultEyeParam[0].positionOffset; } @Override - public final FovHVHalves[] getDefaultFOV() { - return defaultEyeFov; - } + public final FovHVHalves[] getDefaultFOV() { return defaultEyeFov; } + + @Override + public final LocationSensorParameter getLocationSensorParams() { return null; } + + @Override + public final void resetLocationSensorOrigin() { } @Override public final boolean startSensors(final int desiredSensorBits, final int requiredSensorBits) { |