diff options
Diffstat (limited to 'src/nativewindow/classes/com/jogamp')
39 files changed, 6823 insertions, 0 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsConfiguration.java new file mode 100644 index 000000000..684f1f86a --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsConfiguration.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +/** A marker interface describing a graphics configuration, visual, or + pixel format in a toolkit-independent manner. */ +public interface AbstractGraphicsConfiguration extends VisualIDHolder, Cloneable { + public Object clone(); + + /** + * Return the screen this graphics configuration is valid for + */ + public AbstractGraphicsScreen getScreen(); + + /** + * Return the capabilities reflecting this graphics configuration, + * which may differ from the capabilities used to choose this configuration. + * + * @return An immutable instance of the Capabilities to avoid mutation by + * the user. + */ + public CapabilitiesImmutable getChosenCapabilities(); + + /** + * Return the capabilities used to choose this graphics configuration. + * + * These may be used to reconfigure the NativeWindow in case + * the device changes in a multiple screen environment. + * + * @return An immutable instance of the Capabilities to avoid mutation by + * the user. + */ + public CapabilitiesImmutable getRequestedCapabilities(); + + /** + * In case the implementation utilizes a delegation pattern to wrap abstract toolkits, + * this method shall return the native {@link AbstractGraphicsConfiguration}, + * otherwise this instance. + * @see NativeSurface#getGraphicsConfiguration() + */ + public AbstractGraphicsConfiguration getNativeGraphicsConfiguration(); +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsDevice.java new file mode 100644 index 000000000..7b630b1ea --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsDevice.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +import jogamp.nativewindow.Debug; + +/** A interface describing a graphics device in a + toolkit-independent manner. + */ +public interface AbstractGraphicsDevice extends Cloneable { + public static final boolean DEBUG = Debug.debug("GraphicsDevice"); + + /** Dummy connection value for a default connection where no native support for multiple devices is available */ + public static String DEFAULT_CONNECTION = "decon"; + + /** Dummy connection value for an external connection where no native support for multiple devices is available */ + public static String EXTERNAL_CONNECTION = "excon"; + + /** Default unit id for the 1st device: 0 */ + public static int DEFAULT_UNIT = 0; + + public Object clone(); + + /** + * Returns the type of the underlying subsystem, ie + * NativeWindowFactory.TYPE_KD, NativeWindowFactory.TYPE_X11, .. + */ + public String getType(); + + /** + * Returns the semantic GraphicsDevice connection.<br> + * On platforms supporting remote devices, eg via tcp/ip network, + * the implementation shall return a unique name for each remote address.<br> + * On X11 for example, the connection string should be as the following example.<br> + * <ul> + * <li><code>:0.0</code> for a local connection</li> + * <li><code>remote.host.net:0.0</code> for a remote connection</li> + * </ul> + * + * To support multiple local device, see {@link #getUnitID()}. + */ + public String getConnection(); + + /** + * Returns the graphics device <code>unit ID</code>.<br> + * The <code>unit ID</code> support multiple graphics device configurations + * on a local machine.<br> + * To support remote device, see {@link #getConnection()}. + * @return + */ + public int getUnitID(); + + /** + * Returns a unique ID object of this device using {@link #getType() type}, + * {@link #getConnection() connection} and {@link #getUnitID() unitID} as it's key components. + * <p> + * The unique ID does not reflect the instance of the device, hence the handle is not included. + * The unique ID may be used as a key for semantic device mapping. + * </p> + * <p> + * The returned string object reference is unique using {@link String#intern()} + * and hence can be used as a key itself. + * </p> + */ + public String getUniqueID(); + + /** + * Returns the native handle of the underlying native device, + * if such thing exist. + */ + public long getHandle(); + + /** + * Optionally locking the device, utilizing eg {@link com.jogamp.nativewindow.ToolkitLock#lock()}. + * The lock implementation must be recursive. + */ + public void lock(); + + /** + * Optionally unlocking the device, utilizing eg {@link com.jogamp.nativewindow.ToolkitLock#unlock()}. + * The lock implementation must be recursive. + * + * @throws RuntimeException in case the lock is not acquired by this thread. + */ + public void unlock(); + + /** + * @throws RuntimeException if current thread does not hold the lock + */ + public void validateLocked() throws RuntimeException; + + /** + * Optionally [re]opening the device if handle is <code>null</code>. + * <p> + * The default implementation is a <code>NOP</code>. + * </p> + * <p> + * Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} + * or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice} + * issue the native open operation in case handle is <code>null</code>. + * </p> + * + * @return true if the handle was <code>null</code> and opening was successful, otherwise false. + */ + public boolean open(); + + /** + * Optionally closing the device if handle is not <code>null</code>. + * <p> + * The default implementation {@link ToolkitLock#dispose() dispose} it's {@link ToolkitLock} and sets the handle to <code>null</code>. + * </p> + * <p> + * Example implementations like {@link com.jogamp.nativewindow.x11.X11GraphicsDevice} + * or {@link com.jogamp.nativewindow.egl.EGLGraphicsDevice} + * issue the native close operation or skip it depending on the {@link #isHandleOwner() handles's ownership}. + * </p> + * + * @return true if the handle was not <code>null</code> and closing was successful, otherwise false. + */ + public boolean close(); + + /** + * @return <code>true</code> if instance owns the handle to issue {@link #close()}, otherwise <code>false</code>. + */ + public boolean isHandleOwner(); + + public void clearHandleOwner(); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsScreen.java new file mode 100644 index 000000000..7767cf9e4 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/AbstractGraphicsScreen.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +/** A interface describing a graphics screen in a + toolkit-independent manner. + */ + +public interface AbstractGraphicsScreen extends Cloneable { + public Object clone(); + + /** + * Return the device this graphics configuration is valid for + */ + public AbstractGraphicsDevice getDevice(); + + /** Returns the screen index this graphics screen is valid for + */ + public int getIndex(); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/Capabilities.java b/src/nativewindow/classes/com/jogamp/nativewindow/Capabilities.java new file mode 100644 index 000000000..fa172b201 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/Capabilities.java @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +/** Specifies a set of capabilities that a window's rendering context + must support, such as color depth per channel. It currently + contains the minimal number of routines which allow configuration + on all supported window systems. */ +public class Capabilities implements CapabilitiesImmutable, Cloneable { + protected final static String na_str = "----" ; + + private int redBits = 8; + private int greenBits = 8; + private int blueBits = 8; + private int alphaBits = 0; + + // Support for transparent windows containing OpenGL content + private boolean backgroundOpaque = true; + private int transparentValueRed = 0; + private int transparentValueGreen = 0; + private int transparentValueBlue = 0; + private int transparentValueAlpha = 0; + + // Switch for on- or offscreen + private boolean onscreen = true; + + // offscreen bitmap mode + private boolean isBitmap = false; + + /** Creates a Capabilities object. All attributes are in a default + state. + */ + public Capabilities() {} + + @Override + public Object cloneMutable() { + return clone(); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException e) { + throw new NativeWindowException(e); + } + } + + /** + * Copies all {@link Capabilities} values + * from <code>source</code> into this instance. + * @return this instance + */ + public Capabilities copyFrom(final CapabilitiesImmutable other) { + redBits = other.getRedBits(); + greenBits = other.getGreenBits(); + blueBits = other.getBlueBits(); + alphaBits = other.getAlphaBits(); + backgroundOpaque = other.isBackgroundOpaque(); + onscreen = other.isOnscreen(); + isBitmap = other.isBitmap(); + transparentValueRed = other.getTransparentRedValue(); + transparentValueGreen = other.getTransparentGreenValue(); + transparentValueBlue = other.getTransparentBlueValue(); + transparentValueAlpha = other.getTransparentAlphaValue(); + return this; + } + + @Override + public int hashCode() { + // 31 * x == (x << 5) - x + int hash = 31 + this.redBits; + hash = ((hash << 5) - hash) + ( this.onscreen ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( this.isBitmap ? 1 : 0 ); + hash = ((hash << 5) - hash) + this.greenBits; + hash = ((hash << 5) - hash) + this.blueBits; + hash = ((hash << 5) - hash) + this.alphaBits; + hash = ((hash << 5) - hash) + ( this.backgroundOpaque ? 1 : 0 ); + hash = ((hash << 5) - hash) + this.transparentValueRed; + hash = ((hash << 5) - hash) + this.transparentValueGreen; + hash = ((hash << 5) - hash) + this.transparentValueBlue; + hash = ((hash << 5) - hash) + this.transparentValueAlpha; + return hash; + } + + @Override + public boolean equals(final Object obj) { + if(this == obj) { return true; } + if(!(obj instanceof CapabilitiesImmutable)) { + return false; + } + final CapabilitiesImmutable other = (CapabilitiesImmutable)obj; + boolean res = other.getRedBits()==redBits && + other.getGreenBits()==greenBits && + other.getBlueBits()==blueBits && + other.getAlphaBits()==alphaBits && + other.isBackgroundOpaque()==backgroundOpaque && + other.isOnscreen()==onscreen && + other.isBitmap()==isBitmap; + if(res && !backgroundOpaque) { + res = other.getTransparentRedValue()==transparentValueRed && + other.getTransparentGreenValue()==transparentValueGreen && + other.getTransparentBlueValue()==transparentValueBlue && + other.getTransparentAlphaValue()==transparentValueAlpha; + } + + return res; + } + + /** + * Comparing RGBA values only + **/ + @Override + public int compareTo(final CapabilitiesImmutable caps) { + /** + if ( ! ( o instanceof CapabilitiesImmutable ) ) { + Class<?> c = (null != o) ? o.getClass() : null ; + throw new ClassCastException("Not a CapabilitiesImmutable object, but " + c); + } + final CapabilitiesImmutable caps = (CapabilitiesImmutable) o; */ + + final int rgba = redBits * greenBits * blueBits * ( alphaBits + 1 ); + + final int xrgba = caps.getRedBits() * caps.getGreenBits() * caps.getBlueBits() * ( caps.getAlphaBits() + 1 ); + + if(rgba > xrgba) { + return 1; + } else if(rgba < xrgba) { + return -1; + } + + return 0; // they are equal: RGBA + } + + @Override + public int getVisualID(final VIDType type) throws NativeWindowException { + switch(type) { + case INTRINSIC: + case NATIVE: + return VisualIDHolder.VID_UNDEFINED; + default: + throw new NativeWindowException("Invalid type <"+type+">"); + } + } + + @Override + public final int getRedBits() { + return redBits; + } + + /** Sets the number of bits requested for the color buffer's red + component. On some systems only the color depth, which is the + sum of the red, green, and blue bits, is considered. */ + public void setRedBits(final int redBits) { + this.redBits = redBits; + } + + @Override + public final int getGreenBits() { + return greenBits; + } + + /** Sets the number of bits requested for the color buffer's green + component. On some systems only the color depth, which is the + sum of the red, green, and blue bits, is considered. */ + public void setGreenBits(final int greenBits) { + this.greenBits = greenBits; + } + + @Override + public final int getBlueBits() { + return blueBits; + } + + /** Sets the number of bits requested for the color buffer's blue + component. On some systems only the color depth, which is the + sum of the red, green, and blue bits, is considered. */ + public void setBlueBits(final int blueBits) { + this.blueBits = blueBits; + } + + @Override + public final int getAlphaBits() { + return alphaBits; + } + + /** + * Sets the number of bits requested for the color buffer's alpha + * component. On some systems only the color depth, which is the + * sum of the red, green, and blue bits, is considered. + * <p> + * <b>Note:</b> If alpha bits are <code>zero</code>, they are set to <code>one</code> + * by {@link #setBackgroundOpaque(boolean)} and it's OpenGL specialization <code>GLCapabilities::setSampleBuffers(boolean)</code>.<br/> + * Ensure to call this method after the above to ensure a <code>zero</code> value.</br> + * The above automated settings takes into account, that the user calls this method to <i>request</i> alpha bits, + * not to <i>reflect</i> a current state. Nevertheless if this is the case - call it at last. + * </p> + */ + public void setAlphaBits(final int alphaBits) { + this.alphaBits = alphaBits; + } + + /** + * Sets whether the surface shall be opaque or translucent. + * <p> + * Platform implementations may need an alpha component in the surface (eg. Windows), + * or expect pre-multiplied alpha values (eg. X11/XRender).<br> + * To unify the experience, this method also invokes {@link #setAlphaBits(int) setAlphaBits(1)} + * if {@link #getAlphaBits()} == 0.<br> + * Please note that in case alpha is required on the platform the + * clear color shall have an alpha lower than 1.0 to allow anything shining through. + * </p> + * <p> + * Mind that translucency may cause a performance penalty + * due to the composite work required by the window manager. + * </p> + */ + public void setBackgroundOpaque(final boolean opaque) { + backgroundOpaque = opaque; + if(!opaque && getAlphaBits()==0) { + setAlphaBits(1); + } + } + + @Override + public final boolean isBackgroundOpaque() { + return backgroundOpaque; + } + + /** + * Sets whether the surface shall be on- or offscreen. + * <p> + * Defaults to true. + * </p> + * <p> + * If requesting an offscreen surface without further selection of it's mode, + * e.g. FBO, Pbuffer or {@link #setBitmap(boolean) bitmap}, + * the implementation will choose the best available offscreen mode. + * </p> + * @param onscreen + */ + public void setOnscreen(final boolean onscreen) { + this.onscreen=onscreen; + } + + @Override + public final boolean isOnscreen() { + return onscreen; + } + + /** + * Requesting offscreen bitmap mode. + * <p> + * If enabled this method also invokes {@link #setOnscreen(int) setOnscreen(false)}. + * </p> + * <p> + * Defaults to false. + * </p> + * <p> + * Requesting offscreen bitmap mode disables the offscreen auto selection. + * </p> + */ + public void setBitmap(final boolean enable) { + if(enable) { + setOnscreen(false); + } + isBitmap = enable; + } + + @Override + public boolean isBitmap() { + return isBitmap; + } + + @Override + public final int getTransparentRedValue() { return transparentValueRed; } + + @Override + public final int getTransparentGreenValue() { return transparentValueGreen; } + + @Override + public final int getTransparentBlueValue() { return transparentValueBlue; } + + @Override + public final int getTransparentAlphaValue() { return transparentValueAlpha; } + + /** Sets the transparent red value for the frame buffer configuration, + ranging from 0 to the maximum frame buffer value for red. + This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> + It defaults to half of the frambuffer value for red. <br> + A value of -1 is interpreted as any value. */ + public void setTransparentRedValue(final int transValueRed) { transparentValueRed=transValueRed; } + + /** Sets the transparent green value for the frame buffer configuration, + ranging from 0 to the maximum frame buffer value for green. + This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> + It defaults to half of the frambuffer value for green.<br> + A value of -1 is interpreted as any value. */ + public void setTransparentGreenValue(final int transValueGreen) { transparentValueGreen=transValueGreen; } + + /** Sets the transparent blue value for the frame buffer configuration, + ranging from 0 to the maximum frame buffer value for blue. + This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> + It defaults to half of the frambuffer value for blue.<br> + A value of -1 is interpreted as any value. */ + public void setTransparentBlueValue(final int transValueBlue) { transparentValueBlue=transValueBlue; } + + /** Sets the transparent alpha value for the frame buffer configuration, + ranging from 0 to the maximum frame buffer value for alpha. + This value is ignored if {@link #isBackgroundOpaque()} equals true.<br> + It defaults to half of the frambuffer value for alpha.<br> + A value of -1 is interpreted as any value. */ + public void setTransparentAlphaValue(final int transValueAlpha) { transparentValueAlpha=transValueAlpha; } + + @Override + public StringBuilder toString(final StringBuilder sink) { + return toString(sink, true); + } + + /** Returns a textual representation of this Capabilities + object. */ + @Override + public String toString() { + final StringBuilder msg = new StringBuilder(); + msg.append("Caps["); + toString(msg); + msg.append("]"); + return msg.toString(); + } + + /** Return a textual representation of this object's on/off screen state. Use the given StringBuilder [optional]. */ + protected StringBuilder onoffScreenToString(StringBuilder sink) { + if(null == sink) { + sink = new StringBuilder(); + } + if(onscreen) { + sink.append("on-scr"); + } else { + sink.append("offscr["); + } + if(isBitmap) { + sink.append("bitmap"); + } else if(onscreen) { + sink.append("."); // no additional off-screen modes besides on-screen + } else { + sink.append("auto-cfg"); // auto-config off-screen mode + } + sink.append("]"); + + return sink; + } + + /** Element separator */ + protected static final String ESEP = "/"; + /** Component separator */ + protected static final String CSEP = ", "; + + protected StringBuilder toString(StringBuilder sink, final boolean withOnOffScreen) { + if(null == sink) { + sink = new StringBuilder(); + } + sink.append("rgba ").append(redBits).append(ESEP).append(greenBits).append(ESEP).append(blueBits).append(ESEP).append(alphaBits); + if(backgroundOpaque) { + sink.append(", opaque"); + } else { + sink.append(", trans-rgba 0x").append(toHexString(transparentValueRed)).append(ESEP).append(toHexString(transparentValueGreen)).append(ESEP).append(toHexString(transparentValueBlue)).append(ESEP).append(toHexString(transparentValueAlpha)); + } + if(withOnOffScreen) { + sink.append(CSEP); + onoffScreenToString(sink); + } + return sink; + } + + protected final String toHexString(final int val) { return Integer.toHexString(val); } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/CapabilitiesChooser.java b/src/nativewindow/classes/com/jogamp/nativewindow/CapabilitiesChooser.java new file mode 100644 index 000000000..c33ff5a3f --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/CapabilitiesChooser.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +import java.util.List; + +/** Provides a mechanism by which applications can customize the + window type selection for a given {@link Capabilities}. + Developers can implement this interface and pass an instance into + the method {@link GraphicsConfigurationFactory#chooseGraphicsConfiguration}; the chooser + will be called at window creation time. */ + +public interface CapabilitiesChooser { + /** Chooses the index (0..available.length - 1) of the {@link + Capabilities} most closely matching the desired one from the + list of all supported. Some of the entries in the + <code>available</code> array may be null; the chooser must + ignore these. The <em>windowSystemRecommendedChoice</em> + parameter may be provided to the chooser by the underlying + window system; if this index is valid, it is recommended, but + not necessarily required, that the chooser select that entry. + + <P> <em>Note:</em> this method is called automatically by the + {@link GraphicsConfigurationFactory#chooseGraphicsConfiguration} method + when an instance of this class is passed in to it. + It should generally not be + invoked by users directly, unless it is desired to delegate the + choice to some other CapabilitiesChooser object. + */ + public int chooseCapabilities(CapabilitiesImmutable desired, + List<? extends CapabilitiesImmutable> available, + int windowSystemRecommendedChoice); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/CapabilitiesImmutable.java b/src/nativewindow/classes/com/jogamp/nativewindow/CapabilitiesImmutable.java new file mode 100644 index 000000000..780d537b8 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/CapabilitiesImmutable.java @@ -0,0 +1,139 @@ +/** + * 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.nativewindow; + +import com.jogamp.common.type.WriteCloneable; + +/** + * Specifies an immutable set of capabilities that a window's rendering context + * must support, such as color depth per channel. + * + * @see com.jogamp.nativewindow.Capabilities + */ +public interface CapabilitiesImmutable extends VisualIDHolder, WriteCloneable, Comparable<CapabilitiesImmutable> { + + /** + * Returns the number of bits for the color buffer's red + * component. On some systems only the color depth, which is the sum of the + * red, green, and blue bits, is considered. + */ + int getRedBits(); + + /** + * Returns the number of bits for the color buffer's green + * component. On some systems only the color depth, which is the sum of the + * red, green, and blue bits, is considered. + */ + int getGreenBits(); + + /** + * Returns the number of bits for the color buffer's blue + * component. On some systems only the color depth, which is the sum of the + * red, green, and blue bits, is considered. + */ + int getBlueBits(); + + /** + * Returns the number of bits for the color buffer's alpha + * component. On some systems only the color depth, which is the sum of the + * red, green, and blue bits, is considered. + */ + int getAlphaBits(); + + /** + * Returns whether an opaque or translucent surface is requested, supported or chosen. + * <p> + * Default is true, i.e. opaque. + * </p> + */ + boolean isBackgroundOpaque(); + + /** + * Returns whether an on- or offscreen surface is requested, available or chosen. + * <p> + * Default is true, i.e. onscreen. + * </p> + * <p> + * Mind that an capabilities intance w/ <i>available</i> semantics + * may show onscreen, but also the offscreen modes FBO, Pbuffer or {@link #setBitmap(boolean) bitmap}. + * This is valid, since one native configuration maybe used for either functionality. + * </p> + */ + boolean isOnscreen(); + + /** + * Returns whether bitmap offscreen mode is requested, available or chosen. + * <p> + * Default is false. + * </p> + * <p> + * For chosen capabilities, only the selected offscreen surface is set to <code>true</code>. + * </p> + */ + boolean isBitmap(); + + /** + * Gets the transparent red value for the frame buffer configuration. This + * value is undefined if; equals true. + */ + int getTransparentRedValue(); + + /** + * Gets the transparent green value for the frame buffer configuration. This + * value is undefined if; equals true. + */ + int getTransparentGreenValue(); + + /** + * Gets the transparent blue value for the frame buffer configuration. This + * value is undefined if; equals true. + */ + int getTransparentBlueValue(); + + /** + * Gets the transparent alpha value for the frame buffer configuration. This + * value is undefined if; equals true. + */ + int getTransparentAlphaValue(); + + /** Equality over the immutable attributes of both objects */ + @Override + boolean equals(Object obj); + + /** hash code over the immutable attributes of both objects */ + @Override + int hashCode(); + + /** Return a textual representation of this object. Use the given StringBuilder [optional]. */ + StringBuilder toString(StringBuilder sink); + + /** Returns a textual representation of this object. */ + @Override + String toString(); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultCapabilitiesChooser.java b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultCapabilitiesChooser.java new file mode 100644 index 000000000..33c3f8458 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultCapabilitiesChooser.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +import java.util.List; + +import com.jogamp.common.util.PropertyAccess; + +import jogamp.nativewindow.Debug; + +/** <P> The default implementation of the {@link + CapabilitiesChooser} interface, which provides consistent visual + selection behavior across platforms. The precise algorithm is + deliberately left loosely specified. Some properties are: </P> + + <LI> Attempts to match as closely as possible the given + Capabilities, but will select one with fewer capabilities (i.e., + lower color depth) if necessary. + + <LI> If there is no exact match, prefers a more-capable visual to + a less-capable one. + + <LI> If there is more than one exact match, chooses an arbitrary + one. + + <LI> If a valid windowSystemRecommendedChoice parameter is + supplied, chooses that instead of using the cross-platform code. + + </UL> +*/ + +public class DefaultCapabilitiesChooser implements CapabilitiesChooser { + private static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = PropertyAccess.isPropertyDefined("nativewindow.debug.CapabilitiesChooser", true); + } + + private final static int NO_SCORE = -9999999; + private final static int COLOR_MISMATCH_PENALTY_SCALE = 36; + + @Override + public int chooseCapabilities(final CapabilitiesImmutable desired, + final List<? extends CapabilitiesImmutable> available, + final int windowSystemRecommendedChoice) { + if (DEBUG) { + System.err.println("Desired: " + desired); + for (int i = 0; i < available.size(); i++) { + System.err.println("Available " + i + ": " + available.get(i)); + } + System.err.println("Window system's recommended choice: " + windowSystemRecommendedChoice); + } + final int availnum = available.size(); + + if (windowSystemRecommendedChoice >= 0 && + windowSystemRecommendedChoice < availnum && + null != available.get(windowSystemRecommendedChoice)) { + if (DEBUG) { + System.err.println("Choosing window system's recommended choice of " + windowSystemRecommendedChoice); + System.err.println(available.get(windowSystemRecommendedChoice)); + } + return windowSystemRecommendedChoice; + } + + // Create score array + final int[] scores = new int[availnum]; + for (int i = 0; i < availnum; i++) { + scores[i] = NO_SCORE; + } + // Compute score for each + for (int i = 0; i < availnum; i++) { + final CapabilitiesImmutable cur = available.get(i); + if (cur == null) { + continue; + } + if (desired.isOnscreen() && !cur.isOnscreen()) { + continue; // requested onscreen, but n/a + } + + int score = 0; + // Compute difference in color depth + score += (COLOR_MISMATCH_PENALTY_SCALE * + ((cur.getRedBits() + cur.getGreenBits() + cur.getBlueBits() + cur.getAlphaBits()) - + (desired.getRedBits() + desired.getGreenBits() + desired.getBlueBits() + desired.getAlphaBits()))); + scores[i] = score; + } + + if (DEBUG) { + System.err.print("Scores: ["); + for (int i = 0; i < availnum; i++) { + if (i > 0) { + System.err.print(","); + } + System.err.print(" " + scores[i]); + } + System.err.println(" ]"); + } + + // Ready to select. Choose score closest to 0. + int scoreClosestToZero = NO_SCORE; + int chosenIndex = -1; + for (int i = 0; i < availnum; i++) { + final int score = scores[i]; + if (score == NO_SCORE) { + continue; + } + // Don't substitute a positive score for a smaller negative score + if ((scoreClosestToZero == NO_SCORE) || + (Math.abs(score) < Math.abs(scoreClosestToZero) && + ((sign(scoreClosestToZero) < 0) || (sign(score) > 0)))) { + scoreClosestToZero = score; + chosenIndex = i; + } + } + if (chosenIndex < 0) { + throw new NativeWindowException("Unable to select one of the provided Capabilities"); + } + if (DEBUG) { + System.err.println("Chosen index: " + chosenIndex); + System.err.println("Chosen capabilities:"); + System.err.println(available.get(chosenIndex)); + } + + return chosenIndex; + } + + private static int sign(final int score) { + if (score < 0) { + return -1; + } + return 1; + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsConfiguration.java b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsConfiguration.java new file mode 100644 index 000000000..d20a6824d --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsConfiguration.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.nativewindow; + +import jogamp.nativewindow.Debug; + +public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphicsConfiguration { + protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); + + private AbstractGraphicsScreen screen; + protected CapabilitiesImmutable capabilitiesChosen; + protected CapabilitiesImmutable capabilitiesRequested; + + public DefaultGraphicsConfiguration(final AbstractGraphicsScreen screen, + final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested) { + if(null == screen) { + throw new IllegalArgumentException("Null screen"); + } + if(null == capsChosen) { + throw new IllegalArgumentException("Null chosen caps"); + } + if(null == capsRequested) { + throw new IllegalArgumentException("Null requested caps"); + } + this.screen = screen; + this.capabilitiesChosen = capsChosen; + this.capabilitiesRequested = capsRequested; + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException e) { + throw new NativeWindowException(e); + } + } + + @Override + final public AbstractGraphicsScreen getScreen() { + return screen; + } + + @Override + final public CapabilitiesImmutable getChosenCapabilities() { + return capabilitiesChosen; + } + + @Override + final public CapabilitiesImmutable getRequestedCapabilities() { + return capabilitiesRequested; + } + + @Override + public AbstractGraphicsConfiguration getNativeGraphicsConfiguration() { + return this; + } + + @Override + final public int getVisualID(final VIDType type) throws NativeWindowException { + return capabilitiesChosen.getVisualID(type); + } + + /** + * Set the capabilities to a new value. + * + * <p> + * The use case for setting the Capabilities at a later time is + * a change or re-validation of capabilities. + * </p> + * @see com.jogamp.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) + */ + protected void setChosenCapabilities(final CapabilitiesImmutable capsChosen) { + this.capabilitiesChosen = capsChosen; + } + + /** + * Set a new screen. + * + * <p> + * the use case for setting a new screen at a later time is + * a change of the graphics device in a multi-screen environment. + * </p> + */ + protected void setScreen(final AbstractGraphicsScreen screen) { + this.screen = screen; + } + + @Override + public String toString() { + return getClass().getSimpleName()+"[" + screen + + ",\n\tchosen " + capabilitiesChosen+ + ",\n\trequested " + capabilitiesRequested+ + "]"; + } + + public static String toHexString(final int val) { + return "0x"+Integer.toHexString(val); + } + + public static String toHexString(final long val) { + return "0x"+Long.toHexString(val); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsDevice.java new file mode 100644 index 000000000..070b6bb28 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsDevice.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.nativewindow; + +import jogamp.nativewindow.NativeWindowFactoryImpl; + +public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice { + private static final String separator = "_"; + private final String type; + protected final String connection; + protected final int unitID; + protected final String uniqueID; + protected long handle; + protected ToolkitLock toolkitLock; + + /** + * Create an instance with the system default {@link ToolkitLock}, + * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String)}. + * @param type + */ + public DefaultGraphicsDevice(final String type, final String connection, final int unitID) { + this(type, connection, unitID, 0, NativeWindowFactory.getDefaultToolkitLock(type)); + } + + /** + * Create an instance with the system default {@link ToolkitLock}. + * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. + * @param type + * @param handle + */ + public DefaultGraphicsDevice(final String type, final String connection, final int unitID, final long handle) { + this(type, connection, unitID, handle, NativeWindowFactory.getDefaultToolkitLock(type, handle)); + } + + /** + * Create an instance with the given {@link ToolkitLock} instance, or <i>null</i> {@link ToolkitLock} if null. + * @param type + * @param handle + * @param locker if null, a non blocking <i>null</i> lock is used. + */ + public DefaultGraphicsDevice(final String type, final String connection, final int unitID, final long handle, final ToolkitLock locker) { + this.type = type; + this.connection = connection; + this.unitID = unitID; + this.uniqueID = getUniqueID(type, connection, unitID); + this.handle = handle; + this.toolkitLock = null != locker ? locker : NativeWindowFactoryImpl.getNullToolkitLock(); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException e) { + throw new NativeWindowException(e); + } + } + + @Override + public final String getType() { + return type; + } + + @Override + public final String getConnection() { + return connection; + } + + @Override + public final int getUnitID() { + return unitID; + } + + @Override + public final String getUniqueID() { + return uniqueID; + } + + @Override + public final long getHandle() { + return handle; + } + + /** + * {@inheritDoc} + * <p> + * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}. + * </p> + * + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, com.jogamp.nativewindow.ToolkitLock) + */ + @Override + public final void lock() { + toolkitLock.lock(); + } + + @Override + public final void validateLocked() throws RuntimeException { + toolkitLock.validateLocked(); + } + + /** + * {@inheritDoc} + * <p> + * Locking is perfomed via delegation to {@link ToolkitLock#lock()}, {@link ToolkitLock#unlock()}. + * </p> + * + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, com.jogamp.nativewindow.ToolkitLock) + */ + @Override + public final void unlock() { + toolkitLock.unlock(); + } + + @Override + public boolean open() { + return false; + } + + @Override + public boolean close() { + toolkitLock.dispose(); + if(0 != handle) { + handle = 0; + return true; + } + return false; + } + + @Override + public boolean isHandleOwner() { + return false; + } + + @Override + public void clearHandleOwner() { + } + + @Override + public String toString() { + return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", owner "+isHandleOwner()+", "+toolkitLock+"]"; + } + + /** + * Set the native handle of the underlying native device + * and return the previous one. + */ + protected final long setHandle(final long newHandle) { + final long oldHandle = handle; + handle = newHandle; + return oldHandle; + } + + protected Object getHandleOwnership() { + return null; + } + protected Object setHandleOwnership(final Object newOwnership) { + return null; + } + + public static final void swapDeviceHandleAndOwnership(final DefaultGraphicsDevice aDevice1, final DefaultGraphicsDevice aDevice2) { + aDevice1.lock(); + try { + aDevice2.lock(); + try { + final long aDevice1Handle = aDevice1.getHandle(); + final long aDevice2Handle = aDevice2.setHandle(aDevice1Handle); + aDevice1.setHandle(aDevice2Handle); + final Object aOwnership1 = aDevice1.getHandleOwnership(); + final Object aOwnership2 = aDevice2.setHandleOwnership(aOwnership1); + aDevice1.setHandleOwnership(aOwnership2); + } finally { + aDevice2.unlock(); + } + } finally { + aDevice1.unlock(); + } + } + + /** + * Set the internal ToolkitLock, which is used within the + * {@link #lock()} and {@link #unlock()} implementation. + * + * <p> + * The current ToolkitLock is being locked/unlocked while swapping the reference, + * ensuring no concurrent access can occur during the swap. + * </p> + * + * @param locker the ToolkitLock, if null, {@link jogamp.nativewindow.NullToolkitLock} is being used + * @return the previous ToolkitLock instance + */ + protected ToolkitLock setToolkitLock(final ToolkitLock locker) { + final ToolkitLock _toolkitLock = toolkitLock; + _toolkitLock.lock(); + try { + toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; + } finally { + _toolkitLock.unlock(); + } + return _toolkitLock; + } + + /** + * @return the used ToolkitLock + * + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long) + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(java.lang.String, long, com.jogamp.nativewindow.ToolkitLock) + */ + public final ToolkitLock getToolkitLock() { + return toolkitLock; + } + + /** + * Returns a unique String object using {@link String#intern()} for the given arguments, + * which object reference itself can be used as a key. + */ + private static String getUniqueID(final String type, final String connection, final int unitID) { + return (type + separator + connection + separator + unitID).intern(); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsScreen.java b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsScreen.java new file mode 100644 index 000000000..63c79af55 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DefaultGraphicsScreen.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.nativewindow; + +public class DefaultGraphicsScreen implements Cloneable, AbstractGraphicsScreen { + private final AbstractGraphicsDevice device; + private final int idx; + + public DefaultGraphicsScreen(final AbstractGraphicsDevice device, final int idx) { + this.device = device; + this.idx = idx; + } + + public static AbstractGraphicsScreen createDefault(final String type) { + return new DefaultGraphicsScreen(new DefaultGraphicsDevice(type, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT), 0); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException e) { + throw new NativeWindowException(e); + } + } + + @Override + public AbstractGraphicsDevice getDevice() { + return device; + } + + @Override + public int getIndex() { + return idx; + } + + @Override + public String toString() { + return getClass().getSimpleName()+"["+device+", idx "+idx+"]"; + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java new file mode 100644 index 000000000..929af054e --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/GraphicsConfigurationFactory.java @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.nativewindow; + +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.util.ReflectionUtil; + +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.DefaultGraphicsConfigurationFactoryImpl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Provides the mechanism by which the graphics configuration for a + * window can be chosen before the window is created. The graphics + * configuration decides parameters related to hardware accelerated rendering such + * as the OpenGL pixel format. <br> + * On some window systems (EGL/OpenKODE and X11 in particular) it is necessary to + * choose the graphics configuration early at window creation time. <br> + * Note that the selection of the graphics configuration is an algorithm which does not have + * strong dependencies on the particular Java window toolkit in use + * (e.g., AWT) and therefore it is strongly desirable to factor this + * functionality out of the core {@link NativeWindowFactory} so that + * new window toolkits can replace just the {@link + * NativeWindowFactory} and reuse the graphics configuration selection + * algorithm provided by, for example, an OpenGL binding. + */ + +public abstract class GraphicsConfigurationFactory { + protected static final boolean DEBUG; + + private static class DeviceCapsType { + public final Class<?> deviceType; + public final Class<?> capsType; + private final int hash32; + + public DeviceCapsType(final Class<?> deviceType, final Class<?> capsType) { + this.deviceType = deviceType; + this.capsType = capsType; + + // 31 * x == (x << 5) - x + int hash32 = 31 + deviceType.hashCode(); + hash32 = ((hash32 << 5) - hash32) + capsType.hashCode(); + this.hash32 = hash32; + } + + @Override + public final int hashCode() { + return hash32; + } + + @Override + public final boolean equals(final Object obj) { + if(this == obj) { return true; } + if (obj instanceof DeviceCapsType) { + final DeviceCapsType dct = (DeviceCapsType)obj; + return deviceType == dct.deviceType && capsType == dct.capsType; + } + return false; + } + + @Override + public final String toString() { + return "DeviceCapsType["+deviceType.getName()+", "+capsType.getName()+"]"; + } + + } + + private static final Map<DeviceCapsType, GraphicsConfigurationFactory> registeredFactories; + private static final DeviceCapsType defaultDeviceCapsType; + static boolean initialized = false; + + static { + DEBUG = Debug.debug("GraphicsConfiguration"); + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - Info: GraphicsConfigurationFactory.<init>"); + // Thread.dumpStack(); + } + registeredFactories = Collections.synchronizedMap(new HashMap<DeviceCapsType, GraphicsConfigurationFactory>()); + defaultDeviceCapsType = new DeviceCapsType(AbstractGraphicsDevice.class, CapabilitiesImmutable.class); + } + + public static synchronized void initSingleton() { + if(!initialized) { + initialized = true; + + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - GraphicsConfigurationFactory.initSingleton()"); + } + + // Register the default no-op factory for arbitrary + // AbstractGraphicsDevice implementations, including + // AWTGraphicsDevice instances -- the OpenGL binding will take + // care of handling AWTGraphicsDevices on X11 platforms (as + // well as X11GraphicsDevices in non-AWT situations) + registerFactory(defaultDeviceCapsType.deviceType, defaultDeviceCapsType.capsType, new DefaultGraphicsConfigurationFactoryImpl()); + + if (NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true)) { + try { + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (final Exception e) { + throw new RuntimeException(e); + } + if(NativeWindowFactory.isAWTAvailable()) { + try { + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.awt.X11AWTGraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (final Exception e) { /* n/a */ } + } + } + } + } + + public static synchronized void shutdown() { + if(initialized) { + initialized = false; + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - GraphicsConfigurationFactory.shutdown()"); + } + registeredFactories.clear(); + } + } + + protected static String getThreadName() { + return Thread.currentThread().getName(); + } + + protected static String toHexString(final int val) { + return "0x" + Integer.toHexString(val); + } + + protected static String toHexString(final long val) { + return "0x" + Long.toHexString(val); + } + + /** Creates a new NativeWindowFactory instance. End users do not + need to call this method. */ + protected GraphicsConfigurationFactory() { + } + + /** + * Returns the graphics configuration factory for use with the + * given device and capability. + * + * @see #getFactory(Class, Class) + */ + public static GraphicsConfigurationFactory getFactory(final AbstractGraphicsDevice device, final CapabilitiesImmutable caps) { + if (device == null) { + throw new IllegalArgumentException("null device"); + } + if (caps == null) { + throw new IllegalArgumentException("null caps"); + } + return getFactory(device.getClass(), caps.getClass()); + } + + /** + * Returns the graphics configuration factory for use with the + * given device and capability class. + * <p> + * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only. + * </p> + * + * <p> + * Pseudo code for finding a suitable factory is: + * <pre> + For-All devT := getTopDownDeviceTypes(deviceType) + For-All capsT := getTopDownCapabilitiesTypes(capabilitiesType) + f = factory.get(devT, capsT); + if(f) { return f; } + end + end + * </pre> + * </p> + * + * @param deviceType the minimum capabilities class type accepted, must implement or extend {@link AbstractGraphicsDevice} + * @param capabilitiesType the minimum capabilities class type accepted, must implement or extend {@link CapabilitiesImmutable} + * + * @throws IllegalArgumentException if the deviceType does not implement {@link AbstractGraphicsDevice} or + * capabilitiesType does not implement {@link CapabilitiesImmutable} + */ + public static GraphicsConfigurationFactory getFactory(final Class<?> deviceType, final Class<?> capabilitiesType) + throws IllegalArgumentException, NativeWindowException + { + if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(deviceType))) { + throw new IllegalArgumentException("Given class must implement AbstractGraphicsDevice"); + } + if (!(defaultDeviceCapsType.capsType.isAssignableFrom(capabilitiesType))) { + throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable"); + } + if(DEBUG) { + ExceptionUtils.dumpStack(System.err); + System.err.println("GraphicsConfigurationFactory.getFactory: "+deviceType.getName()+", "+capabilitiesType.getName()); + dumpFactories(); + } + + final List<Class<?>> deviceTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.deviceType, deviceType, false); + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.getFactory() deviceTypes: " + deviceTypes); + } + final List<Class<?>> capabilitiesTypes = getAllAssignableClassesFrom(defaultDeviceCapsType.capsType, capabilitiesType, true); + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.getFactory() capabilitiesTypes: " + capabilitiesTypes); + } + for(int j=0; j<deviceTypes.size(); j++) { + final Class<?> interfaceDevice = deviceTypes.get(j); + for(int i=0; i<capabilitiesTypes.size(); i++) { + final Class<?> interfaceCaps = capabilitiesTypes.get(i); + final DeviceCapsType dct = new DeviceCapsType(interfaceDevice, interfaceCaps); + final GraphicsConfigurationFactory factory = registeredFactories.get(dct); + if (factory != null) { + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.getFactory() found "+dct+" -> "+factory); + } + return factory; + } + } + } + // Return the default + final GraphicsConfigurationFactory factory = registeredFactories.get(defaultDeviceCapsType); + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.getFactory() DEFAULT "+defaultDeviceCapsType+" -> "+factory); + } + return factory; + } + private static ArrayList<Class<?>> getAllAssignableClassesFrom(final Class<?> superClassOrInterface, final Class<?> fromClass, final boolean interfacesOnly) { + // Using a todo list avoiding a recursive loop! + final ArrayList<Class<?>> inspectClasses = new ArrayList<Class<?>>(); + final ArrayList<Class<?>> resolvedInterfaces = new ArrayList<Class<?>>(); + inspectClasses.add(fromClass); + for(int j=0; j<inspectClasses.size(); j++) { + final Class<?> clazz = inspectClasses.get(j); + getAllAssignableClassesFrom(superClassOrInterface, clazz, interfacesOnly, resolvedInterfaces, inspectClasses); + } + return resolvedInterfaces; + } + private static void getAllAssignableClassesFrom(final Class<?> superClassOrInterface, final Class<?> fromClass, final boolean interfacesOnly, final List<Class<?>> resolvedInterfaces, final List<Class<?>> inspectClasses) { + final ArrayList<Class<?>> types = new ArrayList<Class<?>>(); + if( superClassOrInterface.isAssignableFrom(fromClass) && !resolvedInterfaces.contains(fromClass)) { + if( !interfacesOnly || fromClass.isInterface() ) { + types.add(fromClass); + } + } + types.addAll(Arrays.asList(fromClass.getInterfaces())); + + for(int i=0; i<types.size(); i++) { + final Class<?> iface = types.get(i); + if( superClassOrInterface.isAssignableFrom(iface) && !resolvedInterfaces.contains(iface) ) { + resolvedInterfaces.add(iface); + if( !superClassOrInterface.equals(iface) && !inspectClasses.contains(iface) ) { + inspectClasses.add(iface); // safe add to todo list, avoiding a recursive nature + } + } + } + final Class<?> parentClass = fromClass.getSuperclass(); + if( null != parentClass && superClassOrInterface.isAssignableFrom(parentClass) && !inspectClasses.contains(parentClass) ) { + inspectClasses.add(parentClass); // safe add to todo list, avoiding a recursive nature + } + } + private static void dumpFactories() { + final Set<DeviceCapsType> dcts = registeredFactories.keySet(); + int i=0; + for(final Iterator<DeviceCapsType> iter = dcts.iterator(); iter.hasNext(); ) { + final DeviceCapsType dct = iter.next(); + System.err.println("Factory #"+i+": "+dct+" -> "+registeredFactories.get(dct)); + i++; + } + } + + /** + * Registers a GraphicsConfigurationFactory handling + * the given graphics device and capability class. + * <p> + * This does not need to be called by end users, only implementors of new + * GraphicsConfigurationFactory subclasses. + * </p> + * + * <p> + * Note: Registered device types maybe classes or interfaces, where capabilities types are interfaces only. + * </p> + * + * <p>See {@link #getFactory(Class, Class)} for a description of the find algorithm.</p> + * + * @param deviceType the minimum capabilities class type accepted, must implement or extend interface {@link AbstractGraphicsDevice} + * @param capabilitiesType the minimum capabilities class type accepted, must extend interface {@link CapabilitiesImmutable} + * @return the previous registered factory, or null if none + * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice + */ + protected static GraphicsConfigurationFactory registerFactory(final Class<?> abstractGraphicsDeviceImplementor, final Class<?> capabilitiesType, final GraphicsConfigurationFactory factory) + throws IllegalArgumentException + { + if (!(defaultDeviceCapsType.deviceType.isAssignableFrom(abstractGraphicsDeviceImplementor))) { + throw new IllegalArgumentException("Given device class must implement AbstractGraphicsDevice"); + } + if (!(defaultDeviceCapsType.capsType.isAssignableFrom(capabilitiesType))) { + throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable"); + } + final DeviceCapsType dct = new DeviceCapsType(abstractGraphicsDeviceImplementor, capabilitiesType); + final GraphicsConfigurationFactory prevFactory; + if(null == factory) { + prevFactory = registeredFactories.remove(dct); + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.registerFactory() remove "+dct+ + ", deleting: "+prevFactory); + } + } else { + prevFactory = registeredFactories.put(dct, factory); + if(DEBUG) { + System.err.println("GraphicsConfigurationFactory.registerFactory() put "+dct+" -> "+factory+ + ", overridding: "+prevFactory); + } + } + return prevFactory; + } + + /** + * <P> Selects a graphics configuration on the specified graphics + * device compatible with the supplied {@link Capabilities}. Some + * platforms (e.g.: X11, EGL, KD) require the graphics configuration + * to be specified when the native window is created. + * These architectures have seperated their device, screen, window and drawable + * context and hence are capable of quering the capabilities for each screen. + * A fully established window is not required.</P> + * + * <P>Other platforms (e.g. Windows, MacOSX) don't offer the mentioned seperation + * and hence need a fully established window and it's drawable. + * Here the validation of the capabilities is performed later. + * In this case, the AbstractGraphicsConfiguration implementation + * must allow an overwrite of the Capabilites, for example + * {@link DefaultGraphicsConfiguration#setChosenCapabilities DefaultGraphicsConfiguration.setChosenCapabilities(..)}. + * </P> + * + * <P> + * This method is mainly intended to be both used and implemented by the + * OpenGL binding.</P> + * + * <P> The concrete data type of the passed graphics device and + * returned graphics configuration must be specified in the + * documentation binding this particular API to the underlying + * window toolkit. The Reference Implementation accepts {@link + * com.jogamp.nativewindow.awt.AWTGraphicsDevice AWTGraphicsDevice} objects and returns {@link + * com.jogamp.nativewindow.awt.AWTGraphicsConfiguration AWTGraphicsConfiguration} objects. On + * X11 platforms where the AWT is not in use, it also accepts + * {@link com.jogamp.nativewindow.x11.X11GraphicsDevice + * X11GraphicsDevice} objects and returns {@link + * com.jogamp.nativewindow.x11.X11GraphicsConfiguration + * X11GraphicsConfiguration} objects.</P> + * + * @param capsChosen the intermediate chosen capabilities to be refined by this implementation, may be equal to capsRequested + * @param capsRequested the original requested capabilities + * @param chooser the choosing implementation + * @param screen the referring Screen + * @param nativeVisualID if not {@link VisualIDHolder#VID_UNDEFINED} it reflects a pre-chosen visualID of the native platform's windowing system. + * @return the complete GraphicsConfiguration + * + * @throws IllegalArgumentException if the data type of the passed + * AbstractGraphicsDevice is not supported by this + * NativeWindowFactory. + * @throws NativeWindowException if any window system-specific errors caused + * the selection of the graphics configuration to fail. + * + * @see com.jogamp.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) + * @see com.jogamp.nativewindow.DefaultGraphicsConfiguration#setChosenCapabilities(Capabilities caps) + */ + public final AbstractGraphicsConfiguration + chooseGraphicsConfiguration(final CapabilitiesImmutable capsChosen, final CapabilitiesImmutable capsRequested, + final CapabilitiesChooser chooser, + final AbstractGraphicsScreen screen, final int nativeVisualID) + throws IllegalArgumentException, NativeWindowException { + if(null==capsChosen) { + throw new NativeWindowException("Chosen Capabilities are null"); + } + if(null==capsRequested) { + throw new NativeWindowException("Requested Capabilities are null"); + } + if(null==screen) { + throw new NativeWindowException("Screen is null"); + } + final AbstractGraphicsDevice device = screen.getDevice(); + if(null==device) { + throw new NativeWindowException("Screen's Device is null"); + } + device.lock(); + try { + return chooseGraphicsConfigurationImpl(capsChosen, capsRequested, chooser, screen, nativeVisualID); + } finally { + device.unlock(); + } + } + + protected abstract AbstractGraphicsConfiguration + chooseGraphicsConfigurationImpl(CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + CapabilitiesChooser chooser, AbstractGraphicsScreen screen, int nativeVisualID) + throws IllegalArgumentException, NativeWindowException; + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/MutableSurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/MutableSurface.java new file mode 100644 index 000000000..7686f270b --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/MutableSurface.java @@ -0,0 +1,44 @@ +/** + * 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.nativewindow; + +/** + * Provides a {@link NativeSurface} with a mutable <code>surfaceHandle</code> + * via {@link #setSurfaceHandle(long)}. + * + * @see NativeSurface + */ +public interface MutableSurface extends NativeSurface { + + /** + * Sets the surface handle which is created outside of this implementation. + */ + public void setSurfaceHandle(long surfaceHandle); +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeSurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeSurface.java new file mode 100644 index 000000000..ce0699c56 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeSurface.java @@ -0,0 +1,238 @@ +/** + * 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.nativewindow; + +/** + * Provides low-level information required for + * hardware-accelerated rendering using a surface in a platform-independent manner. + * <p> + * All values of this interface are represented in pixel units, if not stated otherwise. + * See {@link NativeWindow}. + * </p> + * <p> + * A NativeSurface created for a particular on- or offscreen component is + * expected to have the same lifetime as that component. As long as + * the component is alive and realized/visible, NativeSurface must be able + * provide information such as the surface handle while it is locked. + * </p> + */ +public interface NativeSurface extends SurfaceUpdatedListener { + /** Unlocked state, {@value}. */ + public static final int LOCK_SURFACE_UNLOCKED = 0; + + /** Returned by {@link #lockSurface()} if the surface is not ready to be locked, {@value}. */ + public static final int LOCK_SURFACE_NOT_READY = 1; + + /** Returned by {@link #lockSurface()} if the surface is locked, but has changed, {@value}. */ + public static final int LOCK_SURFACE_CHANGED = 2; + + /** Returned by {@link #lockSurface()} if the surface is locked, and is unchanged, {@value}. */ + public static final int LOCK_SUCCESS = 3; + + /** + * Lock the surface of this native window. + * <p> + * The surface handle shall be valid after a successfull call, + * ie return a value other than {@link #LOCK_SURFACE_UNLOCKED} and {@link #LOCK_SURFACE_NOT_READY}, + * which is + * <pre> + * boolean ok = LOCK_SURFACE_NOT_READY < lockSurface(); + * </pre> + * </p> + * <p> + * The caller may need to take care of the result {@link #LOCK_SURFACE_CHANGED}, + * where the surface handle is valid but has changed. + * </p> + * <p> + * This call is blocking until the surface has been locked + * or a timeout is reached. The latter will throw a runtime exception. + * </p> + * <p> + * This call allows recursion from the same thread. + * </p> + * <p> + * The implementation may want to aquire the + * application level {@link com.jogamp.common.util.locks.RecursiveLock} + * first before proceeding with a native surface lock. + * </p> + * <p> + * The implementation shall also invoke {@link AbstractGraphicsDevice#lock()} + * for the initial lock (recursive count zero). + * </p> + * + * @return {@link #LOCK_SUCCESS}, {@link #LOCK_SURFACE_CHANGED} or {@link #LOCK_SURFACE_NOT_READY}. + * + * @throws RuntimeException after timeout when waiting for the surface lock + * @throws NativeWindowException if native locking failed, maybe platform related + * + * @see com.jogamp.common.util.locks.RecursiveLock + */ + public int lockSurface() throws NativeWindowException, RuntimeException; + + /** + * Unlock the surface of this native window + * + * Shall not modify the surface handle, see {@link #lockSurface()} <P> + * + * The implementation shall also invoke {@link AbstractGraphicsDevice#unlock()} + * for the final unlock (recursive count zero).<P> + * + * The implementation shall be fail safe, i.e. tolerant in case the native resources + * are already released / unlocked. In this case the implementation shall simply ignore the call. + * + * @see #lockSurface + * @see com.jogamp.common.util.locks.RecursiveLock + */ + public void unlockSurface(); + + /** + * Query if surface is locked by another thread, i.e. not the current one. + * <br> + * Convenient shortcut for: + * <pre> + * final Thread o = getSurfaceLockOwner(); + * if( null != o && Thread.currentThread() != o ) { .. } + * </pre> + */ + public boolean isSurfaceLockedByOtherThread(); + + /** + * Return the locking owner's Thread, or null if not locked. + */ + public Thread getSurfaceLockOwner(); + + /** + * Provide a mechanism to utilize custom (pre-) swap surface + * code. This method is called before the render toolkit (e.g. JOGL) + * swaps the buffer/surface if double buffering is enabled. + * <p> + * The implementation may itself apply the swapping, + * in which case true shall be returned. + * </p> + * + * @return true if this method completed swapping the surface, + * otherwise false, in which case eg the GLDrawable + * implementation has to swap the code. + */ + public boolean surfaceSwap(); + + /** Appends the given {@link SurfaceUpdatedListener} to the end of the list. */ + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l); + + /** + * Inserts the given {@link SurfaceUpdatedListener} at the + * specified position in the list.<br> + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). + * @param l The listener object to be inserted + * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 + */ + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; + + /** Remove the specified {@link SurfaceUpdatedListener} from the list. */ + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); + + /** + * Returns the handle to the surface for this NativeSurface. <P> + * + * The surface handle should be set/update by {@link #lockSurface()}, + * where {@link #unlockSurface()} is not allowed to modify it. + * After {@link #unlockSurface()} it is no more guaranteed + * that the surface handle is still valid. + * + * The surface handle shall reflect the platform one + * for all drawable surface operations, e.g. opengl, swap-buffer. <P> + * + * On X11 this returns an entity of type Window, + * since there is no differentiation of surface and window there. <BR> + * On Microsoft Windows this returns an entity of type HDC. + */ + public long getSurfaceHandle(); + + /** + * Returns the width of the client area excluding insets (window decorations) in pixel units. + * @return width of the client area in pixel units + * @see NativeWindow#getWidth() + * @see #convertToWindowUnits(int[]) + */ + public int getSurfaceWidth(); + + /** + * Returns the height of the client area excluding insets (window decorations) in pixel units. + * @return height of the client area in pixel units + * @see NativeWindow#getHeight() + * @see #convertToWindowUnits(int[]) + */ + public int getSurfaceHeight(); + + /** + * Converts the given pixel units into window units <i>in place</i>. + * @param pixelUnitsAndResult int[2] storage holding the pixel units for the x- and y-coord to convert + * and the resulting values. + * @return result int[2] storage pixelUnitsAndResult for chaining holding the converted values + * @see ScalableSurface + */ + public int[] convertToWindowUnits(final int[] pixelUnitsAndResult); + + /** + * Converts the given window units into pixel units <i>in place</i>. + * @param windowUnitsAndResult int[2] storage holding the window units for the x- and y-coord to convert + * and the resulting values. + * @return result int[2] storage windowUnitsAndResult for chaining holding the converted values + * @see ScalableSurface + */ + public int[] convertToPixelUnits(final int[] windowUnitsAndResult); + + /** + * Returns the graphics configuration corresponding to this window. + * <p> + * In case the implementation utilizes a delegation pattern to wrap abstract toolkits, + * this method shall return the native {@link AbstractGraphicsConfiguration} via {@link AbstractGraphicsConfiguration#getNativeGraphicsConfiguration()}. + * </p> + * @see AbstractGraphicsConfiguration#getNativeGraphicsConfiguration() + * @see com.jogamp.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) + */ + public AbstractGraphicsConfiguration getGraphicsConfiguration(); + + /** + * Convenience: Get display handle from + * AbstractGraphicsConfiguration . AbstractGraphicsScreen . AbstractGraphicsDevice + */ + public long getDisplayHandle(); + + /** + * Convenience: Get display handle from + * AbstractGraphicsConfiguration . AbstractGraphicsScreen + */ + public int getScreenIndex(); + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeSurfaceHolder.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeSurfaceHolder.java new file mode 100644 index 000000000..667f5d8af --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeSurfaceHolder.java @@ -0,0 +1,41 @@ +/** + * Copyright 2014 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; + +/** + * Accessor interface for implementing classes with ownership of a {@link NativeSurface} + * via an <i>is-a</i> or <i>has-a</i> relation. + */ +public interface NativeSurfaceHolder { + /** + * Returns the associated {@link NativeSurface} of this {@link NativeSurfaceHolder}. + */ + public NativeSurface getNativeSurface(); +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindow.java new file mode 100644 index 000000000..1a2d212da --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindow.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +import com.jogamp.nativewindow.util.InsetsImmutable; +import com.jogamp.nativewindow.util.Point; + +/** + * Extend the {@link NativeSurface} interface with windowing + * information such as {@link #getWindowHandle() window-handle}, + * {@link #getWidth() window-size} and {@link #getX() window-position}. + * <p> + * All values of this interface are represented in window units, if not stated otherwise. + * See {@link NativeSurface}. + * </p> + * + * <a name="coordinateSystem"><h5>Coordinate System</h5></a> + * <p> + * <ul> + * <li>Abstract screen space has it's origin in the top-left corner, and may not be at 0/0.</li> + * <li>Window origin is in it's top-left corner, see {@link #getX()} and {@link #getY()}. </li> + * <li>Window client-area excludes {@link #getInsets() insets}, i.e. window decoration.</li> + * <li>Window origin is relative to it's parent window if exist, or the screen position (top-level).</li> + * </ul> + * </p> + * <p> + * A window toolkit such as the AWT may either implement this interface + * directly with one of its components, or provide and register an + * implementation of {@link NativeWindowFactory NativeWindowFactory} + * which can create NativeWindow objects for its components. + * </p> + */ +public interface NativeWindow extends NativeSurface, NativeSurfaceHolder { + + /** + * {@inheritDoc} + * <p> + * Returns this instance, which <i>is-a</i> {@link NativeSurface}. + * </p> + */ + @Override + public NativeSurface getNativeSurface(); + + /** + * Destroys this window incl. releasing all related resources. + */ + public void destroy(); + + /** + * @return The parent NativeWindow, or null if this NativeWindow is top level. + */ + public NativeWindow getParent(); + + /** + * Returns the window handle for this NativeWindow. <P> + * + * The window handle shall reflect the platform one + * for all window related operations, e.g. open, close, resize. <P> + * + * On X11 this returns an entity of type Window. <BR> + * On Microsoft Windows this returns an entity of type HWND. + */ + public long getWindowHandle(); + + /** + * Returns the insets defined as the width and height of the window decoration + * on the left, right, top and bottom in window units. + * <p> + * Insets are zero if the window is undecorated, including child windows. + * </p> + * + * <p> + * Insets are available only after the native window has been created, + * ie. the native window has been made visible.<br> + * + * The top-level window area's top-left corner is located at + * <pre> + * {@link #getX()} - getInsets().{@link InsetsImmutable#getLeftWidth() getLeftWidth()} + * {@link #getY()} - getInsets().{@link InsetsImmutable#getTopHeight() getTopHeight()} + * </pre> + * + * The top-level window size is + * <pre> + * {@link #getWidth()} + getInsets().{@link InsetsImmutable#getTotalWidth() getTotalWidth()} + * {@link #getHeight()} + getInsets().{@link InsetsImmutable#getTotalHeight() getTotalHeight()} + * </pre> + * + * @return insets + */ + public InsetsImmutable getInsets(); + + /** Returns the current x position of this window, relative to it's parent. */ + + /** + * Returns the x position of the top-left corner + * of the client area relative to it's parent in window units. + * <p> + * If no parent exist (top-level window), this coordinate equals the screen coordinate. + * </p> + * <p> + * Since the position reflects the client area, it does not include the insets. + * </p> + * <p> + * See <a href="#coordinateSystem"> Coordinate System</a>. + * </p> + * @see #getInsets() + * @see #getLocationOnScreen(Point) + */ + public int getX(); + + /** + * Returns the current y position of the top-left corner + * of the client area relative to it's parent in window units. + * <p> + * If no parent exist (top-level window), this coordinate equals the screen coordinate. + * </p> + * <p> + * Since the position reflects the client area, it does not include the insets. + * </p> + * <p> + * See <a href="#coordinateSystem"> Coordinate System</a>. + * </p> + * @see #getInsets() + * @see #getLocationOnScreen(Point) + */ + public int getY(); + + /** + * Returns the width of the client area excluding insets (window decorations) in window units. + * @return width of the client area in window units + * @see NativeSurface#getSurfaceWidth() + */ + public int getWidth(); + + /** + * Returns the height of the client area excluding insets (window decorations) in window units. + * @return height of the client area in window units + * @see NativeSurface#getSurfaceHeight() + */ + public int getHeight(); + + /** + * Returns the window's top-left client-area position in the screen. + * <p> + * If {@link Point} is not <code>null</code>, it is translated about the resulting screen position + * and returned. + * </p> + * <p> + * See <a href="#coordinateSystem"> Coordinate System</a>. + * </p> + * <p> + * Since the position reflects the client area, it does not include the insets. + * </p> + * @param point Optional {@link Point} storage. + * If not null, <code>null</code>, it is translated about the resulting screen position + * and returned. + * @see #getX() + * @see #getY() + * @see #getInsets() + */ + public Point getLocationOnScreen(Point point); + + /** Returns true if this native window owns the focus, otherwise false. */ + boolean hasFocus(); + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowException.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowException.java new file mode 100644 index 000000000..8f841e7ea --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowException.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.nativewindow; + +/** A generic exception for OpenGL errors used throughout the binding + as a substitute for {@link RuntimeException}. */ + +public class NativeWindowException extends RuntimeException { + /** Constructs a NativeWindowException object. */ + public NativeWindowException() { + super(); + } + + /** Constructs a NativeWindowException object with the specified detail + message. */ + public NativeWindowException(final String message) { + super(message); + } + + /** Constructs a NativeWindowException object with the specified detail + message and root cause. */ + public NativeWindowException(final String message, final Throwable cause) { + super(message, cause); + } + + /** Constructs a NativeWindowException object with the specified root + cause. */ + public NativeWindowException(final Throwable cause) { + super(cause); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java new file mode 100644 index 000000000..cba3a9214 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/NativeWindowFactory.java @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +package com.jogamp.nativewindow; + +import java.io.File; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.jogamp.nativewindow.util.PointImmutable; + +import jogamp.common.os.PlatformPropsImpl; +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NativeWindowFactoryImpl; +import jogamp.nativewindow.ToolkitProperties; +import jogamp.nativewindow.ResourceToolkitLock; +import jogamp.nativewindow.WrappedWindow; +import jogamp.nativewindow.macosx.OSXUtil; +import jogamp.nativewindow.windows.GDIUtil; +import jogamp.nativewindow.x11.X11Lib; + +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.PropertyAccess; +import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.nativewindow.UpstreamWindowHookMutableSizePos; +import com.jogamp.nativewindow.awt.AWTGraphicsDevice; +import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; +import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsScreen; + +/** Provides a pluggable mechanism for arbitrary window toolkits to + adapt their components to the {@link NativeWindow} interface, + which provides a platform-independent mechanism of accessing the + information required to perform operations like + hardware-accelerated rendering using the OpenGL API. */ + +public abstract class NativeWindowFactory { + protected static final boolean DEBUG; + + /** OpenKODE/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ + public static final String TYPE_EGL = ".egl".intern(); + + /** Microsoft Windows type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_WINDOWS = ".windows".intern(); + + /** X11 type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_X11 = ".x11".intern(); + + /** Broadcom VC IV/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_BCM_VC_IV = ".bcm.vc.iv".intern(); + + /** Android/EGL type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}.*/ + public static final String TYPE_ANDROID = ".android".intern(); + + /** Mac OS X type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_MACOSX = ".macosx".intern(); + + /** Generic AWT type, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_AWT = ".awt".intern(); + + /** Generic DEFAULT type, where platform implementation don't care, as retrieved with {@link #getNativeWindowType(boolean)}. String is canonical via {@link String#intern()}. */ + public static final String TYPE_DEFAULT = ".default".intern(); + + private static final String nativeWindowingTypePure; // canonical String via String.intern() + private static final String nativeWindowingTypeCustom; // canonical String via String.intern() + + private static NativeWindowFactory defaultFactory; + private static Map<Class<?>, NativeWindowFactory> registeredFactories; + + private static Class<?> nativeWindowClass; + private static boolean isAWTAvailable; + + private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ; + /** {@link jogamp.nativewindow.x11.X11Util} implements {@link ToolkitProperties}. */ + 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.windows.GDIUtil} implements {@link ToolkitProperties}. */ + private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil"; + + private static ToolkitLock jawtUtilJAWTToolkitLock; + + private static boolean requiresToolkitLock; + private static boolean desktopHasThreadingIssues; + + // Shutdown hook mechanism for the factory + private static volatile boolean isJVMShuttingDown = false; + private static final List<Runnable> customShutdownHooks = new ArrayList<Runnable>(); + + /** Creates a new NativeWindowFactory instance. End users do not + need to call this method. */ + protected NativeWindowFactory() { + } + + private static final boolean guessBroadcomVCIV() { + return AccessController.doPrivileged(new PrivilegedAction<Boolean>() { + private final File vcliblocation = new File( + "/opt/vc/lib/libbcm_host.so"); + @Override + public Boolean run() { + if ( vcliblocation.isFile() ) { + return Boolean.TRUE; + } + return Boolean.FALSE; + } + } ).booleanValue(); + } + + private static String _getNativeWindowingType() { + switch(PlatformPropsImpl.OS_TYPE) { + case ANDROID: + return TYPE_ANDROID; + case MACOS: + return TYPE_MACOSX; + case WINDOWS: + return TYPE_WINDOWS; + case OPENKODE: + return TYPE_EGL; + + case LINUX: + case FREEBSD: + case SUNOS: + case HPUX: + default: + if( guessBroadcomVCIV() ) { + return TYPE_BCM_VC_IV; + } + return TYPE_X11; + } + } + + static { + final boolean[] _DEBUG = new boolean[] { false }; + final String[] _tmp = new String[] { null }; + + AccessController.doPrivileged(new PrivilegedAction<Object>() { + @Override + public Object run() { + Platform.initSingleton(); // last resort .. + _DEBUG[0] = Debug.debug("NativeWindow"); + _tmp[0] = PropertyAccess.getProperty("nativewindow.ws.name", true); + Runtime.getRuntime().addShutdownHook( + new Thread(new Runnable() { + @Override + public void run() { + NativeWindowFactory.shutdown(true); + } }, "NativeWindowFactory_ShutdownHook" ) ) ; + return null; + } } ) ; + + DEBUG = _DEBUG[0]; + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - Info: NativeWindowFactory.<init>"); + // Thread.dumpStack(); + } + + // Gather the windowing TK first + nativeWindowingTypePure = _getNativeWindowingType(); + if(null==_tmp[0] || _tmp[0].length()==0) { + nativeWindowingTypeCustom = nativeWindowingTypePure; + } else { + nativeWindowingTypeCustom = _tmp[0].intern(); // canonical representation + } + } + + private static boolean initialized = false; + + private static void initSingletonNativeImpl(final ClassLoader cl) { + final String clazzName; + if( TYPE_X11 == nativeWindowingTypePure ) { + clazzName = X11UtilClassName; + } else if( TYPE_WINDOWS == nativeWindowingTypePure ) { + clazzName = GDIClassName; + } else if( TYPE_MACOSX == nativeWindowingTypePure ) { + clazzName = OSXUtilClassName; + } else { + clazzName = null; + } + if( null != clazzName ) { + ReflectionUtil.callStaticMethod(clazzName, "initSingleton", null, null, cl ); + + final Boolean res1 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "requiresToolkitLock", null, null, cl); + requiresToolkitLock = res1.booleanValue(); + final Boolean res2 = (Boolean) ReflectionUtil.callStaticMethod(clazzName, "hasThreadingIssues", null, null, cl); + desktopHasThreadingIssues = res2.booleanValue(); + } else { + requiresToolkitLock = false; + desktopHasThreadingIssues = false; + } + } + + /** Returns true if the JVM is shutting down, otherwise false. */ + public static final boolean isJVMShuttingDown() { return isJVMShuttingDown; } + + /** + * Add a custom shutdown hook to be performed at JVM shutdown before shutting down NativeWindowFactory instance. + * + * @param head if true add runnable at the start, otherwise at the end + * @param runnable runnable to be added. + */ + public static void addCustomShutdownHook(final boolean head, final Runnable runnable) { + synchronized( customShutdownHooks ) { + if( !customShutdownHooks.contains( runnable ) ) { + if( head ) { + customShutdownHooks.add(0, runnable); + } else { + customShutdownHooks.add( runnable ); + } + } + } + } + + /** + * Cleanup resources at JVM shutdown + */ + public static synchronized void shutdown(final boolean _isJVMShuttingDown) { + isJVMShuttingDown = _isJVMShuttingDown; + if(DEBUG) { + System.err.println("NativeWindowFactory.shutdown() START: JVM Shutdown "+isJVMShuttingDown+", on thread "+Thread.currentThread().getName()); + } + synchronized(customShutdownHooks) { + final int cshCount = customShutdownHooks.size(); + for(int i=0; i < cshCount; i++) { + try { + if( DEBUG ) { + System.err.println("NativeWindowFactory.shutdown - customShutdownHook #"+(i+1)+"/"+cshCount); + } + customShutdownHooks.get(i).run(); + } catch(final Throwable t) { + System.err.println("NativeWindowFactory.shutdown: Caught "+t.getClass().getName()+" during customShutdownHook #"+(i+1)+"/"+cshCount); + if( DEBUG ) { + t.printStackTrace(); + } + } + } + customShutdownHooks.clear(); + } + if(DEBUG) { + System.err.println("NativeWindowFactory.shutdown(): Post customShutdownHook"); + } + + if(initialized) { + initialized = false; + if(null != registeredFactories) { + registeredFactories.clear(); + registeredFactories = null; + } + GraphicsConfigurationFactory.shutdown(); + } + + shutdownNativeImpl(NativeWindowFactory.class.getClassLoader()); // always re-shutdown + // SharedResourceToolkitLock.shutdown(DEBUG); // not used yet + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END JVM Shutdown "+isJVMShuttingDown); + } + } + + private static void shutdownNativeImpl(final ClassLoader cl) { + final String clazzName; + if( TYPE_X11 == nativeWindowingTypePure ) { + clazzName = X11UtilClassName; + } else if( TYPE_WINDOWS == nativeWindowingTypePure ) { + clazzName = GDIClassName; + } else if( TYPE_MACOSX == nativeWindowingTypePure ) { + clazzName = OSXUtilClassName; + } else { + clazzName = null; + } + if( null != clazzName ) { + ReflectionUtil.callStaticMethod(clazzName, "shutdown", null, null, cl ); + } + } + + /** Returns true if {@link #initSingleton()} has been called w/o subsequent {@link #shutdown(boolean)}. */ + public static synchronized boolean isInitialized() { return initialized; } + + /** + * Static one time initialization of this factory.<br> + * This initialization method <b>must be called</b> once by the program or utilizing modules! + */ + public static synchronized void initSingleton() { + if(!initialized) { + initialized = true; + + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.initSingleton()"); + } + + final ClassLoader cl = NativeWindowFactory.class.getClassLoader(); + + isAWTAvailable = false; // may be set to true below + + if( Platform.AWT_AVAILABLE && + ReflectionUtil.isClassAvailable("com.jogamp.nativewindow.awt.AWTGraphicsDevice", cl) ) { + + final Method[] jawtUtilMethods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() { + @Override + public Method[] run() { + try { + final Class<?> _jawtUtilClass = Class.forName(JAWTUtilClassName, true, NativeWindowFactory.class.getClassLoader()); + final Method jawtUtilIsHeadlessMethod = _jawtUtilClass.getDeclaredMethod("isHeadlessMode", (Class[])null); + jawtUtilIsHeadlessMethod.setAccessible(true); + final Method jawtUtilInitMethod = _jawtUtilClass.getDeclaredMethod("initSingleton", (Class[])null); + jawtUtilInitMethod.setAccessible(true); + final Method jawtUtilGetJAWTToolkitLockMethod = _jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{}); + jawtUtilGetJAWTToolkitLockMethod.setAccessible(true); + return new Method[] { jawtUtilInitMethod, jawtUtilIsHeadlessMethod, jawtUtilGetJAWTToolkitLockMethod }; + } catch (final Exception e) { + if(DEBUG) { + e.printStackTrace(); + } + } + return null; + } + }); + if(null != jawtUtilMethods) { + final Method jawtUtilInitMethod = jawtUtilMethods[0]; + final Method jawtUtilIsHeadlessMethod = jawtUtilMethods[1]; + final Method jawtUtilGetJAWTToolkitLockMethod = jawtUtilMethods[2]; + + ReflectionUtil.callMethod(null, jawtUtilInitMethod); + + Object resO = ReflectionUtil.callMethod(null, jawtUtilIsHeadlessMethod); + if(resO instanceof Boolean) { + // AWT is only available in case all above classes are available + // and AWT is not int headless mode + isAWTAvailable = ((Boolean)resO).equals(Boolean.FALSE); + } else { + throw new RuntimeException("JAWTUtil.isHeadlessMode() didn't return a Boolean"); + } + resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitLockMethod); + if(resO instanceof ToolkitLock) { + jawtUtilJAWTToolkitLock = (ToolkitLock) resO; + } else { + throw new RuntimeException("JAWTUtil.getJAWTToolkitLock() didn't return a ToolkitLock"); + } + } + } + + // X11 initialization after possible AWT initialization + // This is performed post AWT initialization, allowing AWT to complete the same, + // which may have been triggered before NativeWindow initialization. + // This way behavior is more uniforms across configurations (Applet/RCP, applications, ..). + initSingletonNativeImpl(cl); + + registeredFactories = Collections.synchronizedMap(new HashMap<Class<?>, NativeWindowFactory>()); + + // register our default factory -> NativeWindow + final NativeWindowFactory factory = new NativeWindowFactoryImpl(); + nativeWindowClass = com.jogamp.nativewindow.NativeWindow.class; + registerFactory(nativeWindowClass, factory); + defaultFactory = factory; + + if ( isAWTAvailable ) { + // register either our default factory or (if exist) the X11/AWT one -> AWT Component + registerFactory(ReflectionUtil.getClass(ReflectionUtil.AWTNames.ComponentClass, false, cl), factory); + } + + if(DEBUG) { + System.err.println("NativeWindowFactory requiresToolkitLock "+requiresToolkitLock+", desktopHasThreadingIssues "+desktopHasThreadingIssues); + System.err.println("NativeWindowFactory isAWTAvailable "+isAWTAvailable+", defaultFactory "+factory); + } + + GraphicsConfigurationFactory.initSingleton(); + } + } + + /** @return true if the underlying toolkit requires locking, otherwise false. */ + public static boolean requiresToolkitLock() { + return requiresToolkitLock; + } + + /** @return true if not headless, AWT Component and NativeWindow's AWT part available */ + public static boolean isAWTAvailable() { return isAWTAvailable; } + + /** + * @param useCustom if false return the native value, if true return a custom value if set, otherwise fallback to the native value. + * @return the native window type, e.g. {@link #TYPE_X11}, which is canonical via {@link String#intern()}. + * Hence {@link String#equals(Object)} and <code>==</code> produce the same result. + */ + public static String getNativeWindowType(final boolean useCustom) { + return useCustom?nativeWindowingTypeCustom:nativeWindowingTypePure; + } + + /** Don't know if we shall add this factory here .. + public static AbstractGraphicsDevice createGraphicsDevice(String type, String connection, int unitID, long handle, ToolkitLock locker) { + if(TYPE_EGL == type) { + return new + } else if(TYPE_X11 == type) { + } else if(TYPE_WINDOWS == type) { + } else if(TYPE_MACOSX == type)) { + } else if(TYPE_AWT == type) { + } else if(TYPE_DEFAULT == type) { + } + } */ + + /** Sets the default NativeWindowFactory. */ + public static void setDefaultFactory(final NativeWindowFactory factory) { + defaultFactory = factory; + } + + /** Gets the default NativeWindowFactory. */ + public static NativeWindowFactory getDefaultFactory() { + return defaultFactory; + } + + /** + * Returns the AWT {@link ToolkitLock} (JAWT based) if {@link #isAWTAvailable}, otherwise null. + * <p> + * The JAWT based {@link ToolkitLock} also locks the global lock, + * which matters if the latter is required. + * </p> + */ + public static ToolkitLock getAWTToolkitLock() { + return jawtUtilJAWTToolkitLock; + } + + public static ToolkitLock getNullToolkitLock() { + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + /** + * Provides the system default {@link ToolkitLock} for the default system windowing type. + * @see #getNativeWindowType(boolean) + * @see #getDefaultToolkitLock(java.lang.String) + */ + public static ToolkitLock getDefaultToolkitLock() { + return getDefaultToolkitLock(nativeWindowingTypePure); + } + + /** + * Provides the default {@link ToolkitLock} for <code>type</code>. + * <ul> + * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li> + * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> + * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> + * </ul> + */ + public static ToolkitLock getDefaultToolkitLock(final String type) { + if( requiresToolkitLock ) { + if( TYPE_AWT == type && isAWTAvailable() ) { // uses .intern()! + return getAWTToolkitLock(); + } + return ResourceToolkitLock.create(); + } + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + /** + * Provides the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. + * <ul> + * <li> JAWT {@link ToolkitLock} if required and <code>type</code> is of {@link #TYPE_AWT} and AWT available,</li> + * <li> {@link jogamp.nativewindow.ResourceToolkitLock} if required, otherwise</li> + * <li> {@link jogamp.nativewindow.NullToolkitLock} </li> + * </ul> + */ + public static ToolkitLock getDefaultToolkitLock(final String type, final long deviceHandle) { + if( requiresToolkitLock ) { + if( TYPE_AWT == type && isAWTAvailable() ) { // uses .intern()! + return getAWTToolkitLock(); + } + return ResourceToolkitLock.create(); + } + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + /** + * @param device + * @param screen -1 is default screen of the given device, e.g. maybe 0 or determined by native API. >= 0 is specific screen + * @return newly created AbstractGraphicsScreen matching device's native type + */ + public static AbstractGraphicsScreen createScreen(final AbstractGraphicsDevice device, int screen) { + final String type = device.getType(); + if( TYPE_X11 == type ) { + final X11GraphicsDevice x11Device = (X11GraphicsDevice)device; + if(0 > screen) { + screen = x11Device.getDefaultScreen(); + } + return new X11GraphicsScreen(x11Device, screen); + } + if(0 > screen) { + screen = 0; // FIXME: Needs native API utilization + } + if( TYPE_AWT == type ) { + final AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) device; + return new AWTGraphicsScreen(awtDevice); + } + return new DefaultGraphicsScreen(device, screen); + } + + /** Returns the appropriate NativeWindowFactory to handle window + objects of the given type. The windowClass might be {@link + NativeWindow NativeWindow}, in which case the client has + already assumed the responsibility of creating a compatible + NativeWindow implementation, or it might be that of a toolkit + class like {@link java.awt.Component Component}. */ + public static NativeWindowFactory getFactory(final Class<?> windowClass) throws IllegalArgumentException { + if (nativeWindowClass.isAssignableFrom(windowClass)) { + return registeredFactories.get(nativeWindowClass); + } + Class<?> clazz = windowClass; + while (clazz != null) { + final NativeWindowFactory factory = registeredFactories.get(clazz); + if (factory != null) { + return factory; + } + clazz = clazz.getSuperclass(); + } + throw new IllegalArgumentException("No registered NativeWindowFactory for class " + windowClass.getName()); + } + + /** Registers a NativeWindowFactory handling window objects of the + given class. This does not need to be called by end users, + only implementors of new NativeWindowFactory subclasses. */ + protected static void registerFactory(final Class<?> windowClass, final NativeWindowFactory factory) { + if(DEBUG) { + System.err.println("NativeWindowFactory.registerFactory() "+windowClass+" -> "+factory); + } + registeredFactories.put(windowClass, factory); + } + + /** Converts the given window object and it's + {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration} into a + {@link NativeWindow NativeWindow} which can be operated upon by a custom + toolkit, e.g. {@link com.jogamp.opengl.GLDrawableFactory com.jogamp.opengl.GLDrawableFactory}.<br> + The object may be a component for a particular window toolkit, such as an AWT + Canvas. It may also be a NativeWindow object itself.<br> + You shall utilize {@link com.jogamp.nativewindow.GraphicsConfigurationFactory GraphicsConfigurationFactory} + to construct a proper {@link AbstractGraphicsConfiguration AbstractGraphicsConfiguration}.<br> + The particular implementation of the + NativeWindowFactory is responsible for handling objects from a + particular window toolkit. The built-in NativeWindowFactory + handles NativeWindow instances as well as AWT Components.<br> + + @throws IllegalArgumentException if the given window object + could not be handled by any of the registered + NativeWindowFactory instances + + @see com.jogamp.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) + */ + public static NativeWindow getNativeWindow(final Object winObj, final AbstractGraphicsConfiguration config) throws IllegalArgumentException, NativeWindowException { + if (winObj == null) { + throw new IllegalArgumentException("Null window object"); + } + + return getFactory(winObj.getClass()).getNativeWindowImpl(winObj, config); + } + + /** Performs the conversion from a toolkit's window object to a + NativeWindow. Implementors of concrete NativeWindowFactory + subclasses should override this method. */ + protected abstract NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException; + + /** + * Returns the {@link OffscreenLayerSurface} instance of this {@link NativeSurface}. + * <p> + * In case this surface is a {@link NativeWindow}, we traverse from the given surface + * up to root until an implementation of {@link OffscreenLayerSurface} is found. + * In case <code>ifEnabled</code> is true, the surface must also implement {@link OffscreenLayerOption} + * where {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()} is <code>true</code>. + * </p> + * + * @param surface The surface to query. + * @param ifEnabled If true, only return the enabled {@link OffscreenLayerSurface}, see {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()}. + * @return + */ + public static OffscreenLayerSurface getOffscreenLayerSurface(final NativeSurface surface, final boolean ifEnabled) { + if(surface instanceof OffscreenLayerSurface && + ( !ifEnabled || surface instanceof OffscreenLayerOption ) ) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) surface; + return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + if(surface instanceof NativeWindow) { + NativeWindow nw = ((NativeWindow) surface).getParent(); + while(null != nw) { + if(nw instanceof OffscreenLayerSurface && + ( !ifEnabled || nw instanceof OffscreenLayerOption ) ) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) nw; + return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + nw = nw.getParent(); + } + } + return null; + } + + /** + * Returns true if the given visualID is valid for further processing, i.e. OpenGL usage, + * otherwise return false. + * <p> + * On certain platforms, i.e. X11, a valid visualID is required at window creation. + * Other platforms may determine it later on, e.g. OSX and Windows. </p> + * <p> + * If the visualID is {@link VisualIDHolder#VID_UNDEFINED} and the platform requires it + * at creation time (see above), it is not valid for further processing. + * </p> + */ + public static boolean isNativeVisualIDValidForProcessing(final int visualID) { + return NativeWindowFactory.TYPE_X11 != NativeWindowFactory.getNativeWindowType(false) || + VisualIDHolder.VID_UNDEFINED != visualID ; + } + + /** + * Creates a native device type, following {@link #getNativeWindowType(boolean) getNativeWindowType(true)}. + * <p> + * The device will be opened if <code>own</code> is true, otherwise no native handle will ever be acquired. + * </p> + */ + public static AbstractGraphicsDevice createDevice(final String displayConnection, final boolean own) { + final String nwt = NativeWindowFactory.getNativeWindowType(true); + if( NativeWindowFactory.TYPE_X11 == nwt ) { + if( own ) { + return new X11GraphicsDevice(displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT, null /* ToolkitLock */); + } else { + return new X11GraphicsDevice(displayConnection, AbstractGraphicsDevice.DEFAULT_UNIT); + } + } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { + return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + return new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + /** + * FIXME: Needs service provider interface (SPI) for TK dependent implementation + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_ANDROID== nwt ) { + } else if( NativeWindowFactory.TYPE_EGL == nwt ) { + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_AWT == nwt ) { + */ + } + throw new UnsupportedOperationException("n/a for windowing system: "+nwt); + } + + /** + * Creates a wrapped {@link NativeWindow} with given native handles and {@link AbstractGraphicsScreen}. + * <p> + * The given {@link UpstreamWindowHookMutableSizePos} maybe used to reflect resizes and repositioning of the native window. + * </p> + * <p> + * The {@link AbstractGraphicsScreen} may be created via {@link #createScreen(AbstractGraphicsDevice, int)}. + * </p> + * <p> + * The {@link AbstractGraphicsScreen} may have an underlying open {@link AbstractGraphicsDevice} + * or a simple <i>dummy</i> instance, see {@link #createDevice(String, boolean)}. + * </p> + */ + public static NativeWindow createWrappedWindow(final AbstractGraphicsScreen aScreen, final long surfaceHandle, final long windowHandle, + final UpstreamWindowHookMutableSizePos hook) { + final CapabilitiesImmutable caps = new Capabilities(); + final AbstractGraphicsConfiguration config = new DefaultGraphicsConfiguration(aScreen, caps, caps); + return new WrappedWindow(config, surfaceHandle, hook, true, windowHandle); + } + + /** + * @param nw + * @return top-left client-area position in window units + */ + public static PointImmutable getLocationOnScreen(final NativeWindow nw) { + final String nwt = NativeWindowFactory.getNativeWindowType(true); + if( NativeWindowFactory.TYPE_X11 == nwt ) { + return X11Lib.GetRelativeLocation(nw.getDisplayHandle(), nw.getScreenIndex(), nw.getWindowHandle(), 0, 0, 0); + } else if( NativeWindowFactory.TYPE_WINDOWS == nwt ) { + return GDIUtil.GetRelativeLocation(nw.getWindowHandle(), 0, 0, 0); + } else if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + return OSXUtil.GetLocationOnScreen(nw.getWindowHandle(), 0, 0); + /** + * FIXME: Needs service provider interface (SPI) for TK dependent implementation + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_ANDROID== nwt ) { + } else if( NativeWindowFactory.TYPE_EGL == nwt ) { + } else if( NativeWindowFactory.TYPE_BCM_VC_IV == nwt ) { + } else if( NativeWindowFactory.TYPE_AWT == nwt ) { + */ + } + throw new UnsupportedOperationException("n/a for windowing system: "+nwt); + } + + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/OffscreenLayerOption.java b/src/nativewindow/classes/com/jogamp/nativewindow/OffscreenLayerOption.java new file mode 100644 index 000000000..2e9f2c172 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/OffscreenLayerOption.java @@ -0,0 +1,61 @@ +/** + * Copyright 2011 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; + +/** + * Handling requests for using an {@link OffscreenLayerSurface} + * within the implementation. + */ +public interface OffscreenLayerOption { + /** + * Request an offscreen layer, if supported. + * <p> + * Shall be called before the first {@link NativeWindow#lockSurface()}, + * and hence before realization. + * </p> + * + * @see #getShallUseOffscreenLayer() + * @see #isOffscreenLayerSurfaceEnabled() + */ + public void setShallUseOffscreenLayer(boolean v); + + /** Returns the property set by {@link #setShallUseOffscreenLayer(boolean)}. */ + public boolean getShallUseOffscreenLayer(); + + /** + * Returns true if this instance uses an offscreen layer, otherwise false. + * <p> + * This instance is an offscreen layer, if {@link #setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)} + * has been called before it's realization and first lock and the underlying implementation supports it. + * </p> + * The return value is undefined before issuing the first {@link NativeWindow#lockSurface()}. + * + * @see #setShallUseOffscreenLayer(boolean) + */ + public boolean isOffscreenLayerSurfaceEnabled(); +}
\ No newline at end of file diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/OffscreenLayerSurface.java new file mode 100644 index 000000000..abba2c126 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/OffscreenLayerSurface.java @@ -0,0 +1,86 @@ +/** + * Copyright 2011 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; + +import com.jogamp.nativewindow.util.PixelRectangle; +import com.jogamp.nativewindow.util.PointImmutable; + +import com.jogamp.common.util.locks.RecursiveLock; + +/** + * Interface specifying the offscreen layer surface protocol. + */ +public interface OffscreenLayerSurface { + /** + * Attach the offscreen layer to this offscreen layer surface. + * <p> + * Implementation may realize all required resources at this point. + * </p> + * + * @see #isOffscreenLayerSurfaceEnabled() + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false + */ + public void attachSurfaceLayer(final long layerHandle) throws NativeWindowException; + + /** + * Detaches a previously attached offscreen layer from this offscreen layer surface. + * @see #attachSurfaceLayer(long) + * @see #isOffscreenLayerSurfaceEnabled() + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false + * or no surface layer is attached. + */ + public void detachSurfaceLayer() throws NativeWindowException; + + /** Returns the attached surface layer or null if none is attached. */ + public long getAttachedSurfaceLayer(); + + /** Returns true if a surface layer is attached, otherwise false. */ + public boolean isSurfaceLayerAttached(); + + /** Sets the capabilities of this instance, allowing upstream API's to refine it, i.e. OpenGL related settings. */ + public void setChosenCapabilities(CapabilitiesImmutable caps); + + /** Returns the recursive lock object of this surface, which synchronizes multithreaded access. */ + public RecursiveLock getLock(); + + /** + * Optional method setting cursor in the corresponding on-screen surface/window, if exists. + * + * @param pixelrect cursor pixels, maybe null for default cursor + * @param hotSpot maybe null for default cursor + * @return true if successful, i.e. on-screen surface/window w/ cursor capabilities exists. Otherwise false. + */ + public boolean setCursor(PixelRectangle pixelrect, PointImmutable hotSpot); + + /** + * Optional method hiding the cursor in the corresponding on-screen surface/window, if exists. + * + * @return true if successful, i.e. on-screen surface/window w/ cursor capabilities exists. Otherwise false. + */ + public boolean hideCursor(); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/ProxySurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/ProxySurface.java new file mode 100644 index 000000000..7b36531dc --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/ProxySurface.java @@ -0,0 +1,135 @@ +/** + * 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.nativewindow; + +import jogamp.nativewindow.Debug; + +/** + * Provides a mutable {@link NativeSurface}, i.e. {@link MutableSurface}, while allowing an + * {@link UpstreamSurfaceHook} to influence the lifecycle and information. + * + * @see UpstreamSurfaceHook + * @see MutableSurface + * @see NativeSurface + */ +public interface ProxySurface extends MutableSurface { + public static final boolean DEBUG = Debug.debug("ProxySurface"); + + /** + * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's surface handle + * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() + */ + public static final int OPT_PROXY_OWNS_UPSTREAM_SURFACE = 1 << 6; + + /** + * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's {@link AbstractGraphicsDevice}. + * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() + */ + public static final int OPT_PROXY_OWNS_UPSTREAM_DEVICE = 1 << 7; + + /** + * Implementation specific bitvalue stating the upstream's {@link NativeSurface} is an invisible window, i.e. maybe incomplete. + * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() + */ + public static final int OPT_UPSTREAM_WINDOW_INVISIBLE = 1 << 8; + + /** + * Implementation specific bitvalue stating the upstream's {@link NativeSurface}'s zero handle is valid. + * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() + */ + public static final int OPT_UPSTREAM_SURFACELESS = 1 << 9; + + /** Allow redefining the AbstractGraphicsConfiguration */ + public void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg); + + /** + * Returns the optional upstream {@link NativeSurface} if used by implementation, otherwise <code>null</code>. + * <p> + * The upstream {@link NativeSurface} is retrieved via {@link #getUpstreamSurfaceHook() the UpstreamSurfaceHook}, + * i.e. {@link UpstreamSurfaceHook#getUpstreamSurface()}. + * </p> + * <p> + * One example is the JOGL EGLWrappedSurface, which might be backed up by a + * native platform NativeSurface (X11, WGL, CGL, ..). + * </p> + */ + public NativeSurface getUpstreamSurface(); + + /** Returns the {@link UpstreamSurfaceHook} if {@link #setUpstreamSurfaceHook(UpstreamSurfaceHook) set}, otherwise <code>null</code>. */ + public UpstreamSurfaceHook getUpstreamSurfaceHook(); + + /** + * Overrides the {@link UpstreamSurfaceHook}. + */ + public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook); + + /** + * Enables or disables the {@link UpstreamSurfaceHook} lifecycle functions + * {@link UpstreamSurfaceHook#create(ProxySurface)} and {@link UpstreamSurfaceHook#destroy(ProxySurface)}. + * <p> + * Use this for small code blocks where the native resources shall not change, + * i.e. resizing a derived (OpenGL) drawable. + * </p> + */ + public void enableUpstreamSurfaceHookLifecycle(boolean enable); + + /** + * {@link UpstreamSurfaceHook#create(ProxySurface)} is being issued and the proxy surface/window handles shall be set. + */ + public void createNotify(); + + /** + * {@link UpstreamSurfaceHook#destroy(ProxySurface)} is being issued and all proxy surface/window handles shall be cleared. + */ + public void destroyNotify(); + + public StringBuilder getUpstreamOptionBits(StringBuilder sink); + public int getUpstreamOptionBits(); + + /** Returns <code>true</code> if the give bit-mask <code>v</code> is set in this instance upstream-option-bits, otherwise <code>false</code>.*/ + public boolean containsUpstreamOptionBits(int v); + + /** Add the given bit-mask to this instance upstream-option-bits using bit-or w/ <code>v</code>.*/ + public void addUpstreamOptionBits(int v); + + /** Clear the given bit-mask from this instance upstream-option-bits using bit-and w/ <code>~v</code>*/ + public void clearUpstreamOptionBits(int v); + + public StringBuilder toString(StringBuilder sink); + @Override + public String toString(); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/ScalableSurface.java b/src/nativewindow/classes/com/jogamp/nativewindow/ScalableSurface.java new file mode 100644 index 000000000..eea9e4bed --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/ScalableSurface.java @@ -0,0 +1,107 @@ +/** + * Copyright 2014 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; + +/** + * Adding mutable surface pixel scale property to implementing class, usually to a {@link NativeSurface} implementation, + * see {@link #setSurfaceScale(float[])}. + */ +public interface ScalableSurface { + /** Setting surface-pixel-scale of {@value}, results in same pixel- and window-units. */ + public static final float IDENTITY_PIXELSCALE = 1f; + /** Setting surface-pixel-scale of {@value}, results in maximum platform dependent pixel-scale, i.e. pixel-units >> window-units where available. */ + public static final float AUTOMAX_PIXELSCALE = 0f; + + /** + * Request a pixel scale in x- and y-direction for the associated {@link NativeSurface}, + * where {@code size_in_pixel_units = pixel_scale * size_in_window_units}. + * <p> + * Default pixel scale request for both directions is {@link #AUTOMAX_PIXELSCALE}. + * </p> + * <p> + * In case platform only supports uniform pixel scale, i.e. one scale for both directions, + * either {@link #AUTOMAX_PIXELSCALE} or the maximum requested pixel scale component is used. + * </p> + * <p> + * The <i>requested</i> pixel scale will be validated against platform limits before native scale-setup, + * i.e. clipped to {@link #IDENTITY_PIXELSCALE} if not supported or clipped to the platform maximum. + * It can be queried via {@link #getRequestedSurfaceScale(float[])}. + * </p> + * <p> + * The actual <i>realized</i> pixel scale values of the {@link NativeSurface} + * can be queried via {@link #getCurrentSurfaceScale(float[])} or + * computed via <code>surface.{@link NativeSurface#convertToPixelUnits(int[]) convertToPixelUnits}(new int[] { 1, 1 })</code> + * </p> + * @param pixelScale <i>requested</i> surface pixel scale float[2] values for x- and y-direction. + * @return {@code true} if the {@link #getCurrentSurfaceScale(float[]) current pixel scale} has changed, otherwise {@code false}. + * @see #getRequestedSurfaceScale(float[]) + */ + public boolean setSurfaceScale(final float[] pixelScale); + + /** + * Returns the {@link #setSurfaceScale(float[]) requested} pixel scale of the associated {@link NativeSurface}. + * + * @param result float[2] storage for the result + * @return the passed storage containing the current pixelScale for chaining + * @see #setSurfaceScale(float[]) + */ + public float[] getRequestedSurfaceScale(final float[] result); + + /** + * Returns the current pixel scale of the associated {@link NativeSurface}. + * + * @param result float[2] storage for the result + * @return the passed storage containing the current pixelScale for chaining + */ + public float[] getCurrentSurfaceScale(final float[] result); + + /** + * Returns the minimum pixel scale of the associated {@link NativeSurface}. + * @param result float[2] storage for the result + * @return the passed storage containing the minimum pixelScale for chaining + */ + public float[] getMinimumSurfaceScale(final float[] result); + + /** + * Returns the maximum pixel scale of the associated {@link NativeSurface}. + * <p> + * The maximum pixel scale maybe used to determine the proper <i>dpi</i> + * value of the monitor displaying this {@link NativeSurface}. + * <pre> + * surfacePpMM = monitorPpMM * currentSurfaceScale / nativeSurfaceScale, + * with PpMM == pixel per millimeter + * </pre> + * </p> + * + * @param result float[2] storage for the result + * @return the passed storage containing the maximum pixelScale for chaining + */ + public float[] getMaximumSurfaceScale(final float[] result); +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/SurfaceUpdatedListener.java b/src/nativewindow/classes/com/jogamp/nativewindow/SurfaceUpdatedListener.java new file mode 100644 index 000000000..37e4bd0c9 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/SurfaceUpdatedListener.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 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: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +package com.jogamp.nativewindow; + +/** + * Clients may add their SurfaceUpdateListener implementation to a {@link com.jogamp.nativewindow.NativeSurface} + * allowing to get notified after the surface has been updated, eg. after a swap buffer operation. + */ +public interface SurfaceUpdatedListener { + /** Notification of a surface update event, eg. after a swap buffer operation. + * + * @param updater is the caller object who updated the surface, + * e.g. a JOGL GLDrawable. + * @param ns the updated NativeSurface + * @param when the time in ms, when the surface was updated + */ + public void surfaceUpdated(Object updater, NativeSurface ns, long when) ; +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/ToolkitLock.java b/src/nativewindow/classes/com/jogamp/nativewindow/ToolkitLock.java new file mode 100644 index 000000000..eef11adb7 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/ToolkitLock.java @@ -0,0 +1,78 @@ +/** + * 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.nativewindow; + +import jogamp.nativewindow.Debug; + +/** + * Marker for a singleton global recursive blocking lock implementation, + * optionally locking a native windowing toolkit as well. + * <p> + * Toolkit locks are created solely via {@link NativeWindowFactory}. + * </p> + * <p> + * One use case is the AWT locking on X11, see {@link NativeWindowFactory#getDefaultToolkitLock(String, long)}. + * </p> + */ +public interface ToolkitLock { + public static final boolean DEBUG = Debug.debug("ToolkitLock"); + public static final boolean TRACE_LOCK = Debug.isPropertyDefined("nativewindow.debug.ToolkitLock.TraceLock", true); + + /** + * Blocking until the lock is acquired by this Thread or a timeout is reached. + * <p> + * Timeout is implementation specific, if used at all. + * </p> + * + * @throws RuntimeException in case of a timeout + */ + public void lock(); + + /** + * Release the lock. + * + * @throws RuntimeException in case the lock is not acquired by this thread. + */ + public void unlock(); + + /** + * @throws RuntimeException if current thread does not hold the lock + */ + public void validateLocked() throws RuntimeException; + + /** + * Dispose this instance. + * <p> + * Shall be called when instance is no more required. + * </p> + * This allows implementations sharing a lock via resources + * to decrease the reference counter. + */ + public void dispose(); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHook.java b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHook.java new file mode 100644 index 000000000..5e9b8d293 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHook.java @@ -0,0 +1,66 @@ +/** + * 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.nativewindow; + +/** + * Interface allowing upstream caller to pass lifecycle actions and size info + * to a {@link ProxySurface} instance. + */ +public interface UpstreamSurfaceHook { + /** called within {@link ProxySurface#createNotify()} within lock, before using surface. */ + public void create(ProxySurface s); + /** called within {@link ProxySurface#destroyNotify()} within lock, before clearing fields. */ + public void destroy(ProxySurface s); + + /** + * Returns the optional upstream {@link NativeSurface} if used by implementation, otherwise <code>null</code>. + * <p> + * One example is the JOGL EGLWrappedSurface, which might be backed up by a + * native platform NativeSurface (X11, WGL, CGL, ..). + * </p> + */ + public NativeSurface getUpstreamSurface(); + + /** Returns the width of the upstream surface in pixels, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ + public int getSurfaceWidth(ProxySurface s); + /** Returns the height of the upstream surface in pixels, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ + public int getSurfaceHeight(ProxySurface s); + + /** + * {@link UpstreamSurfaceHook} w/ mutable size, allowing it's {@link ProxySurface} user to resize. + */ + public interface MutableSize extends UpstreamSurfaceHook { + /** + * Resizes the upstream surface. + * @param width new width in pixel units + * @param height new height in pixel units + */ + public void setSurfaceSize(int width, int height); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java b/src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java new file mode 100644 index 000000000..69bfe50f8 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/VisualIDHolder.java @@ -0,0 +1,136 @@ +/** + * 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.nativewindow; + +import java.util.Comparator; + +/** + * Visual ID holder interface. + * <p> + * Allows queries of different types of native visual IDs, + * see {@link #getVisualID(int)}. + * </p> + */ +public interface VisualIDHolder { + + public enum VIDType { + // Generic Values + INTRINSIC(0), NATIVE(1), + // EGL Values + EGL_CONFIG(10), + // X11 Values + X11_XVISUAL(20), X11_FBCONFIG(21), + // Windows Values + WIN32_PFD(30); + + public final int id; + + VIDType(final int id){ + this.id = id; + } + } + + /** + * Returns the native visual ID of the given <code>type</code> + * if supported, or {@link #VID_UNDEFINED} if not supported. + * <p> + * Depending on the native windowing system, <code>type</code> is handled as follows: + * <ul> + * <li>X11 throws NativeWindowException on <code>EGL_CONFIG</code>, <code>WIN32_PFD</code> + * <ul> + * <li><code>INTRINSIC</code>: <i>X11 XVisual ID</i></li> + * <li><code>NATIVE</code>: <i>X11 XVisual ID</i></li> + * <li><code>X11_XVISUAL</code>: <i>X11 XVisual ID</i></li> + * <li><code>X11_FBCONFIG</code>: <code>VID_UNDEFINED</code></li> + * </ul></li> + * <li>X11/GL throws NativeWindowException on <code>EGL_CONFIG</code>, <code>WIN32_PFD</code> + * <ul> + * <li><code>INTRINSIC</code>: <i>X11 XVisual ID</i></li> + * <li><code>NATIVE</code>: <i>X11 XVisual ID</i></li> + * <li><code>X11_XVISUAL</code>: <i>X11 XVisual ID</i></li> + * <li><code>X11_FBCONFIG</code>: <i>X11 FBConfig ID</i> or <code>VID_UNDEFINED</code></li> + * </ul></li> + * <li>Windows/GL throws NativeWindowException on <code>EGL_CONFIG</code>, <code>X11_XVISUAL</code>, <code>X11_FBCONFIG</code> + * <ul> + * <li><code>INTRINSIC</code>: <i>Win32 PIXELFORMATDESCRIPTOR ID</i></li> + * <li><code>NATIVE</code>: <i>Win32 PIXELFORMATDESCRIPTOR ID</i></li> + * <li><code>WIN32_PFD</code>: <i>Win32 PIXELFORMATDESCRIPTOR ID</i></li> + * </ul></li> + * <li>EGL/GL throws NativeWindowException on <code>X11_XVISUAL</code>, <code>X11_FBCONFIG</code>, <code>WIN32_PFD</code> + * <ul> + * <li><code>INTRINSIC</code>: <i>EGL Config ID</i></li> + * <li><code>NATIVE</code>: <i>EGL NativeVisual ID</i> (<i>X11 XVisual ID</i>, <i>Win32 PIXELFORMATDESCRIPTOR ID</i>, ...)</li> + * <li><code>EGL_CONFIG</code>: <i>EGL Config ID</i></li> + * </ul></li> + * </ul> + * </p> + * Note: <code>INTRINSIC</code> and <code>NATIVE</code> are always handled, + * but may result in {@link #VID_UNDEFINED}. The latter is true if + * the native value are actually undefined or the corresponding object is not + * mapped to a native visual object. + * + * @throws NativeWindowException if <code>type</code> is neither + * <code>INTRINSIC</code> nor <code>NATIVE</code> + * and does not match the native implementation. + */ + int getVisualID(VIDType type) throws NativeWindowException ; + + /** + * {@link #getVisualID(VIDType)} result indicating an undefined value, + * which could be cause by an unsupported query. + * <p> + * We assume the const value <code>0</code> doesn't reflect a valid native visual ID + * and is interpreted as <i>no value</i> on all platforms. + * This is currently true for Android, X11 and Windows. + * </p> + */ + static final int VID_UNDEFINED = 0; + + /** Comparing {@link VIDType#NATIVE} */ + public static class VIDComparator implements Comparator<VisualIDHolder> { + private final VIDType type; + + public VIDComparator(final VIDType type) { + this.type = type; + } + + @Override + public int compare(final VisualIDHolder vid1, final VisualIDHolder vid2) { + final int id1 = vid1.getVisualID(type); + final int id2 = vid2.getVisualID(type); + + if(id1 > id2) { + return 1; + } else if(id1 < id2) { + return -1; + } + return 0; + } + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/WindowClosingProtocol.java b/src/nativewindow/classes/com/jogamp/nativewindow/WindowClosingProtocol.java new file mode 100644 index 000000000..f4f8a02e1 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/WindowClosingProtocol.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.nativewindow; + +/** + * Protocol for handling window closing events. + * <p> + * The implementation shall obey either the user value set by this interface,<br> + * an underlying toolkit set user value or it's default, eg. {@link WindowClosingMode#DO_NOTHING_ON_CLOSE DO_NOTHING_ON_CLOSE} within an AWT environment.<br> + * If none of the above determines the operation, + * this protocol default behavior {@link WindowClosingMode#DISPOSE_ON_CLOSE DISPOSE_ON_CLOSE} shall be used.</p> + */ +public interface WindowClosingProtocol { + + /** + * Window closing mode if triggered by toolkit close operation. + */ + public enum WindowClosingMode { + /** + * Do nothing on native window close operation.<br> + * This is the default behavior within an AWT environment. + */ + DO_NOTHING_ON_CLOSE, + + /** + * Dispose resources on native window close operation.<br> + * This is the default behavior in case no underlying toolkit defines otherwise. + */ + DISPOSE_ON_CLOSE; + } + + + /** + * @return the current close operation value + * @see WindowClosingMode#DISPOSE_ON_CLOSE + * @see WindowClosingMode#DO_NOTHING_ON_CLOSE + */ + WindowClosingMode getDefaultCloseOperation(); + + /** + * @param op the new close operation value + * @return the previous close operation value + * @see WindowClosingMode#DISPOSE_ON_CLOSE + * @see WindowClosingMode#DO_NOTHING_ON_CLOSE + */ + WindowClosingMode setDefaultCloseOperation(WindowClosingMode op); +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/package.html b/src/nativewindow/classes/com/jogamp/nativewindow/package.html new file mode 100644 index 000000000..1fe52eea4 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/package.html @@ -0,0 +1,101 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> + <title>NativeWindow Specification Overview</title> +</head> + <body> + +<h2><i>NativeWindow Protocol</i> Specification Overview</h2> + +<h3>Preface</h3> + This specification, an optional set of packages, describing a <i>protocol</i> for a + <i>native windowing interface</i> binding to Java(TM).<br> + Currently specified <i>native windowing systems</i> are: + <ul> + <li> EGL/OpenKODE Windowing System</li> + <li> X11 Windowing System</li> + <li> Microsoft Windows</li> + <li> Apple MacOSX</li> + <li> Java's AWT</li> + </ul> + <br> + However, any other native windowing system may be added to the implementation, + using a generic string identifier and an optional specialisation of: + <ul> + <li>{@link com.jogamp.nativewindow.AbstractGraphicsDevice AbstractGraphicsDevice}, + <p>Shall return the new string identifier with {@link com.jogamp.nativewindow.AbstractGraphicsDevice#getType() getType()}</p></li> + <li>{@link com.jogamp.nativewindow.AbstractGraphicsScreen AbstractGraphicsScreen}</li> + <li>{@link com.jogamp.nativewindow.AbstractGraphicsConfiguration AbstractGraphicsConfiguration}</li> + </ul> + <p>The implementor has to provide the following:</p> + <ul> + <li> The specialisation of the abstract class {@link com.jogamp.nativewindow.NativeWindowFactory NativeWindowFactory} + <p>shall be registered with {@link com.jogamp.nativewindow.NativeWindowFactory#registerFactory NativeWindowFactory.registerFactory(..)}.</p></li> + + <li> The specialisation of the abstract class {@link com.jogamp.nativewindow.GraphicsConfigurationFactory GraphicsConfigurationFactory} + <p>shall be registered with {@link com.jogamp.nativewindow.GraphicsConfigurationFactory#registerFactory GraphicsConfigurationFactory.registerFactory(..)}.</p></li> + </ul> + <p>This protocol <i>does not</i> describe how to <i>create</i> native windows, but how to <i>bind</i> a native surface to an implementation of + and window to an implementation of {@link com.jogamp.nativewindow.NativeSurface NativeSurface}.</p> + <p>{@link com.jogamp.nativewindow.NativeWindow NativeWindow} specializes the NativeSurface.</p> + <p>However, an implementation of this protocol (e.g. {@link com.jogamp.newt}) may support the creation.</p> + +<h3>Dependencies</h3> + This binding has dependencies to the following: + <ul> + <li> Either of the following Java implementations: + <ul> + <li> <a href="http://docs.oracle.com/javase/6/docs/api/">Java SE 1.6 or later</a> </li> + <li> A mobile JavaVM with language 1.6 support, ie: + <ul> + <li> <a href="http://developer.android.com/reference/packages.html">Android API Level 9 (Version 2.3)</a> </li> + <li> <a href="http://jamvm.sourceforge.net/">JamVM</a> </li> + </ul> + with + <ul> + <li> <a href="http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/package-summary.html"> Java 1.4 <i>java.nio</i> implementation</a> </li> + </ul></li> + </ul></li> + </ul> + <br> + +<h3>Package Structure</h3> + The packages defined by this specification include: +<ul> + <li>The <b>com.jogamp.nativewindow</b> package + <p>This package contains Java bindings for a native windowing system.</p> + <p>Subsequent packages contain marker type classes, containing native characteristics of the windowing system.</p> + <ul> + <li>The <b>com.jogamp.nativewindow.awt</b> package + <p>This sub package contains classes to cover the native characteristics of the AWT windowing system.</p></li> + + <li>The <b>com.jogamp.nativewindow.x11</b> package + <p>This sub package contains classes to cover the native characteristics of the X11 windowing system.</p></li> + + <li>The <b>com.jogamp.nativewindow.windows</b> package + <p>This sub package contains classes to cover the native characteristics of the Windows windowing system.</p></li> + + <li>The <b>com.jogamp.nativewindow.macosx</b> package + <p>This sub package contains classes to cover the native characteristics of the MacOSX windowing system.</p></li> + + <li>The <b>com.jogamp.nativewindow.egl</b> package + <p>This sub package contains classes to cover the native characteristics of the EGL/OpenKODE windowing system.</p></li> + </ul></li> +</ul> + +<h3>Factory Model</h3> +<p>Running on a platform with a supported windowing system, the factory model shall be used +to instantiate a native window, see {@link com.jogamp.nativewindow.NativeWindowFactory NativeWindowFactory}.</p> + +<h3>Revision History</h3> + +<ul> +<li> Early Draft Review, June 2009</li> +<li> 2.0.0 Maintenance Release, February 2011</li> +<li> 2.0.2 Major Release, July 18th 2013</li> +</ul> + <br> + <br> + <br> +</body> +</html> diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/Dimension.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/Dimension.java new file mode 100644 index 000000000..28c5dd90e --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/Dimension.java @@ -0,0 +1,128 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright (c) 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.nativewindow.util; + +public class Dimension implements Cloneable, DimensionImmutable { + int width; + int height; + + public Dimension() { + this(0, 0); + } + + public Dimension(final int[] size) { + this(size[0], size[1]); + } + + public Dimension(final int width, final int height) { + if(width<0 || height<0) { + throw new IllegalArgumentException("width and height must be within: ["+0+".."+Integer.MAX_VALUE+"]"); + } + this.width=width; + this.height=height; + } + + @Override + public Object cloneMutable() { + return clone(); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + @Override + public final int getWidth() { return width; } + @Override + public final int getHeight() { return height; } + + public final void set(final int width, final int height) { + this.width = width; + this.height = height; + } + public final void setWidth(final int width) { + this.width = width; + } + public final void setHeight(final int height) { + this.height = height; + } + public final Dimension scale(final int s) { + width *= s; + height *= s; + return this; + } + public final Dimension add(final Dimension pd) { + width += pd.width ; + height += pd.height ; + return this; + } + + @Override + public String toString() { + return width + " x " + height; + } + + @Override + public int compareTo(final DimensionImmutable d) { + final int tsq = width*height; + final int xsq = d.getWidth()*d.getHeight(); + + if(tsq > xsq) { + return 1; + } else if(tsq < xsq) { + return -1; + } + return 0; + } + + @Override + public boolean equals(final Object obj) { + if(this == obj) { return true; } + if (obj instanceof Dimension) { + final Dimension p = (Dimension)obj; + return height == p.height && + width == p.width ; + } + return false; + } + + @Override + public int hashCode() { + // 31 * x == (x << 5) - x + final int hash = 31 + width; + return ((hash << 5) - hash) + height; + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/DimensionImmutable.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/DimensionImmutable.java new file mode 100644 index 000000000..6de77a716 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/DimensionImmutable.java @@ -0,0 +1,68 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright (c) 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.nativewindow.util; + +import com.jogamp.common.type.WriteCloneable; + +/** Immutable Dimension Interface, consisting of it's read only components:<br> + * <ul> + * <li><code>width</code></li> + * <li><code>height</code></li> + * </ul> + */ +public interface DimensionImmutable extends WriteCloneable, Comparable<DimensionImmutable> { + + int getHeight(); + + int getWidth(); + + /** + * <p> + * Compares square of size. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final DimensionImmutable d); + + /** + * Checks whether two dimensions objects are equal. Two instances + * of <code>DimensionReadOnly</code> are equal if two components + * <code>height</code> and <code>width</code> are equal. + * @return <code>true</code> if the two dimensions are equal; + * otherwise <code>false</code>. + */ + @Override + boolean equals(Object obj); + + @Override + int hashCode(); + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/Insets.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/Insets.java new file mode 100644 index 000000000..205e18346 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/Insets.java @@ -0,0 +1,136 @@ +/** + * Copyright 2011 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.util; + +/** + * Mutable insets representing rectangular window decoration insets on all four edges + * in window units. + */ +public class Insets implements Cloneable, InsetsImmutable { + static final InsetsImmutable zeroInsets = new Insets(); + public static final InsetsImmutable getZero() { return zeroInsets; } + + private int l, r, t, b; + + public Insets() { + this(0, 0, 0, 0); + } + + public Insets(final int left, final int right, final int top, final int bottom) { + this.l=left; + this.r=right; + this.t=top; + this.b=bottom; + } + + @Override + public Object cloneMutable() { + return clone(); + } + + @Override + protected Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + @Override + public final int getLeftWidth() { return l; } + @Override + public final int getRightWidth() { return r; } + @Override + public final int getTotalWidth() { return l + r; } + @Override + public final int getTopHeight() { return t; } + @Override + public final int getBottomHeight() { return b; } + @Override + public final int getTotalHeight() { return t + b; } + + /** + * Set the inset values of this instance in window units. + * @param left left inset width in window units. + * @param right right inset width in window units. + * @param top top inset width in window units. + * @param bottom bottom inset width in window units. + */ + public final void set(final int left, final int right, final int top, final int bottom) { + l = left; r = right; t = top; b = bottom; + } + /** + * Set the left inset value of this instance in window units. + * @param left left inset width in window units. + */ + public final void setLeftWidth(final int left) { l = left; } + /** + * Set the right inset value of this instance in window units. + * @param right right inset width in window units. + */ + public final void setRightWidth(final int right) { r = right; } + /** + * Set the top inset value of this instance in window units. + * @param top top inset width in window units. + */ + public final void setTopHeight(final int top) { t = top; } + /** + * Set the bottom inset value of this instance in window units. + * @param bottom bottom inset width in window units. + */ + public final void setBottomHeight(final int bottom) { b = bottom; } + + @Override + public boolean equals(final Object obj) { + if(this == obj) { return true; } + if (obj instanceof Insets) { + final Insets insets = (Insets)obj; + return (r == insets.r) && (l == insets.l) && + (b == insets.b) && (t == insets.t); + } + return false; + } + + @Override + public int hashCode() { + final int sum1 = l + b; + final int sum2 = t + r; + final int val1 = sum1 * (sum1 + 1)/2 + l; + final int val2 = sum2 * (sum2 + 1)/2 + r; + final int sum3 = val1 + val2; + return sum3 * (sum3 + 1)/2 + val2; + } + + @Override + public String toString() { + return "[ l "+l+", r "+r+" - t "+t+", b "+b+" - "+getTotalWidth()+"x"+getTotalHeight()+"]"; + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/InsetsImmutable.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/InsetsImmutable.java new file mode 100644 index 000000000..e626a507e --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/InsetsImmutable.java @@ -0,0 +1,71 @@ +/** + * Copyright 2011 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.util; + +import com.jogamp.common.type.WriteCloneable; + +/** + * Immutable insets representing rectangular window decoration insets on all four edges + * in window units. + */ +public interface InsetsImmutable extends WriteCloneable { + + /** @return left inset width in window units. */ + int getLeftWidth(); + + /** @return right inset width in window units. */ + int getRightWidth(); + + /** @return total width in window units, ie. <code>left_width + right_width</code> */ + int getTotalWidth(); + + /** @return top inset height in window units. */ + int getTopHeight(); + + /** @return bottom inset height in window units. */ + int getBottomHeight(); + + /** @return total height in window units, ie. <code>top_height + bottom_height</code> */ + int getTotalHeight(); + + /** + * Checks whether two rect objects are equal. Two instances + * of <code>Insets</code> are equal if the four integer values + * of the fields <code>left</code>, <code>right</code>, + * <code>top</code>, and <code>bottom</code> are all equal. + * @return <code>true</code> if the two Insets are equal; + * otherwise <code>false</code>. + */ + @Override + boolean equals(Object obj); + + @Override + int hashCode(); + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelFormat.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelFormat.java new file mode 100644 index 000000000..8b1e91564 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelFormat.java @@ -0,0 +1,739 @@ +/** + * Copyright (c) 2014 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.util; + +import java.util.Arrays; + +import com.jogamp.common.util.IntBitfield; + +/** + * Basic pixel formats + * <p> + * Notation follows OpenGL notation, i.e. + * name consist of all it's component names + * followed by their bit size. + * </p> + * <p> + * Order of component names is from lowest-bit to highest-bit. + * </p> + * <p> + * In case component-size is 1 byte (e.g. OpenGL data-type GL_UNSIGNED_BYTE), + * component names are ordered from lowest-byte to highest-byte. + * Note that OpenGL applies special interpretation if + * data-type is e.g. GL_UNSIGNED_8_8_8_8_REV or GL_UNSIGNED_8_8_8_8_REV. + * </p> + * <p> + * PixelFormat can be converted to OpenGL GLPixelAttributes + * via + * <pre> + * GLPixelAttributes glpa = GLPixelAttributes.convert(PixelFormat pixFmt, GLProfile glp); + * </pre> + * </p> + * <p> + * See OpenGL Specification 4.3 - February 14, 2013, Core Profile, + * Section 8.4.4 Transfer of Pixel Rectangles, p. 161-174. + * </ul> + * + * </p> + */ +public enum PixelFormat { + /** + * Stride is 8 bits, 8 bits per pixel, 1 component of 8 bits. + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_ALPHA (< GL3), GL_RED (>= GL3), data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: <i>none</i></li> + * </ul> + * </p> + */ + LUMINANCE(new CType[]{ CType.Y }, 1, 8, 8), + + /** + * Stride is 16 bits, 16 bits per pixel, 3 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0x1F << 0</li> + * <li>G: 0x3F << 5</li> + * <li>B: 0x1F << 11</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5_REV</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + RGB565(new CType[]{ CType.R, CType.G, CType.B }, + new int[]{ 0x1F, 0x3F, 0x1F }, + new int[]{ 0, 5, 5+6 }, + 16 ), + + /** + * Stride is 16 bits, 16 bits per pixel, 3 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0x1F << 0</li> + * <li>G: 0x3F << 5</li> + * <li>R: 0x1F << 11</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + BGR565(new CType[]{ CType.B, CType.G, CType.R}, + new int[]{ 0x1F, 0x3F, 0x1F }, + new int[]{ 0, 5, 5+6 }, + 16 ), + + /** + * Stride is 16 bits, 16 bits per pixel, 4 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0x1F << 0</li> + * <li>G: 0x1F << 5</li> + * <li>B: 0x1F << 10</li> + * <li>A: 0x01 << 15</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_1_5_5_5_REV</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + RGBA5551(new CType[]{ CType.R, CType.G, CType.B, CType.A}, + new int[]{ 0x1F, 0x1F, 0x1F, 0x01 }, + new int[]{ 0, 5, 5+5, 5+5+5 }, + 16 ), + + /** + * Stride is 16 bits, 16 bits per pixel, 4 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>A: 0x01 << 0</li> + * <li>B: 0x1F << 1</li> + * <li>G: 0x1F << 6</li> + * <li>R: 0x1F << 11</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_5_5_5_1</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + ABGR1555(new CType[]{ CType.A, CType.B, CType.G, CType.R }, + new int[]{ 0x01, 0x1F, 0x1F, 0x1F }, + new int[]{ 0, 1, 1+5, 1+5+5 }, + 16 ), + + /** + * Stride 24 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>B: 0xFF << 16</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + RGB888(new CType[]{ CType.R, CType.G, CType.B }, 3, 8, 24), + + /** + * Stride is 24 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>R: 0xFF << 16</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_BGR (>= GL2), data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_3BYTE_BGR TYPE_3BYTE_BGR}</li> + * </ul> + * </p> + */ + BGR888(new CType[]{ CType.B, CType.G, CType.R }, 3, 8, 24), + + /** + * Stride is 32 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>B: 0xFF << 16</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE, with alpha discarded!</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_BGR TYPE_INT_BGR}</li> + * </ul> + * </p> + */ + RGBx8888(new CType[]{ CType.R, CType.G, CType.B }, 3, 8, 32), + + /** + * Stride is 32 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>R: 0xFF << 16</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE - with alpha discarded!</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_RGB TYPE_INT_RGB}</li> + * </ul> + * </p> + */ + BGRx8888(new CType[]{ CType.B, CType.G, CType.R }, 3, 8, 32), + + /** + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>B: 0xFF << 16</li> + * <li>A: 0xFF << 24</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: <i>None</i></li> + * <li>PointerIcon: OSX (NSBitmapImageRep)</li> + * <li>Window Icon: OSX (NSBitmapImageRep)</li> + * <li>PNGJ: Scanlines</li> + * </ul> + * </p> + */ + RGBA8888(new CType[]{ CType.R, CType.G, CType.B, CType.A }, 4, 8, 32), + + /** + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>A: 0xFF << 0</li> + * <li>B: 0xFF << 8</li> + * <li>G: 0xFF << 16</li> + * <li>R: 0xFF << 24</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_INT_8_8_8_8</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}</li> + * </ul> + * </p> + */ + ABGR8888(new CType[]{ CType.A, CType.B, CType.G, CType.R }, 4, 8, 32), + + /** + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>A: 0xFF << 0</li> + * <li>R: 0xFF << 8</li> + * <li>G: 0xFF << 16</li> + * <li>B: 0xFF << 24</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_INT_8_8_8_8</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + ARGB8888(new CType[]{ CType.A, CType.R, CType.G, CType.B }, 4, 8, 32), + + /** + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>R: 0xFF << 16</li> + * <li>A: 0xFF << 24</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_ARGB TYPE_INT_ARGB}</li> + * <li>PointerIcon: X11 (XCURSOR), Win32, AWT</li> + * <li>Window Icon: X11, Win32</li> + * </ul> + * </p> + */ + BGRA8888(new CType[]{ CType.B, CType.G, CType.R, CType.A }, 4, 8, 32); + + /** Unique {@link Composition Pixel Composition}, i.e. layout of its components. */ + public final Composition comp; + + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link Composition#componentBitMask()}. + * @param componentCount number of components + * @param bpc bits per component + * @param bitStride stride bits to next pixel + */ + private PixelFormat(final CType[] componentOrder, final int componentCount, final int bpc, final int bitStride) { + this.comp = new PackedComposition(componentOrder, componentCount, bpc, bitStride); + } + + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link Composition#componentBitMask()}. + * @param componentMask bit-mask of of all components, see {@link Composition##componentBitMask()}. + * @param componentBitShift bit-shift of all components, see {@link Composition##componentBitMask()}. + * @param bitStride stride bits to next pixel + */ + private PixelFormat(final CType[] componentOrder, final int[] componentMask, final int[] componentBitShift, final int bitStride) { + this.comp = new PackedComposition(componentOrder, componentMask, componentBitShift, bitStride); + } + + /** + * Returns the unique matching {@link PixelFormat} of the given {@link Composition} + * or {@code null} if none is available. + */ + public static PixelFormat valueOf(final Composition comp) { + final PixelFormat[] all = PixelFormat.values(); + for(int i=all.length-1; i>=0; i--) { + final PixelFormat pf = all[i]; + if( comp.hashCode() == pf.comp.hashCode() && comp.equals(pf.comp) ) { + return pf; + } + } + return null; + } + + /** Component types */ + public static enum CType { + /** Red component */ + R, + /** Green component */ + G, + /** Blue component */ + B, + /** Alpha component */ + A, + /** Luminance component, e.g. grayscale or Y of YUV */ + Y, + /** U component of YUV */ + U, + /** V component of YUV */ + V; + } + + /** + * Pixel composition, i.e. layout of its components. + */ + public static interface Composition { + /** {@value} */ + public static final int UNDEF = -1; + + /** + * Returns {@code true} if all components are of same bit-size, e.g. {@link PixelFormat#RGBA8888 RGBA8888}, + * otherwise {@code false}, e.g. {@link PixelFormat#RGBA5551 RGBA5551} + */ + boolean isUniform(); + + /** + * Returns {@code true} if all components are packed, i.e. interleaved, e.g. {@link PixelFormat#RGBA8888 RGBA8888}, + * otherwise {@code false}. + */ + boolean isInterleaved(); + + /** Number of components per pixel, e.g. 3 for {@link PixelFormat#RGBx8888 RGBx8888}. */ + int componenCount(); + /** Number of bits per pixel, e.g. 24 bits for {@link PixelFormat#RGBx8888 RGBx8888}. */ + int bitsPerPixel(); + /** + * Bit distance between pixels. + * <p> + * For packed pixels e.g. 32 bits for {@link PixelFormat#RGBx8888 RGBx8888}. + * </p> + */ + int bitStride(); + /** Number of bytes per pixel, i.e. packed {@link #bitStride()} in bytes, e.g. 4 for {@link PixelFormat#RGBx8888 RGBx8888}. */ + int bytesPerPixel(); + /** + * Returns the {@link CType Component type} order of all components, see {@link #componentBitMask()}. + */ + CType[] componentOrder(); + /** + * Returns the index of given {@link CType} within {@link #componentOrder()}, -1 if not exists. + */ + int find(final PixelFormat.CType s); + /** + * Returns the un-shifted bit-mask of all components. + * <p> + * Components mask is returned in the order Low-Index to High-Index, e.g.: + * <ul> + * <li>{@link PixelFormat#RGB565 RGB565}: 0: R 0x1F, 1: G 0x3F, 2: B 0x1F</li> + * <li>{@link PixelFormat#RGBA5551 RGBA5551}: 0: R 0x1F, 1: G 0x1F, 2: B 0x1F, 3: A 0x01</li> + * <li>{@link PixelFormat#RGBA8888 RGBA8888}: 0: R 0xFF, 1: G 0xFF, 2: B 0xFF, 3: A 0xFF</li> + * </ul> + * </p> + * <p> + */ + int[] componentBitMask(); + /** + * Returns the number of bits of all components, see {@link #componentBitMask()}. + */ + int[] componentBitCount(); + /** + * Returns the bit-shift of all components, see {@link #componentBitMask()}. + */ + int[] componentBitShift(); + + /** + * Decodes a component from the shifted pixel data with a {@link #bytesPerPixel()} of up to 32bit. + * @param shifted complete pixel encoded into on 32bit integer + * @param cIdx the desired component index + * @return the decoded component value + */ + int decodeSingleI32(final int shifted, final int cIdx); + /** + * Decodes a component from the shifted pixel data with a {@link #bytesPerPixel()} of up to 64bit. + * @param shifted complete pixel encoded into on 64bit integer + * @param cIdx the desired component index + * @return the decoded component value + */ + int decodeSingleI64(final long shifted, final int cIdx); + + int encodeSingleI32(final int norm, final int cIdx); + long encodeSingleI64(final int norm, final int cIdx); + + int encode3CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32); + int encode4CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32, final int c4NormI32); + + int encodeSingleI8(final byte normalI8, final int cIdx); + int encode3CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8); + int encode4CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8, final byte c4NormI8); + + float toFloat(final int i32, final int cIdx, final boolean i32Shifted); + int fromFloat(final float f, final int cIdx, final boolean shiftResult); + + int defaultValue(final int cIdx, final boolean shiftResult); + + /** + * Returns cached immutable hash value, see {@link Object#hashCode()}. + */ + int hashCode(); + /** + * Returns {@link Object#equals(Object)} + */ + boolean equals(final Object o); + + /** + * Returns {@link Object#toString()}. + */ + String toString(); + } + + /** + * Packed pixel composition, see {@link Composition}. + * <p> + * Components are interleaved, i.e. packed. + * </p> + */ + public static class PackedComposition implements Composition { + private final CType[] compOrder; + private final int[] compMask; + private final int[] compBitCount; + private final int[] compBitShift; + private final int bitsPerPixel; + private final int bitStride; + private final boolean uniform; + private final int hashCode; + + public final String toString() { + return String.format("PackedComp[order %s, stride %d, bpp %d, uni %b, comp %d: %s]", + Arrays.toString(compOrder), bitStride, bitsPerPixel, uniform, + compMask.length, toHexString(compBitCount, compMask, compBitShift)); + } + + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link #componentBitMask()}. + * @param componentCount number of components + * @param bpc bits per component + * @param bitStride stride bits to next pixel + */ + public PackedComposition(final CType[] componentOrder, final int componentCount, final int bpc, final int bitStride) { + this.compOrder = componentOrder; + this.compMask = new int[componentCount]; + this.compBitShift = new int[componentCount]; + this.compBitCount = new int[componentCount]; + final int compMask = ( 1 << bpc ) - 1; + for(int i=0; i<componentCount; i++) { + this.compMask[i] = compMask; + this.compBitShift[i] = bpc * i; + this.compBitCount[i] = bpc; + } + this.uniform = true; + this.bitsPerPixel = bpc * componentCount; + this.bitStride = bitStride; + if( this.bitStride < this.bitsPerPixel ) { + throw new IllegalArgumentException(String.format("bit-stride %d < bitsPerPixel %d", this.bitStride, this.bitsPerPixel)); + } + this.hashCode = hashCodeImpl(); + } + + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link #componentBitMask()}. + * @param componentMask bit-mask of of all components, see {@link #componentBitMask()}. + * @param componentBitShift bit-shift of all components, see {@link #componentBitMask()}. + * @param bitStride stride bits to next pixel + */ + public PackedComposition(final CType[] componentOrder, final int[] componentMask, final int[] componentBitShift, final int bitStride) { + this.compOrder = componentOrder; + this.compMask = componentMask; + this.compBitShift = componentBitShift; + this.compBitCount = new int[componentMask.length]; + int bpp = 0; + boolean uniform = true; + for(int i = componentMask.length-1; i>=0; i--) { + final int cmask = componentMask[i]; + final int bitCount = IntBitfield.getBitCount(cmask); + bpp += bitCount; + this.compBitCount[i] = bitCount; + if( i > 0 && uniform ) { + uniform = componentMask[i-1] == cmask; + } + } + this.uniform = uniform; + this.bitsPerPixel = bpp; + this.bitStride = bitStride; + if( this.bitStride < this.bitsPerPixel ) { + throw new IllegalArgumentException(String.format("bit-stride %d < bitsPerPixel %d", this.bitStride, this.bitsPerPixel)); + } + this.hashCode = hashCodeImpl(); + } + + @Override + public final boolean isUniform() { return uniform; } + /** + * {@inheritDoc} + * <p> + * Instances of {@link PackedComposition} returns {@code true}. + * </p> + */ + @Override + public final boolean isInterleaved() { return true; } + @Override + public final int componenCount() { return compMask.length; } + @Override + public final int bitsPerPixel() { return bitsPerPixel; } + @Override + public final int bitStride() { return bitStride; } + @Override + public final int bytesPerPixel() { return (7+bitStride)/8; } + @Override + public final CType[] componentOrder() { return compOrder; } + @Override + public final int find(final PixelFormat.CType s) { return PixelFormatUtil.find(s, compOrder, false /* mapRGB2Y */); } + @Override + public final int[] componentBitMask() { return compMask; } + @Override + public final int[] componentBitCount() { return compBitCount; } + @Override + public final int[] componentBitShift() { return compBitShift; } + + @Override + public final int decodeSingleI32(final int shifted, final int cIdx) { + return ( shifted >>> compBitShift[cIdx] ) & compMask[cIdx]; + } + @Override + public final int decodeSingleI64(final long shifted, final int cIdx) { + return ( (int)( 0xffffffffL & ( shifted >>> compBitShift[cIdx] ) ) ) & compMask[cIdx]; + } + @Override + public final int encodeSingleI32(final int norm, final int cIdx) { + return ( norm & compMask[cIdx] ) << compBitShift[cIdx] ; + } + @Override + public final long encodeSingleI64(final int norm, final int cIdx) { + return ( 0xffffffffL & ( norm & compMask[cIdx] ) ) << compBitShift[cIdx] ; + } + @Override + public final int encode3CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32) { + return ( c1NormI32 & compMask[0] ) << compBitShift[0] | + ( c2NormI32 & compMask[1] ) << compBitShift[1] | + ( c3NormI32 & compMask[2] ) << compBitShift[2] ; + } + @Override + public final int encode4CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32, final int c4NormI32) { + return ( c1NormI32 & compMask[0] ) << compBitShift[0] | + ( c2NormI32 & compMask[1] ) << compBitShift[1] | + ( c3NormI32 & compMask[2] ) << compBitShift[2] | + ( c4NormI32 & compMask[3] ) << compBitShift[3] ; + } + @Override + public final int encodeSingleI8(final byte normI8, final int cIdx) { + return ( normI8 & compMask[cIdx] ) << compBitShift[cIdx] ; + } + @Override + public final int encode3CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8) { + return ( c1NormI8 & compMask[0] ) << compBitShift[0] | + ( c2NormI8 & compMask[1] ) << compBitShift[1] | + ( c3NormI8 & compMask[2] ) << compBitShift[2] ; + } + @Override + public final int encode4CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8, final byte c4NormI8) { + return ( c1NormI8 & compMask[0] ) << compBitShift[0] | + ( c2NormI8 & compMask[1] ) << compBitShift[1] | + ( c3NormI8 & compMask[2] ) << compBitShift[2] | + ( c4NormI8 & compMask[3] ) << compBitShift[3] ; + } + + @Override + public final float toFloat(final int i32, final int cIdx, final boolean i32Shifted) { + if( i32Shifted ) { + return ( ( i32 >>> compBitShift[cIdx] ) & compMask[cIdx] ) / (float)( compMask[cIdx] ) ; + } else { + return ( i32 & compMask[cIdx] ) / (float)( compMask[cIdx] ) ; + } + } + @Override + public final int fromFloat(final float f, final int cIdx, final boolean shiftResult) { + final int v = (int)(f * compMask[cIdx] + 0.5f); + return shiftResult ? v << compBitShift[cIdx] : v; + } + + @Override + public final int defaultValue(final int cIdx, final boolean shiftResult) { + final int v = ( CType.A == compOrder[cIdx] || CType.Y == compOrder[cIdx] ) + ? compMask[cIdx] : 0; + return shiftResult ? v << compBitShift[cIdx] : v; + } + + @Override + public final int hashCode() { return hashCode; } + private final int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + bitStride; + hash = ((hash << 5) - hash) + bitsPerPixel; + hash = ((hash << 5) - hash) + compMask.length; + for(int i=compOrder.length-1; i>=0; i--) { + hash = ((hash << 5) - hash) + compOrder[i].ordinal(); + } + for(int i=compMask.length-1; i>=0; i--) { + hash = ((hash << 5) - hash) + compMask[i]; + } + for(int i=compBitShift.length-1; i>=0; i--) { + hash = ((hash << 5) - hash) + compBitShift[i]; + } + return hash; + } + + @Override + public final boolean equals(final Object obj) { + if(this == obj) { return true; } + if( obj instanceof PackedComposition ) { + final PackedComposition other = (PackedComposition) obj; + return bitStride == other.bitStride && + bitsPerPixel == other.bitsPerPixel && + Arrays.equals(compOrder, other.compOrder) && + Arrays.equals(compMask, other.compMask) && + Arrays.equals(compBitShift, other.compBitShift); + } else { + return false; + } + } + } + + private static String toHexString(final int[] bitCount, final int[] mask, final int[] shift) { + final StringBuilder sb = new StringBuilder(); + sb.append("["); + final int l = mask.length; + for(int i=0; i < l; i++) { + if(i > 0) { + sb.append(", "); + } + sb.append(bitCount[i]).append(": "). + append("0x").append(Integer.toHexString(mask[i])).append(" << ").append(shift[i]); + } + return sb.append("]").toString(); + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelFormatUtil.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelFormatUtil.java new file mode 100644 index 000000000..180f02d72 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelFormatUtil.java @@ -0,0 +1,600 @@ +/** + * Copyright (c) 2014 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.util; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.common.util.Bitstream; + +/** + * Pixel Rectangle Utilities. + * <p> + * All conversion methods are endian independent. + * </p> + */ +public class PixelFormatUtil { + private static boolean DEBUG = false; + + public static class ComponentMap { + /** + * Contains the source index for each destination index, + * length is {@link Composition#componenCount()} of destination. + */ + final int[] dst2src; + /** + * Contains the destination index for each source index, + * length is {@link Composition#componenCount()} of source. + */ + final int[] src2dst; + + /** + * Contains the source index of RGBA components. + */ + final int[] srcRGBA; + final boolean hasSrcRGB; + + public ComponentMap(final PixelFormat.Composition src, final PixelFormat.Composition dst) { + final int sCompCount = src.componenCount(); + final int dCompCount = dst.componenCount(); + final PixelFormat.CType[] sCompOrder = src.componentOrder(); + final PixelFormat.CType[] dCompOrder = dst.componentOrder(); + + dst2src = new int[dCompCount]; + for(int dIdx=0; dIdx<dCompCount; dIdx++) { + dst2src[dIdx] = PixelFormatUtil.find(dCompOrder[dIdx], sCompOrder, true); + } + src2dst = new int[sCompCount]; + for(int sIdx=0; sIdx<sCompCount; sIdx++) { + src2dst[sIdx] = PixelFormatUtil.find(sCompOrder[sIdx], dCompOrder, true); + } + srcRGBA = new int[4]; + srcRGBA[0] = PixelFormatUtil.find(PixelFormat.CType.R, sCompOrder, false); + srcRGBA[1] = PixelFormatUtil.find(PixelFormat.CType.G, sCompOrder, false); + srcRGBA[2] = PixelFormatUtil.find(PixelFormat.CType.B, sCompOrder, false); + srcRGBA[3] = PixelFormatUtil.find(PixelFormat.CType.A, sCompOrder, false); + hasSrcRGB = 0 <= srcRGBA[0] && 0 <= srcRGBA[1] && 0 <= srcRGBA[2]; + } + } + + public static final int find(final PixelFormat.CType s, + final PixelFormat.CType[] pool, final boolean mapRGB2Y) { + int i=pool.length-1; + while( i >= 0 && pool[i] != s) { i--; } + + if( 0 > i && mapRGB2Y && 1 == pool.length && pool[0] == PixelFormat.CType.Y && + ( PixelFormat.CType.R == s || + PixelFormat.CType.G == s || + PixelFormat.CType.B == s ) ) + { + // Special case, fallback for RGB mapping -> LUMINANCE/Y + return 0; + } else { + return i; + } + } + + /** + * Returns shifted bytes from the given {@code data} at given {@code offset} + * of maximal 4 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param offset byte offset of pixel {@code data} start + * @return the shifted 32bit integer value of the pixel + */ + public static int getShiftedI32(final int bytesPerPixel, final byte[] data, final int offset) { + if( bytesPerPixel <= 4 ) { + int shiftedI32 = 0; + for(int i=0; i<bytesPerPixel; i++) { + shiftedI32 |= ( 0xff & data[offset+i] ) << 8*i; + } + return shiftedI32; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4"); + } + } + /** + * Returns shifted bytes from the given {@code data} at given {@code offset} + * of maximal 8 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param offset byte offset of pixel {@code data} start + * @return the shifted 64bit integer value of the pixel + */ + public static long getShiftedI64(final int bytesPerPixel, final byte[] data, final int offset) { + if( bytesPerPixel <= 8 ) { + long shiftedI64 = 0; + for(int i=0; i<bytesPerPixel; i++) { + shiftedI64 |= ( 0xff & data[offset+i] ) << 8*i; + } + return shiftedI64; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8"); + } + } + /** + * Returns shifted bytes from the given {@code data} at current position + * of maximal 4 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged. + * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes. + * @return the shifted 32bit integer value of the pixel + */ + public static int getShiftedI32(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) { + if( bytesPerPixel <= 4 ) { + int shiftedI32 = 0; + if( retainDataPos ) { + final int offset = data.position(); + for(int i=0; i<bytesPerPixel; i++) { + shiftedI32 |= ( 0xff & data.get(offset+i) ) << 8*i; + } + } else { + for(int i=0; i<bytesPerPixel; i++) { + shiftedI32 |= ( 0xff & data.get() ) << 8*i; + } + } + return shiftedI32; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4"); + } + } + /** + * Returns shifted bytes from the given {@code data} at current position + * of maximal 8 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged. + * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes. + * @return the shifted 64bit integer value of the pixel + */ + public static long getShiftedI64(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) { + if( bytesPerPixel <= 8 ) { + long shiftedI64 = 0; + if( retainDataPos ) { + final int offset = data.position(); + for(int i=0; i<bytesPerPixel; i++) { + shiftedI64 |= ( 0xff & data.get(offset+i) ) << 8*i; + } + } else { + for(int i=0; i<bytesPerPixel; i++) { + shiftedI64 |= ( 0xff & data.get() ) << 8*i; + } + } + return shiftedI64; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8"); + } + } + + /** + * Returns the {@link PixelFormat} with reversed components of <code>fmt</code>. + * If no reversed {@link PixelFormat} is available, returns <code>fmt</code>. + */ + public static PixelFormat getReversed(final PixelFormat fmt) { + switch(fmt) { + case RGB565: + return PixelFormat.BGR565; + case BGR565: + return PixelFormat.RGB565; + case RGBA5551: + return PixelFormat.ABGR1555; + case ABGR1555: + return PixelFormat.RGBA5551; + case RGB888: + return PixelFormat.BGR888; + case BGR888: + return PixelFormat.RGB888; + case RGBA8888: + return PixelFormat.ABGR8888; + case ABGR8888: + return PixelFormat.RGBA8888; + case ARGB8888: + return PixelFormat.BGRA8888; + case BGRA8888: + return PixelFormat.ABGR8888; + default: + return fmt; + } + } + + public static int convertToInt32(final PixelFormat dst_fmt, final byte r, final byte g, final byte b, final byte a) { + switch(dst_fmt) { + case LUMINANCE: { + final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) * a ); + return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l ); + } + case RGB888: + return ( 0xff ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r ); + case BGR888: + return ( 0xff ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b ); + case RGBA8888: + return ( 0xff & a ) << 24 | ( 0xff & b ) << 16 | ( 0xff & g ) << 8 | ( 0xff & r ); + case ABGR8888: + return ( 0xff & r ) << 24 | ( 0xff & g ) << 16 | ( 0xff & b ) << 8 | ( 0xff & a ); + case ARGB8888: + return ( 0xff & b ) << 24 | ( 0xff & g ) << 16 | ( 0xff & r ) << 8 | ( 0xff & a ); + case BGRA8888: + return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b ); + default: + throw new InternalError("Unhandled format "+dst_fmt); + } + } + + public static int convertToInt32(final PixelFormat dst_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) { + final byte r, g, b, a; + switch(src_fmt) { + case LUMINANCE: + r = src.get(srcOff++); // R + g = r; // G + b = r; // B + a = (byte) 0xff; // A + break; + case RGB888: + r = src.get(srcOff++); // R + g = src.get(srcOff++); // G + b = src.get(srcOff++); // B + a = (byte) 0xff; // A + break; + case BGR888: + b = src.get(srcOff++); // B + g = src.get(srcOff++); // G + r = src.get(srcOff++); // R + a = (byte) 0xff; // A + break; + case RGBA8888: + r = src.get(srcOff++); // R + g = src.get(srcOff++); // G + b = src.get(srcOff++); // B + a = src.get(srcOff++); // A + break; + case ABGR8888: + a = src.get(srcOff++); // A + b = src.get(srcOff++); // B + g = src.get(srcOff++); // G + r = src.get(srcOff++); // R + break; + case ARGB8888: + a = src.get(srcOff++); // A + r = src.get(srcOff++); // R + g = src.get(srcOff++); // G + b = src.get(srcOff++); // B + break; + case BGRA8888: + b = src.get(srcOff++); // B + g = src.get(srcOff++); // G + r = src.get(srcOff++); // R + a = src.get(srcOff++); // A + break; + default: + throw new InternalError("Unhandled format "+src_fmt); + } + return convertToInt32(dst_fmt, r, g, b, a); + } + + public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final int src_pixel) { + final byte r, g, b, a; + switch(src_fmt) { + case LUMINANCE: + r = (byte) ( src_pixel ); // R + g = r; // G + b = r; // B + a = (byte) 0xff; // A + break; + case RGB888: + r = (byte) ( src_pixel ); // R + g = (byte) ( src_pixel >>> 8 ); // G + b = (byte) ( src_pixel >>> 16 ); // B + a = (byte) 0xff; // A + break; + case BGR888: + b = (byte) ( src_pixel ); // B + g = (byte) ( src_pixel >>> 8 ); // G + r = (byte) ( src_pixel >>> 16 ); // R + a = (byte) 0xff; // A + break; + case RGBA8888: + r = (byte) ( src_pixel ); // R + g = (byte) ( src_pixel >>> 8 ); // G + b = (byte) ( src_pixel >>> 16 ); // B + a = (byte) ( src_pixel >>> 24 ); // A + break; + case ABGR8888: + a = (byte) ( src_pixel ); // A + b = (byte) ( src_pixel >>> 8 ); // B + g = (byte) ( src_pixel >>> 16 ); // G + r = (byte) ( src_pixel >>> 24 ); // R + break; + case ARGB8888: + a = (byte) ( src_pixel ); // A + r = (byte) ( src_pixel >>> 8 ); // R + g = (byte) ( src_pixel >>> 16 ); // G + b = (byte) ( src_pixel >>> 24 ); // B + break; + case BGRA8888: + b = (byte) ( src_pixel ); // B + g = (byte) ( src_pixel >>> 8 ); // G + r = (byte) ( src_pixel >>> 16 ); // R + a = (byte) ( src_pixel >>> 24 ); // A + break; + default: + throw new InternalError("Unhandled format "+src_fmt); + } + return convertToInt32(dest_fmt, r, g, b, a); + } + + public static PixelRectangle convert(final PixelRectangle src, + final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented, + final boolean destIsDirect) { + final int width = src.getSize().getWidth(); + final int height = src.getSize().getHeight(); + final int bpp = destFmt.comp.bytesPerPixel(); + final int destStride; + if( 0 != ddestStride ) { + destStride = ddestStride; + } else { + destStride = bpp * width; + } + final int capacity = destStride*height; + final ByteBuffer destBB = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order()); + convert(src, destBB, destFmt, isGLOriented, destStride); + return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, destBB); + } + + /** + * @param src + * @param dst_bb {@link ByteBuffer} sink + * @param dst_fmt destination {@link PixelFormat} + * @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>, + * otherwise <i>origin at top left</i>. + * @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next. + * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width + * or {@code zero} for default stride. + * + * @throws IllegalStateException + * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid + */ + public static void convert(final PixelRectangle src, + final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, final int dst_lineStride) + throws IllegalStateException + { + convert(src.getSize().getWidth(), src.getSize().getHeight(), + src.getPixels(), src.getPixelformat(), src.isGLOriented(), src.getStride(), + dst_bb, dst_fmt, dst_glOriented, dst_lineStride); + } + + + /** + * @param width width of the to be converted pixel rectangle + * @param height height of the to be converted pixel rectangle + * @param src_bb {@link ByteBuffer} source + * @param src_fmt source {@link PixelFormat} + * @param src_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>, + * otherwise <i>origin at top left</i>. + * @param src_lineStride line stride in byte-size for source, i.e. byte count from one line to the next. + * Must be >= {@link PixelFormat.Composition#bytesPerPixel() src_fmt.comp.bytesPerPixel()} * width + * or {@code zero} for default stride. + * @param dst_bb {@link ByteBuffer} sink + * @param dst_fmt destination {@link PixelFormat} + * @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>, + * otherwise <i>origin at top left</i>. + * @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next. + * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width + * or {@code zero} for default stride. + * + * @throws IllegalStateException + * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid + */ + public static void convert(final int width, final int height, + final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, int src_lineStride, + final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, int dst_lineStride + ) throws IllegalStateException, IllegalArgumentException { + final PixelFormat.Composition src_comp = src_fmt.comp; + final PixelFormat.Composition dst_comp = dst_fmt.comp; + final int src_bpp = src_comp.bytesPerPixel(); + final int dst_bpp = dst_comp.bytesPerPixel(); + + if( 0 != src_lineStride ) { + if( src_lineStride < src_bpp * width ) { + throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d", + "source", src_lineStride, src_bpp, width)); + } + } else { + src_lineStride = src_bpp * width; + } + if( 0 != dst_lineStride ) { + if( dst_lineStride < dst_bpp * width ) { + throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d", + "destination", dst_lineStride, dst_bpp, width)); + } + } else { + dst_lineStride = dst_bpp * width; + } + + // final int src_comp_bitStride = src_comp.bitStride(); + final int dst_comp_bitStride = dst_comp.bitStride(); + final boolean vert_flip = src_glOriented != dst_glOriented; + final boolean fast_copy = src_comp.equals(dst_comp) && 0 == dst_comp_bitStride%8; + if( DEBUG ) { + System.err.println("XXX: size "+width+"x"+height+", fast_copy "+fast_copy); + System.err.println("XXX: SRC fmt "+src_fmt+", "+src_comp+", stride "+src_lineStride+", isGLOrient "+src_glOriented); + System.err.println("XXX: DST fmt "+dst_fmt+", "+dst_comp+", stride "+dst_lineStride+", isGLOrient "+dst_glOriented); + } + + if( fast_copy ) { + // Fast copy + for(int y=0; y<height; y++) { + int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride : y * src_lineStride; + int dst_off = dst_lineStride*y; + for(int x=0; x<width; x++) { + dst_bb.put(dst_off+0, src_bb.get(src_off+0)); // 1 + if( 2 <= dst_bpp ) { + dst_bb.put(dst_off+1, src_bb.get(src_off+1)); // 2 + if( 3 <= dst_bpp ) { + dst_bb.put(dst_off+2, src_bb.get(src_off+2)); // 3 + if( 4 <= dst_bpp ) { + dst_bb.put(dst_off+3, src_bb.get(src_off+3)); // 4 + } + } + } + src_off += src_bpp; + dst_off += dst_bpp; + } + } + } else { + // Conversion + final ComponentMap cmap = new ComponentMap(src_fmt.comp, dst_fmt.comp); + + final Bitstream.ByteBufferStream srcBBS = new Bitstream.ByteBufferStream(src_bb); + final Bitstream<ByteBuffer> srcBitStream = new Bitstream<ByteBuffer>(srcBBS, false /* outputMode */); + srcBitStream.setThrowIOExceptionOnEOF(true); + + final Bitstream.ByteBufferStream dstBBS = new Bitstream.ByteBufferStream(dst_bb); + final Bitstream<ByteBuffer> dstBitStream = new Bitstream<ByteBuffer>(dstBBS, true /* outputMode */); + dstBitStream.setThrowIOExceptionOnEOF(true); + + if( DEBUG ) { + System.err.println("XXX: cmap.dst2src "+Arrays.toString(cmap.dst2src)); + System.err.println("XXX: cmap.src2dst "+Arrays.toString(cmap.src2dst)); + System.err.println("XXX: cmap.srcRGBA "+Arrays.toString(cmap.srcRGBA)); + System.err.println("XXX: srcBitStream "+srcBitStream); + System.err.println("XXX: dstBitStream "+dstBitStream); + } + try { + for(int y=0; y<height; y++) { + final int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride * 8 : y * src_lineStride * 8; + // final int dst_off = dst_lineStride*8*y; + srcBitStream.position(src_off); + for(int x=0; x<width; x++) { + convert(cmap, dst_comp, dstBitStream, src_comp, srcBitStream); + } + // srcBitStream.skip(( src_lineStride * 8 ) - ( src_comp_bitStride * width )); + dstBitStream.skip(( dst_lineStride * 8 ) - ( dst_comp_bitStride * width )); + } + } catch(final IOException ioe) { + throw new RuntimeException(ioe); + } + if( DEBUG ) { + System.err.println("XXX: srcBitStream "+srcBitStream); + System.err.println("XXX: dstBitStream "+dstBitStream); + } + } + } + + public static void convert(final ComponentMap cmap, + final PixelFormat.Composition dstComp, + final Bitstream<ByteBuffer> dstBitStream, + final PixelFormat.Composition srcComp, + final Bitstream<ByteBuffer> srcBitStream) throws IllegalStateException, IOException { + final int sCompCount = srcComp.componenCount(); + final int dCompCount = dstComp.componenCount(); + final int[] sc = new int[sCompCount]; + final int[] dcDef = new int[dCompCount]; + final int[] srcCompBitCount = srcComp.componentBitCount(); + final int[] srcCompBitMask = srcComp.componentBitMask(); + final int[] dstCompBitCount = dstComp.componentBitCount(); + + // Fill w/ source values + for(int sIdx=0; sIdx<sCompCount; sIdx++) { + sc[sIdx] = srcBitStream.readBits31(srcCompBitCount[sIdx]) & srcCompBitMask[sIdx]; + } + srcBitStream.skip(srcComp.bitStride() - srcComp.bitsPerPixel()); + + // Cache missing defaults + for(int i=0; i<dCompCount; i++) { + dcDef[i] = dstComp.defaultValue(i, false); + } + + if( 1 == dCompCount && + PixelFormat.CType.Y == dstComp.componentOrder()[0] && + cmap.hasSrcRGB + ) + { + // RGB[A] -> Y conversion + final int r = sc[cmap.srcRGBA[0]]; + final int g = sc[cmap.srcRGBA[1]]; + final int b = sc[cmap.srcRGBA[2]]; + final float rF = srcComp.toFloat(r, cmap.srcRGBA[0], false); + final float gF = srcComp.toFloat(g, cmap.srcRGBA[1], false); + final float bF = srcComp.toFloat(b, cmap.srcRGBA[2], false); + final int a; + final float aF; + /** if( 0 <= cmap.srcRGBA[3] ) { // disable premultiplied-alpha + a = sc[cmap.srcRGBA[3]]; + aF = srcComp.toFloat(a, false, cmap.srcRGBA[3]); + } else */ { + a = 1; + aF = 1f; + } + final float lF = ( rF + gF + bF ) * aF / 3f; + final int v = dstComp.fromFloat(lF, 0, false); + + dstBitStream.writeBits31(dstCompBitCount[0], v); + dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel()); + if( DEBUG ) { + if( srcBitStream.position() <= 8*4 ) { + System.err.printf("convert: rgb[a] -> Y: rgb 0x%02X 0x%02X 0x%02X 0x%02X -> %f %f %f %f"+ + " -> %f -> dstC 0 0x%08X (%d bits: %s)%n", + r, g, b, a, + rF, gF, bF, aF, + lF, v, dstCompBitCount[0], Bitstream.toBinString(true, v, dstCompBitCount[0]) + ); + } + } + return; + } + + for(int dIdx=0; dIdx<dCompCount; dIdx++) { + int sIdx; + if( 0 <= ( sIdx = cmap.dst2src[dIdx] ) ) { + final float f = srcComp.toFloat(sc[sIdx], sIdx, false); + final int v = dstComp.fromFloat(f, dIdx, false); + dstBitStream.writeBits31(dstCompBitCount[dIdx], v); + if( DEBUG ) { + if( srcBitStream.position() <= 8*4 ) { + System.err.printf("convert: srcC %d: 0x%08X -> %f -> dstC %d 0x%08X (%d bits: %s)%n", + sIdx, sc[sIdx], f, dIdx, v, dstCompBitCount[dIdx], Bitstream.toBinString(true, v, dstCompBitCount[dIdx])); + } + } + } else { + dstBitStream.writeBits31(dstCompBitCount[dIdx], dcDef[dIdx]); + if( DEBUG ) { + if( srcBitStream.position() <= 8*4 ) { + System.err.printf("convert: srcC %d: undef -> dstC %d 0x%08X (%d bits: %s)%n", + sIdx, dIdx, dcDef[dIdx], dstCompBitCount[dIdx], Bitstream.toBinString(true, dcDef[dIdx], dstCompBitCount[dIdx])); + } + } + } + } + dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel()); + return; + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelRectangle.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelRectangle.java new file mode 100644 index 000000000..f58ba0ce2 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/PixelRectangle.java @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2014 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.util; + +import java.nio.ByteBuffer; + +/** + * Pixel Rectangle identified by it's {@link #hashCode()}. + * <p> + * The {@link #getPixels()} are assumed to be immutable. + * </p> + */ +public interface PixelRectangle { + /** + * <p> + * Computes a hash code over: + * <ul> + * <li>pixelformat</li> + * <li>size</li> + * <li>stride</li> + * <li>isGLOriented</li> + * <li>pixels</li> + * </ul> + * </p> + * <p> + * The hashCode shall be computed only once with first call + * and stored for later retrieval to enhance performance. + * </p> + * <p> + * {@inheritDoc} + * </p> + */ + @Override + int hashCode(); + + /** Returns the {@link PixelFormat}. */ + PixelFormat getPixelformat(); + + /** Returns the size, i.e. width and height. */ + DimensionImmutable getSize(); + + /** + * Returns stride in byte-size, i.e. byte count from one line to the next. + * <p> + * Must be >= {@link #getPixelformat()}.{@link PixelFormat#bytesPerPixel() bytesPerPixel()} * {@link #getSize()}.{@link DimensionImmutable#getWidth() getWidth()}. + * </p> + */ + int getStride(); + + /** + * Returns <code>true</code> if the memory is laid out in + * OpenGL's coordinate system, <i>origin at bottom left</i>. + * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>. + */ + public boolean isGLOriented(); + + /** Returns the pixels. */ + ByteBuffer getPixels(); + + @Override + String toString(); + + /** + * Generic PixelRectangle implementation + */ + public static class GenericPixelRect implements PixelRectangle { + protected final PixelFormat pixelformat; + protected final DimensionImmutable size; + protected final int strideInBytes; + protected final boolean isGLOriented; + protected final ByteBuffer pixels; + private int hashCode = 0; + private volatile boolean hashCodeComputed = false; + + /** + * + * @param pixelformat + * @param size + * @param strideInBytes stride in byte-size, i.e. byte count from one line to the next. + * If not zero, value must be >= <code>width * bytes-per-pixel</code>. + * If zero, stride is set to <code>width * bytes-per-pixel</code>. + * @param isGLOriented + * @param pixels + * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid. + * @throws IndexOutOfBoundsException if <code>pixels</code> has insufficient bytes left + */ + public GenericPixelRect(final PixelFormat pixelformat, final DimensionImmutable size, int strideInBytes, final boolean isGLOriented, final ByteBuffer pixels) + throws IllegalArgumentException, IndexOutOfBoundsException + { + if( 0 != strideInBytes ) { + if( strideInBytes < pixelformat.comp.bytesPerPixel() * size.getWidth()) { + throw new IllegalArgumentException("Invalid stride "+strideInBytes+", must be greater than bytesPerPixel "+pixelformat.comp.bytesPerPixel()+" * width "+size.getWidth()); + } + } else { + strideInBytes = pixelformat.comp.bytesPerPixel() * size.getWidth(); + } + final int reqBytes = strideInBytes * size.getHeight(); + if( pixels.limit() < reqBytes ) { + throw new IndexOutOfBoundsException("Dest buffer has insufficient bytes left, needs "+reqBytes+": "+pixels); + } + this.pixelformat = pixelformat; + this.size = size; + this.strideInBytes = strideInBytes; + this.isGLOriented = isGLOriented; + this.pixels = pixels; + } + + /** + * Copy ctor validating src. + * @param src + * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid. + * @throws IndexOutOfBoundsException if <code>pixels</code> has insufficient bytes left + */ + public GenericPixelRect(final PixelRectangle src) + throws IllegalArgumentException, IndexOutOfBoundsException + { + this(src.getPixelformat(), src.getSize(), src.getStride(), src.isGLOriented(), src.getPixels()); + } + + @Override + public int hashCode() { + if( !hashCodeComputed ) { // DBL CHECKED OK VOLATILE + synchronized (this) { + if( !hashCodeComputed ) { + // 31 * x == (x << 5) - x + int hash = pixelformat.comp.hashCode(); + hash = ((hash << 5) - hash) + size.hashCode(); + hash = ((hash << 5) - hash) + strideInBytes; + hash = ((hash << 5) - hash) + ( isGLOriented ? 1 : 0); + hashCode = ((hash << 5) - hash) + pixels.hashCode(); + hashCodeComputed = true; + } + } + } + return hashCode; + } + + @Override + public PixelFormat getPixelformat() { + return pixelformat; + } + + @Override + public DimensionImmutable getSize() { + return size; + } + + @Override + public int getStride() { + return strideInBytes; + } + + @Override + public boolean isGLOriented() { + return isGLOriented; + } + + @Override + public ByteBuffer getPixels() { + return pixels; + } + + @Override + public final String toString() { + return "PixelRect[obj 0x"+Integer.toHexString(super.hashCode())+", "+pixelformat+", "+size+", stride "+strideInBytes+", isGLOrient "+isGLOriented+", pixels "+pixels+"]"; + } + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java new file mode 100644 index 000000000..fc5465bbf --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/Point.java @@ -0,0 +1,190 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright (c) 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.nativewindow.util; + +public class Point implements Cloneable, PointImmutable { + int x; + int y; + + public Point(final int x, final int y) { + this.x=x; + this.y=y; + } + + public Point() { + this(0, 0); + } + + @Override + public Object cloneMutable() { + return clone(); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + @Override + public int compareTo(final PointImmutable d) { + final int sq = x*y; + final int xsq = d.getX()*d.getY(); + + if(sq > xsq) { + return 1; + } else if(sq < xsq) { + return -1; + } + return 0; + } + + @Override + public boolean equals(final Object obj) { + if(this == obj) { return true; } + if (obj instanceof Point) { + final Point p = (Point)obj; + return y == p.y && x == p.x; + } + return false; + } + + @Override + public final int getX() { + return x; + } + + @Override + public final int getY() { + return y; + } + + @Override + public int hashCode() { + // 31 * x == (x << 5) - x + int hash = 31 + x; + hash = ((hash << 5) - hash) + y; + return hash; + } + + @Override + public String toString() { + return x + " / " + y; + } + + public final void set(final int x, final int y) { this.x = x; this.y = y; } + public final void setX(final int x) { this.x = x; } + public final void setY(final int y) { this.y = y; } + + /** + * Translate this instance's x- and y-components, + * i.e. add the values of the given delta point to them. + * @param pd delta point + * @return this instance for scaling + */ + public final Point translate(final Point pd) { + x += pd.x ; + y += pd.y ; + return this; + } + + /** + * Translate this instance's x- and y-components, + * i.e. add the given deltas to them. + * @param dx delta for x + * @param dy delta for y + * @return this instance for scaling + */ + public final Point translate(final int dx, final int dy) { + x += dx ; + y += dy ; + return this; + } + + /** + * Scale this instance's x- and y-components, + * i.e. multiply them by the given scale factors. + * @param sx scale factor for x + * @param sy scale factor for y + * @return this instance for scaling + */ + public final Point scale(final int sx, final int sy) { + x *= sx ; + y *= sy ; + return this; + } + + /** + * Scale this instance's x- and y-components, + * i.e. multiply them by the given scale factors. + * <p> + * The product is rounded back to integer. + * </p> + * @param sx scale factor for x + * @param sy scale factor for y + * @return this instance for scaling + */ + public final Point scale(final float sx, final float sy) { + x = (int)(x * sx + 0.5f); + y = (int)(y * sy + 0.5f); + return this; + } + + /** + * Inverse scale this instance's x- and y-components, + * i.e. divide them by the given scale factors. + * @param sx inverse scale factor for x + * @param sy inverse scale factor for y + * @return this instance for scaling + */ + public final Point scaleInv(final int sx, final int sy) { + x /= sx ; + y /= sy ; + return this; + } + /** + * Inverse scale this instance's x- and y-components, + * i.e. divide them by the given scale factors. + * <p> + * The product is rounded back to integer. + * </p> + * @param sx inverse scale factor for x + * @param sy inverse scale factor for y + * @return this instance for scaling + */ + public final Point scaleInv(final float sx, final float sy) { + x = (int)(x / sx + 0.5f); + y = (int)(y / sy + 0.5f); + return this; + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/PointImmutable.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/PointImmutable.java new file mode 100644 index 000000000..59372f67d --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/PointImmutable.java @@ -0,0 +1,63 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright (c) 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.nativewindow.util; + +import com.jogamp.common.type.WriteCloneable; + +/** Immutable Point interface */ +public interface PointImmutable extends WriteCloneable, Comparable<PointImmutable> { + + int getX(); + + int getY(); + + /** + * <p> + * Compares the square of the position. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final PointImmutable d); + + /** + * Checks whether two points objects are equal. Two instances + * of <code>PointReadOnly</code> are equal if the two components + * <code>y</code> and <code>x</code> are equal. + * @return <code>true</code> if the two points are equal; + * otherwise <code>false</code>. + */ + @Override + public boolean equals(Object obj); + + @Override + public int hashCode(); + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/Rectangle.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/Rectangle.java new file mode 100644 index 000000000..33a1955e8 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/Rectangle.java @@ -0,0 +1,237 @@ +/** + * 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.nativewindow.util; + +import java.util.List; + +public class Rectangle implements Cloneable, RectangleImmutable { + int x; + int y; + int width; + int height; + + public Rectangle() { + this(0, 0, 0, 0); + } + + public Rectangle(final int x, final int y, final int width, final int height) { + this.x=x; + this.y=y; + this.width=width; + this.height=height; + } + + @Override + public Object cloneMutable() { + return clone(); + } + + @Override + protected Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + @Override + public final int getX() { return x; } + @Override + public final int getY() { return y; } + @Override + public final int getWidth() { return width; } + @Override + public final int getHeight() { return height; } + + public final void set(final int x, final int y, final int width, final int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + public final void set(final Rectangle s) { + this.x = s.x; + this.y = s.y; + this.width = s.width; + this.height = s.height; + } + public final void setX(final int x) { this.x = x; } + public final void setY(final int y) { this.y = y; } + public final void setWidth(final int width) { this.width = width; } + public final void setHeight(final int height) { this.height = height; } + + @Override + public final RectangleImmutable union(final RectangleImmutable r) { + return union(r.getX(), r.getY(), r.getX() + r.getWidth(), r.getY() + r.getHeight()); + } + @Override + public final RectangleImmutable union(final int rx1, final int ry1, final int rx2, final int ry2) { + final int x1 = Math.min(x, rx1); + final int y1 = Math.min(y, ry1); + final int x2 = Math.max(x + width, rx2); + final int y2 = Math.max(y + height, ry2); + return new Rectangle(x1, y1, x2 - x1, y2 - y1); + } + /** + * Calculates the union of the given rectangles, stores it in this instance and returns this instance. + * @param rectangles given list of rectangles + * @return this instance holding the union of given rectangles. + */ + public final Rectangle union(final List<RectangleImmutable> rectangles) { + int x1=Integer.MAX_VALUE, y1=Integer.MAX_VALUE; + int x2=Integer.MIN_VALUE, y2=Integer.MIN_VALUE; + for(int i=rectangles.size()-1; i>=0; i--) { + final RectangleImmutable vp = rectangles.get(i); + x1 = Math.min(x1, vp.getX()); + x2 = Math.max(x2, vp.getX() + vp.getWidth()); + y1 = Math.min(y1, vp.getY()); + y2 = Math.max(y2, vp.getY() + vp.getHeight()); + } + set(x1, y1, x2 - x1, y2 - y1); + return this; + } + + @Override + public final RectangleImmutable intersection(final RectangleImmutable r) { + return intersection(r.getX(), r.getY(), r.getX() + r.getWidth(), r.getY() + r.getHeight()); + } + @Override + public final RectangleImmutable intersection(final int rx1, final int ry1, final int rx2, final int ry2) { + final int x1 = Math.max(x, rx1); + final int y1 = Math.max(y, ry1); + final int x2 = Math.min(x + width, rx2); + final int y2 = Math.min(y + height, ry2); + final int ix, iy, iwidth, iheight; + if( x2 < x1 ) { + ix = 0; + iwidth = 0; + } else { + ix = x1; + iwidth = x2 - x1; + } + if( y2 < y1 ) { + iy = 0; + iheight = 0; + } else { + iy = y1; + iheight = y2 - y1; + } + return new Rectangle (ix, iy, iwidth, iheight); + } + @Override + public final float coverage(final RectangleImmutable r) { + final RectangleImmutable isect = intersection(r); + final float sqI = isect.getWidth()*isect.getHeight(); + final float sqT = width*height; + return sqI / sqT; + } + + /** + * Scale this instance's components, + * i.e. multiply them by the given scale factors. + * @param sx scale factor for x + * @param sy scale factor for y + * @return this instance for scaling + */ + public final Rectangle scale(final int sx, final int sy) { + x *= sx ; + y *= sy ; + width *= sx ; + height *= sy ; + return this; + } + + /** + * Inverse scale this instance's components, + * i.e. divide them by the given scale factors. + * @param sx inverse scale factor for x + * @param sy inverse scale factor for y + * @return this instance for scaling + */ + public final Rectangle scaleInv(final int sx, final int sy) { + x /= sx ; + y /= sy ; + width /= sx ; + height /= sy ; + return this; + } + + @Override + public int compareTo(final RectangleImmutable d) { + { + final int sq = width*height; + final int xsq = d.getWidth()*d.getHeight(); + + if(sq > xsq) { + return 1; + } else if(sq < xsq) { + return -1; + } + } + { + final int sq = x*y; + final int xsq = d.getX()*d.getY(); + + if(sq > xsq) { + return 1; + } else if(sq < xsq) { + return -1; + } + } + return 0; + } + + @Override + public boolean equals(final Object obj) { + if(this == obj) { return true; } + if (obj instanceof Rectangle) { + final Rectangle rect = (Rectangle)obj; + return (y == rect.y) && (x == rect.x) && + (height == rect.height) && (width == rect.width); + } + return false; + } + + @Override + public int hashCode() { + final int sum1 = x + height; + final int sum2 = width + y; + final int val1 = sum1 * (sum1 + 1)/2 + x; + final int val2 = sum2 * (sum2 + 1)/2 + y; + final int sum3 = val1 + val2; + return sum3 * (sum3 + 1)/2 + val2; + } + + @Override + public String toString() { + return "[ "+x+" / "+y+" "+width+" x "+height+" ]"; + } +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/RectangleImmutable.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/RectangleImmutable.java new file mode 100644 index 000000000..ff2209598 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/RectangleImmutable.java @@ -0,0 +1,87 @@ +/** + * 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.nativewindow.util; + +import com.jogamp.common.type.WriteCloneable; + +/** Immutable Rectangle interface */ +public interface RectangleImmutable extends WriteCloneable, Comparable<RectangleImmutable> { + + int getHeight(); + + int getWidth(); + + int getX(); + + int getY(); + + /** Returns the union of this rectangle and the given rectangle. */ + RectangleImmutable union(final RectangleImmutable r); + /** Returns the union of this rectangleand the given coordinates. */ + RectangleImmutable union(final int rx1, final int ry1, final int rx2, final int ry2); + /** Returns the intersection of this rectangleand the given rectangle. */ + RectangleImmutable intersection(RectangleImmutable r); + /** Returns the intersection of this rectangleand the given coordinates. */ + RectangleImmutable intersection(final int rx1, final int ry1, final int rx2, final int ry2); + /** + * Returns the coverage of given rectangle w/ this this one, i.e. between <code>0.0</code> and <code>1.0</code>. + * <p> + * Coverage is computed by: + * <pre> + * isect = this.intersection(r); + * coverage = area( isect ) / area( this ) ; + * </pre> + * </p> + */ + float coverage(RectangleImmutable r); + + /** + * <p> + * Compares square of size 1st, if equal the square of position. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final RectangleImmutable d); + + /** + * Checks whether two rect objects are equal. Two instances + * of <code>Rectangle</code> are equal if the four integer values + * of the fields <code>y</code>, <code>x</code>, + * <code>height</code>, and <code>width</code> are all equal. + * @return <code>true</code> if the two rectangles are equal; + * otherwise <code>false</code>. + */ + @Override + boolean equals(Object obj); + + @Override + int hashCode(); + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/util/SurfaceSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/util/SurfaceSize.java new file mode 100644 index 000000000..b9e6ded95 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/util/SurfaceSize.java @@ -0,0 +1,113 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright (c) 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.nativewindow.util; + +/** + * Immutable SurfaceSize Class, consisting of it's read only components:<br> + * <ul> + * <li>{@link com.jogamp.nativewindow.util.DimensionImmutable size in pixels}</li> + * <li><code>bits per pixel</code></li> + * </ul> + */ +public class SurfaceSize implements Comparable<SurfaceSize> { + final DimensionImmutable resolution; + final int bitsPerPixel; + + public SurfaceSize(final DimensionImmutable resolution, final int bitsPerPixel) { + if(null==resolution || bitsPerPixel<=0) { + throw new IllegalArgumentException("resolution must be set and bitsPerPixel greater 0"); + } + this.resolution=resolution; + this.bitsPerPixel=bitsPerPixel; + } + + /** Returns the resolution in pixel units */ + public final DimensionImmutable getResolution() { + return resolution; + } + + public final int getBitsPerPixel() { + return bitsPerPixel; + } + + @Override + public final String toString() { + return "[ "+resolution+" pixels x "+bitsPerPixel+" bpp ]"; + } + + /** + * <p> + * Compares {@link DimensionImmutable#compareTo(DimensionImmutable) resolution} 1st, if equal the bitsPerPixel. + * </p> + * {@inheritDoc} + */ + @Override + public int compareTo(final SurfaceSize ssz) { + final int rres = resolution.compareTo(ssz.getResolution()); + if( 0 != rres ) { + return rres; + } + final int xbpp = ssz.getBitsPerPixel(); + if(bitsPerPixel > xbpp) { + return 1; + } else if(bitsPerPixel < xbpp) { + return -1; + } + return 0; + } + + /** + * Checks whether two size objects are equal. Two instances + * of <code>SurfaceSize</code> are equal if the two components + * <code>resolution</code> and <code>bitsPerPixel</code> + * are equal. + * @return <code>true</code> if the two dimensions are equal; + * otherwise <code>false</code>. + */ + @Override + public final boolean equals(final Object obj) { + if(this == obj) { return true; } + if (obj instanceof SurfaceSize) { + final SurfaceSize p = (SurfaceSize)obj; + return getResolution().equals(p.getResolution()) && + getBitsPerPixel() == p.getBitsPerPixel(); + } + return false; + } + + @Override + public final int hashCode() { + // 31 * x == (x << 5) - x + int hash = getResolution().hashCode(); + hash = ((hash << 5) - hash) + getBitsPerPixel(); + return hash; + } +} + |