From e7ffa68bce9bb707005be72530b207c732f62c31 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 31 Dec 2013 08:14:21 +0100 Subject: Bug 934, Bug 935: NEWT: Add support for custom Application/Window and Pointer Icons - Utilizing JOGL's PNG decoder for all icons, if available. - Application/window icons: - Providing default application/window icons in 16x16 and 32x32 size - NewtFactory.setWindowIcons(..) or property 'newt.window.icons' maybe used to override default icons. - Using icons at application/window instantiation - Display.PointerIcons: - NativeWindow Win32 WindowClass no more references a default cursor in favor of fine grained cursor control [in NEWT] - Display provides create/destroy methods, where display destruction also releases open PointerIcon references. - Window.setPointerIcon(..) sets custom PointerIcon - Implemented Platforms - X11 - Windows - OSX - Manual Test: TestGearsES2NEWT (Press 'c') --- make/resources/assets/newt/data/jogamp-16x16.png | Bin 0 -> 549 bytes make/resources/assets/newt/data/jogamp-32x32.png | Bin 0 -> 1020 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 make/resources/assets/newt/data/jogamp-16x16.png create mode 100644 make/resources/assets/newt/data/jogamp-32x32.png (limited to 'make/resources/assets/newt/data') diff --git a/make/resources/assets/newt/data/jogamp-16x16.png b/make/resources/assets/newt/data/jogamp-16x16.png new file mode 100644 index 000000000..02df8997f Binary files /dev/null and b/make/resources/assets/newt/data/jogamp-16x16.png differ diff --git a/make/resources/assets/newt/data/jogamp-32x32.png b/make/resources/assets/newt/data/jogamp-32x32.png new file mode 100644 index 000000000..ab21c6e1b Binary files /dev/null and b/make/resources/assets/newt/data/jogamp-32x32.png differ -- cgit v1.2.3 From bd98b927b910d9421e63cf0dbc2b746eec019f80 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 8 Jan 2014 21:56:26 +0100 Subject: Bug 935: NEWT PointerIcon: Utilize Toolkit Agnostic PixelFormat and Conversion Utilities (Allowing 'arbitrary' PointerIcon data input) Commit fe28bc125429b38cdcd016746081f4a6d521c6fd added the notion of toolkit agnostic PixelFormat and conversion utilities, utilized and further tested by this patch. +++ - PointerIcon is a PixelRectangle and hence holds the decoded data. This allows on-the-fly conversion if required as well as recreation w/o PNG re-decoding. - Using array-backed PointerIcon data where possible, allowing better performance when converting PixelFormat etc. - NEWT Display adds 'createPointerIcon(final IOUtil.ClassResources pngResource...' method to support agnostic PointerIcon creation. - NEWT Display adds methods to allow users to avoid PixelFormat and Buffer NIO type forced conversion: - PixelFormat getNativePointerIconPixelFormat() - boolean getNativePointerIconForceDirectNIO() +++ PNGImage -> PNGPixelRect Deleted: com.jogamp.opengl.util.texture.spi.PNGImage Added: com.jogamp.opengl.util.PNGPixelRect (We hope nobody was using PNGImage directly since it was a service-plugin for TextureIO) PNGPixelRect is a PixelRectangle PNGPixelRect actually is implemented OpenGL agnostic, however - since our PNGJ support lives under package 'jogamp.opengl.util.pngj' it cannot be moved up (yet). PNGPixelRect now handles all PixelFormat for the target format and also added support for grayscale+alpha (2 channels). The latter is force-converted to RGB* - similar to paletted. Further more, PNGPixelRect allows simply passing an OutputStream to write the PNG data. Used by: TextureIO and NEWT +++ - OffscreenSurfaceLayer's setCursor(..) uses the agnostic PixelRectangle instead of a PNG resource. - AWTMisc uses the PixelRectangle to produce the AWT Cursor and converts it to the required format. Hence same pixels are used for NEWT and AWT pointer/cursor icon. - TestGearsES2Newt and NewtAWTReparentingKeyAdapter 'tests' iterate over 3 custom PointerIcon when pressed 'c'. - JOGLNewtAppletBase uses the new custom PointerIcon 'newt/data/crosshair-lumina-trans-32x32.png', which is included in NEWT (213 bytes only). - --- .../assets-test/crosshair-lumina-trans-64x64.png | Bin 0 -> 424 bytes .../newt/data/crosshair-lumina-trans-32x32.png | Bin 0 -> 213 bytes make/scripts/tests.sh | 9 +- .../com/jogamp/opengl/util/PNGPixelRect.java | 335 +++++++++++++++++++++ .../com/jogamp/opengl/util/texture/TextureIO.java | 63 ++-- .../jogamp/opengl/util/texture/spi/PNGImage.java | 319 -------------------- .../com/jogamp/nativewindow/awt/JAWTWindow.java | 17 +- .../media/nativewindow/OffscreenLayerSurface.java | 10 +- .../classes/jogamp/nativewindow/awt/AWTMisc.java | 48 ++- src/newt/classes/com/jogamp/newt/Display.java | 119 ++++++-- .../jogamp/newt/awt/applet/JOGLNewtAppletBase.java | 4 +- src/newt/classes/jogamp/newt/DisplayImpl.java | 156 +++++++++- src/newt/classes/jogamp/newt/PointerIconImpl.java | 63 +++- src/newt/classes/jogamp/newt/WindowImpl.java | 8 +- src/newt/classes/jogamp/newt/driver/PNGIcon.java | 35 +-- .../jogamp/newt/driver/macosx/DisplayDriver.java | 58 ++-- .../jogamp/newt/driver/opengl/JoglUtilPNGIcon.java | 92 ++---- .../jogamp/newt/driver/windows/DisplayDriver.java | 50 ++- .../jogamp/newt/driver/x11/DisplayDriver.java | 38 +-- .../jogamp/newt/driver/x11/WindowDriver.java | 20 +- src/newt/native/MacWindow.m | 32 +- src/newt/native/WindowsWindow.c | 16 +- src/newt/native/X11Display.c | 15 +- src/newt/native/X11Window.c | 20 +- .../jogl/demos/es2/newt/TestGearsES2NEWT.java | 59 +++- .../test/junit/jogl/util/texture/PNGTstFiles.java | 54 ++++ .../jogl/util/texture/TestPNGImage00NEWT.java | 92 ------ .../jogl/util/texture/TestPNGImage01NEWT.java | 182 ----------- .../jogl/util/texture/TestPNGPixelRect00NEWT.java | 224 ++++++++++++++ .../jogl/util/texture/TestPNGPixelRect01NEWT.java | 198 ++++++++++++ .../util/texture/TestPixelFormatUtil01NEWT.java | 105 +++++++ .../util/texture/crosshair-lumina-trans-32x32.png | Bin 0 -> 213 bytes .../util/texture/crosshair-lumina-trans-64x64.png | Bin 0 -> 424 bytes .../parenting/NewtAWTReparentingKeyAdapter.java | 62 +++- 34 files changed, 1573 insertions(+), 930 deletions(-) create mode 100644 make/resources/assets-test/crosshair-lumina-trans-64x64.png create mode 100644 make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png create mode 100644 src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java delete mode 100644 src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage00NEWT.java delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage01NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect00NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png (limited to 'make/resources/assets/newt/data') diff --git a/make/resources/assets-test/crosshair-lumina-trans-64x64.png b/make/resources/assets-test/crosshair-lumina-trans-64x64.png new file mode 100644 index 000000000..9be285335 Binary files /dev/null and b/make/resources/assets-test/crosshair-lumina-trans-64x64.png differ diff --git a/make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png b/make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png new file mode 100644 index 000000000..92279640b Binary files /dev/null and b/make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png differ diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index db852ce42..55973eb12 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -229,7 +229,7 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Dnewt.debug=all" #D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.GLJPanel -Djogl.debug.TileRenderer -Djogl.debug.TileRenderer.PNG" #D_ARGS="-Djogl.debug.GLCanvas -Djogl.debug.GLJPanel -Djogl.debug.TileRenderer" - #D_ARGS="-Djogl.debug.PNGImage" + #D_ARGS="-Djogl.debug.PNG -Dnewt.debug.Display.PointerIcon" #D_ARGS="-Djogl.debug.JPEGImage" #D_ARGS="-Djogl.debug.GLDrawable -Dnativewindow.debug.GraphicsConfiguration -Djogl.debug.CapabilitiesChooser" #X_ARGS="-Dsun.java2d.noddraw=True -Dsun.java2d.opengl=True -Dsun.java2d.xrender=false" @@ -634,9 +634,10 @@ testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasA #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTCompareNewtAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTBenchmarkNewtAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGTextureFromFileNEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGImage00NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGImage01NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.ToolPNG2CSource $* +#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGPixelRect00NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGPixelRect01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPixelFormatUtil00NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPixelFormatUtil01NEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestGLReadBufferUtilTextureIOWrite01AWT $* diff --git a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java new file mode 100644 index 000000000..1bbc12f32 --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java @@ -0,0 +1,335 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.util; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.DimensionImmutable; +import javax.media.nativewindow.util.PixelFormat; +import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PixelFormatUtil; + +import jogamp.opengl.Debug; +import jogamp.opengl.util.pngj.ImageInfo; +import jogamp.opengl.util.pngj.ImageLine; +import jogamp.opengl.util.pngj.ImageLineHelper; +import jogamp.opengl.util.pngj.PngReader; +import jogamp.opengl.util.pngj.PngWriter; +import jogamp.opengl.util.pngj.chunks.PngChunkPLTE; +import jogamp.opengl.util.pngj.chunks.PngChunkTRNS; +import jogamp.opengl.util.pngj.chunks.PngChunkTextVar; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.common.util.IOUtil; + +public class PNGPixelRect extends PixelRectangle.GenericPixelRect { + private static final boolean DEBUG = Debug.debug("PNG"); + + /** + * Reads a PNG image from the specified InputStream. + *

+ * Implicitly converts the image to match the desired: + *

+ *

+ * + * @param in input stream + * @param destFmt desired destination {@link PixelFormat} incl. conversion, maybe null to use source {@link PixelFormat} + * @param destDirectBuffer if true, using a direct NIO buffer, otherwise an array backed buffer + * @param destMinStrideInBytes used if greater than PNG's stride, otherwise using PNG's stride. Stride is width * bytes-per-pixel. + * @param destIsGLOriented + * @return the newly created PNGPixelRect instance + * @throws IOException + */ + public static PNGPixelRect read(final InputStream in, + final PixelFormat ddestFmt, final boolean destDirectBuffer, final int destMinStrideInBytes, + final boolean destIsGLOriented) throws IOException { + final PngReader pngr = new PngReader(new BufferedInputStream(in), null); + final ImageInfo imgInfo = pngr.imgInfo; + final PngChunkPLTE plte = pngr.getMetadata().getPLTE(); + final PngChunkTRNS trns = pngr.getMetadata().getTRNS(); + final boolean indexed = imgInfo.indexed; + final boolean hasAlpha = indexed ? ( trns != null ) : imgInfo.alpha ; + + if(DEBUG) { + System.err.println("PNGPixelRect: "+imgInfo); + } + final int channels = indexed ? ( hasAlpha ? 4 : 3 ) : imgInfo.channels ; + final boolean isGrayAlpha = 2 == channels && imgInfo.greyscale && imgInfo.alpha; + if ( ! ( 1 == channels || 3 == channels || 4 == channels || isGrayAlpha ) ) { + throw new RuntimeException("PNGPixelRect can only handle Lum/RGB/RGBA [1/3/4 channels] or Lum+A (GA) images for now. Channels "+channels + " Paletted: " + indexed); + } + final int bytesPerPixel = indexed ? channels : imgInfo.bytesPixel ; + if ( ! ( 1 == bytesPerPixel || 3 == bytesPerPixel || 4 == bytesPerPixel || isGrayAlpha ) ) { + throw new RuntimeException("PNGPixelRect can only handle Lum/RGB/RGBA [1/3/4 bpp] images for now. BytesPerPixel "+bytesPerPixel); + } + if( channels != bytesPerPixel ) { + throw new RuntimeException("PNGPixelRect currently only handles Channels [1/3/4] == BytePerPixel [1/3/4], channels: "+channels+", bytesPerPixel "+bytesPerPixel); + } + final int width = imgInfo.cols; + final int height = imgInfo.rows; + final double dpiX, dpiY; + { + final double[] dpi = pngr.getMetadata().getDpi(); + dpiX = dpi[0]; + dpiY = dpi[1]; + } + final PixelFormat srcFmt; + if ( indexed ) { + if ( hasAlpha ) { + srcFmt = PixelFormat.RGBA8888; + } else { + srcFmt = PixelFormat.RGB888; + } + } else { + switch( channels ) { + case 1: srcFmt = PixelFormat.LUMINANCE; break; + case 2: srcFmt = isGrayAlpha ? PixelFormat.LUMINANCE : null; break; + case 3: srcFmt = PixelFormat.RGB888; break; + case 4: srcFmt = PixelFormat.RGBA8888; break; + default: srcFmt = null; + } + if( null == srcFmt ) { + throw new InternalError("XXX: channels: "+channels+", bytesPerPixel "+bytesPerPixel); + } + } + final PixelFormat destFmt; + if( null == ddestFmt ) { + if( isGrayAlpha ) { + destFmt = PixelFormat.BGRA8888; // save alpha value on gray-alpha + } else { + destFmt = srcFmt; // 1:1 + } + } else { + destFmt = ddestFmt; // user choice + } + final int destStrideInBytes = Math.max(destMinStrideInBytes, destFmt.bytesPerPixel() * width); + final ByteBuffer destPixels = destDirectBuffer ? Buffers.newDirectByteBuffer(destStrideInBytes * height) : + ByteBuffer.allocate(destStrideInBytes * height); + { + final int reqBytes = destStrideInBytes * height; + if( destPixels.limit() < reqBytes ) { + throw new IndexOutOfBoundsException("Dest buffer has insufficient bytes left, needs "+reqBytes+": "+destPixels); + } + } + final boolean vert_flip = destIsGLOriented; + + int[] rgbaScanline = indexed ? new int[width * channels] : null; + if(DEBUG) { + System.err.println("PNGPixelRect: indexed "+indexed+", alpha "+hasAlpha+", grayscale "+imgInfo.greyscale+", channels "+channels+"/"+imgInfo.channels+ + ", bytesPerPixel "+bytesPerPixel+"/"+imgInfo.bytesPixel+ + ", grayAlpha "+isGrayAlpha+", pixels "+width+"x"+height+", dpi "+dpiX+"x"+dpiY+", format "+srcFmt); + System.err.println("PNGPixelRect: destFormat "+destFmt+" ("+ddestFmt+", bytesPerPixel "+destFmt.bytesPerPixel()+", fast-path "+(destFmt==srcFmt)+"), destDirectBuffer "+destDirectBuffer+", destIsGLOriented (flip) "+destIsGLOriented); + System.err.println("PNGPixelRect: destStrideInBytes "+destStrideInBytes+" (destMinStrideInBytes "+destMinStrideInBytes+")"); + } + + for (int row = 0; row < height; row++) { + final ImageLine l1 = pngr.readRow(row); + int lineOff = 0; + int dataOff = vert_flip ? ( height - 1 - row ) * destStrideInBytes : row * destStrideInBytes; + if( indexed ) { + for (int j = width - 1; j >= 0; j--) { + rgbaScanline = ImageLineHelper.palette2rgb(l1, plte, trns, rgbaScanline); // reuse rgbaScanline and update if resized + dataOff = getPixelRGBA8ToAny(destFmt, destPixels, dataOff, rgbaScanline, lineOff, hasAlpha); + lineOff += bytesPerPixel; + } + } else if( 1 == channels ) { + for (int j = width - 1; j >= 0; j--) { + dataOff = getPixelLUMToAny(destFmt, destPixels, dataOff, (byte)l1.scanline[lineOff++], (byte)0xff); // Luminance, 1 bytesPerPixel + } + } else if( isGrayAlpha ) { + for (int j = width - 1; j >= 0; j--) { + dataOff = getPixelLUMToAny(destFmt, destPixels, dataOff, (byte)l1.scanline[lineOff++], (byte)l1.scanline[lineOff++]); // Luminance+Alpha, 2 bytesPerPixel + } + } else if( srcFmt == destFmt ) { // fast-path + for (int j = width - 1; j >= 0; j--) { + dataOff = getPixelRGBSame(destPixels, dataOff, l1.scanline, lineOff, bytesPerPixel); + lineOff += bytesPerPixel; + } + } else { + for (int j = width - 1; j >= 0; j--) { + dataOff = getPixelRGBA8ToAny(destFmt, destPixels, dataOff, l1.scanline, lineOff, hasAlpha); + lineOff += bytesPerPixel; + } + } + } + pngr.end(); + + return new PNGPixelRect(destFmt, new Dimension(width, height), destStrideInBytes, destIsGLOriented, destPixels, dpiX, dpiY); + } + + private static final int getPixelLUMToAny(PixelFormat dest_fmt, ByteBuffer d, int dOff, byte lum, byte alpha) { + switch(dest_fmt) { + case LUMINANCE: + d.put(dOff++, lum); + break; + case BGR888: + case RGB888: + d.put(dOff++, lum); + d.put(dOff++, lum); + d.put(dOff++, lum); + break; + case ABGR8888: + case ARGB8888: + d.put(dOff++, alpha); // A + d.put(dOff++, lum); + d.put(dOff++, lum); + d.put(dOff++, lum); + break; + case BGRA8888: + case RGBA8888: + d.put(dOff++, lum); + d.put(dOff++, lum); + d.put(dOff++, lum); + d.put(dOff++, alpha); // A + break; + default: + throw new InternalError("Unhandled format "+dest_fmt); + } + return dOff; + } + private static final int getPixelRGBA8ToAny(final PixelFormat dest_fmt, final ByteBuffer d, int dOff, final int[] scanline, final int lineOff, final boolean srcHasAlpha) { + final int p = PixelFormatUtil.convertToInt32(dest_fmt, (byte)scanline[lineOff], // R + (byte)scanline[lineOff+1], // G + (byte)scanline[lineOff+2], // B + srcHasAlpha ? (byte)scanline[lineOff+3] : (byte)0xff); // A + final int dbpp = dest_fmt.bytesPerPixel(); + d.put(dOff++, (byte) ( p )); // 1 + if( 1 < dbpp ) { + d.put(dOff++, (byte) ( p >>> 8 )); // 2 + d.put(dOff++, (byte) ( p >>> 16 )); // 3 + if( 4 == dbpp ) { + d.put(dOff++, (byte) ( p >>> 24 )); // 4 + } + } + return dOff; + } + private static final int getPixelRGBSame(final ByteBuffer d, int dOff, final int[] scanline, final int lineOff, final int bpp) { + d.put(dOff++, (byte)scanline[lineOff]); // R + if( 1 < bpp ) { + d.put(dOff++, (byte)scanline[lineOff + 1]); // G + d.put(dOff++, (byte)scanline[lineOff + 2]); // B + if( 4 == bpp ) { + d.put(dOff++, (byte)scanline[lineOff + 3]); // A + } + } + return dOff; + } + private int setPixelRGBA8(final ImageLine line, final int lineOff, final ByteBuffer d, final int dOff, final int bytesPerPixel, final boolean hasAlpha) { + final int b = hasAlpha ? 4-1 : 3-1; + if( d.limit() <= dOff + b ) { + throw new IndexOutOfBoundsException("Buffer has unsufficient bytes left, needs ["+dOff+".."+(dOff+b)+"]: "+d); + } + final int p = PixelFormatUtil.convertToInt32(hasAlpha ? PixelFormat.RGBA8888 : PixelFormat.RGB888, pixelformat, d, dOff); + line.scanline[lineOff ] = 0xff & p; // R + line.scanline[lineOff + 1] = 0xff & ( p >>> 8 ); // G + line.scanline[lineOff + 2] = 0xff & ( p >>> 16 ); // B + if(hasAlpha) { + line.scanline[lineOff + 3] = 0xff & ( p >>> 24 ); // A + } + return dOff + pixelformat.bytesPerPixel(); + } + + /** + * Creates a PNGPixelRect from data supplied by the end user. Shares + * data with the passed ByteBuffer. + * + * @param pixelformat + * @param size + * @param strideInBytes + * @param isGLOriented see {@link #isGLOriented()}. + * @param pixels + * @param dpiX + * @param dpiY + */ + public PNGPixelRect(final PixelFormat pixelformat, final DimensionImmutable size, + final int strideInBytes, final boolean isGLOriented, final ByteBuffer pixels, + final double dpiX, final double dpiY) { + super(pixelformat, size, strideInBytes, isGLOriented, pixels); + this.dpi = new double[] { dpiX, dpiY }; + } + public PNGPixelRect(final PixelRectangle src, final double dpiX, final double dpiY) { + super(src); + this.dpi = new double[] { dpiX, dpiY }; + } + private final double[] dpi; + + /** Returns the dpi of the image. */ + public double[] getDpi() { return dpi; } + + public void write(final OutputStream outstream, final boolean closeOutstream) throws IOException { + final int width = size.getWidth(); + final int height = size.getHeight(); + final int bytesPerPixel = pixelformat.bytesPerPixel(); + final ImageInfo imi = new ImageInfo(width, height, 8 /* bitdepth */, + (4 == bytesPerPixel) ? true : false /* alpha */, + (1 == bytesPerPixel) ? true : false /* grayscale */, + false /* indexed */); + + // open image for writing to a output stream + try { + final PngWriter png = new PngWriter(outstream, imi); + // add some optional metadata (chunks) + png.getMetadata().setDpi(dpi[0], dpi[1]); + png.getMetadata().setTimeNow(0); // 0 seconds fron now = now + png.getMetadata().setText(PngChunkTextVar.KEY_Title, "JogAmp PNGPixelRect"); + // png.getMetadata().setText("my key", "my text"); + final boolean hasAlpha = 4 == bytesPerPixel; + + final ImageLine l1 = new ImageLine(imi); + for (int row = 0; row < height; row++) { + int dataOff = isGLOriented ? ( height - 1 - row ) * strideInBytes : row * strideInBytes; + int lineOff = 0; + if(1 == bytesPerPixel) { + for (int j = width - 1; j >= 0; j--) { + l1.scanline[lineOff++] = pixels.get(dataOff++); // // Luminance, 1 bytesPerPixel + } + } else { + for (int j = width - 1; j >= 0; j--) { + dataOff = setPixelRGBA8(l1, lineOff, pixels, dataOff, bytesPerPixel, hasAlpha); + lineOff += bytesPerPixel; + } + } + png.writeRow(l1, row); + } + png.end(); + } finally { + if( closeOutstream ) { + IOUtil.close(outstream, false); + } + } + } +} diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java index 67ab5176d..0cde24db4 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java @@ -41,10 +41,12 @@ package com.jogamp.opengl.util.texture; import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.URL; import java.nio.Buffer; import java.nio.ByteBuffer; @@ -52,9 +54,10 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; import javax.media.opengl.GL2; -import javax.media.opengl.GL2ES2; import javax.media.opengl.GL2GL3; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; @@ -63,11 +66,11 @@ import javax.media.opengl.GLProfile; import jogamp.opengl.Debug; import com.jogamp.common.util.IOUtil; +import com.jogamp.opengl.util.PNGPixelRect; import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; import com.jogamp.opengl.util.texture.spi.DDSImage; import com.jogamp.opengl.util.texture.spi.JPEGImage; import com.jogamp.opengl.util.texture.spi.NetPbmTextureWriter; -import com.jogamp.opengl.util.texture.spi.PNGImage; import com.jogamp.opengl.util.texture.spi.SGIImage; import com.jogamp.opengl.util.texture.spi.TGAImage; import com.jogamp.opengl.util.texture.spi.TextureProvider; @@ -1166,27 +1169,29 @@ public class TextureIO { boolean mipmap, String fileSuffix) throws IOException { if (PNG.equals(fileSuffix)) { - PNGImage image = PNGImage.read(/*glp, */ stream); - if (pixelFormat == 0) { - pixelFormat = image.getGLFormat(); - } - if (internalFormat == 0) { + final PNGPixelRect image = PNGPixelRect.read(stream, null, true /* directBuffer */, 0 /* destMinStrideInBytes */, true /* destIsGLOriented */); + final GLPixelAttributes glpa = GLPixelAttributes.convert(image.getPixelformat(), glp); + if ( 0 == pixelFormat ) { + pixelFormat = glpa.format; + } // else FIXME: Actually not supported w/ preset pixelFormat! + if ( 0 == internalFormat ) { + final boolean hasAlpha = 4 == glpa.bytesPerPixel; if(glp.isGL2ES3()) { - internalFormat = (image.getBytesPerPixel()==4)?GL.GL_RGBA8:GL.GL_RGB8; + internalFormat = hasAlpha ? GL.GL_RGBA8 : GL.GL_RGB8; } else { - internalFormat = (image.getBytesPerPixel()==4)?GL.GL_RGBA:GL.GL_RGB; + internalFormat = hasAlpha ? GL.GL_RGBA : GL.GL_RGB; } } return new TextureData(glp, internalFormat, - image.getWidth(), - image.getHeight(), + image.getSize().getWidth(), + image.getSize().getHeight(), 0, pixelFormat, - image.getGLType(), + glpa.type, mipmap, false, false, - image.getData(), + image.getPixels(), null); } @@ -1392,29 +1397,7 @@ public class TextureIO { final int pixelFormat = pixelAttribs.format; final int pixelType = pixelAttribs.type; final int bytesPerPixel = pixelAttribs.bytesPerPixel; - final boolean reversedChannels; - switch(pixelFormat) { - case GL.GL_ALPHA: - case GL.GL_LUMINANCE: - case GL2ES2.GL_RED: - reversedChannels=false; - break; - case GL.GL_RGB: - reversedChannels=false; - break; - case GL.GL_RGBA: - reversedChannels=false; - break; - case GL2.GL_BGR: - reversedChannels=true; - break; - case GL.GL_BGRA: - reversedChannels=true; - break; - default: - reversedChannels=false; - break; - } + final PixelFormat pixFmt = pixelAttribs.getPixelFormat(); if ( ( 1 == bytesPerPixel || 3 == bytesPerPixel || 4 == bytesPerPixel) && ( pixelType == GL.GL_BYTE || pixelType == GL.GL_UNSIGNED_BYTE)) { ByteBuffer buf = (ByteBuffer) data.getBuffer(); @@ -1423,9 +1406,11 @@ public class TextureIO { } buf.rewind(); - PNGImage image = PNGImage.createFromData(data.getWidth(), data.getHeight(), -1f, -1f, - bytesPerPixel, reversedChannels, !data.getMustFlipVertically(), buf); - image.write(file, true); + final PNGPixelRect image = new PNGPixelRect(pixFmt, new Dimension(data.getWidth(), data.getHeight()), + 0 /* stride */, true /* isGLOriented */, buf /* pixels */, + -1f, -1f); + final OutputStream outs = new BufferedOutputStream(IOUtil.getFileOutputStream(file, true /* allowOverwrite */)); + image.write(outs, true /* close */); return true; } throw new IOException("PNG writer doesn't support this pixel format 0x"+Integer.toHexString(pixelFormat)+ diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java deleted file mode 100644 index 71cbbf97e..000000000 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/PNGImage.java +++ /dev/null @@ -1,319 +0,0 @@ -/** - * Copyright 2012 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.util.texture.spi; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; - -import javax.media.opengl.GL; - -import jogamp.opengl.Debug; -import jogamp.opengl.util.pngj.ImageInfo; -import jogamp.opengl.util.pngj.ImageLine; -import jogamp.opengl.util.pngj.ImageLineHelper; -import jogamp.opengl.util.pngj.PngReader; -import jogamp.opengl.util.pngj.PngWriter; -import jogamp.opengl.util.pngj.chunks.PngChunkPLTE; -import jogamp.opengl.util.pngj.chunks.PngChunkTRNS; -import jogamp.opengl.util.pngj.chunks.PngChunkTextVar; - -import com.jogamp.common.nio.Buffers; -import com.jogamp.common.util.IOUtil; - -public class PNGImage { - private static final boolean DEBUG = Debug.debug("PNGImage"); - - /** - * Creates a PNGImage from data supplied by the end user. Shares - * data with the passed ByteBuffer. Assumes the data is already in - * the correct byte order for writing to disk, i.e., LUMINANCE, RGB or RGBA. - * Orientation is bottom-to-top (OpenGL coord. default) - * or top-to-bottom depending on isGLOriented. - * - * @param width - * @param height - * @param dpiX - * @param dpiY - * @param bytesPerPixel - * @param reversedChannels - * @param isGLOriented see {@link #isGLOriented()}. - * @param data - * @return - */ - public static PNGImage createFromData(int width, int height, double dpiX, double dpiY, - int bytesPerPixel, boolean reversedChannels, boolean isGLOriented, ByteBuffer data) { - return new PNGImage(width, height, dpiX, dpiY, bytesPerPixel, reversedChannels, isGLOriented, data); - } - - /** - * Reads a PNG image from the specified InputStream. - *

- * Implicitly flip image to GL orientation, see {@link #isGLOriented()}. - *

- */ - public static PNGImage read(InputStream in) throws IOException { - return new PNGImage(in); - } - - /** Reverse read and store, implicitly flip image to GL orientation, see {@link #isGLOriented()}. */ - private static final int getPixelRGBA8(ByteBuffer d, int dOff, int[] scanline, int lineOff, boolean hasAlpha) { - final int b = hasAlpha ? 4-1 : 3-1; - if( d.limit() <= dOff || dOff - b < 0 ) { - throw new IndexOutOfBoundsException("Buffer has unsufficient bytes left, needs ["+(dOff-b)+".."+dOff+"]: "+d); - } - if(hasAlpha) { - d.put(dOff--, (byte)scanline[lineOff + 3]); // A - } - d.put(dOff--, (byte)scanline[lineOff + 2]); // B - d.put(dOff--, (byte)scanline[lineOff + 1]); // G - d.put(dOff--, (byte)scanline[lineOff ]); // R - return dOff; - } - - /** Reverse write and store, implicitly flip image from current orientation, see {@link #isGLOriented()}. Handle reversed channels (BGR[A]). */ - private int setPixelRGBA8(ImageLine line, int lineOff, ByteBuffer d, int dOff, boolean hasAlpha) { - final int b = hasAlpha ? 4-1 : 3-1; - if( d.limit() <= dOff + b ) { - throw new IndexOutOfBoundsException("Buffer has unsufficient bytes left, needs ["+dOff+".."+(dOff+b)+"]: "+d); - } - if( reversedChannels ) { - if(hasAlpha) { - line.scanline[lineOff + 3] = d.get(dOff++); // A - } - line.scanline[lineOff + 2] = d.get(dOff++); // R - line.scanline[lineOff + 1] = d.get(dOff++); // G - line.scanline[lineOff ] = d.get(dOff++); // B - } else { - line.scanline[lineOff ] = d.get(dOff++); // R - line.scanline[lineOff + 1] = d.get(dOff++); // G - line.scanline[lineOff + 2] = d.get(dOff++); // B - if(hasAlpha) { - line.scanline[lineOff + 3] = d.get(dOff++); // A - } - } - return isGLOriented ? dOff - bytesPerPixel - bytesPerPixel : dOff; - } - - private PNGImage(int width, int height, double dpiX, double dpiY, int bytesPerPixel, boolean reversedChannels, boolean isGLOriented, ByteBuffer data) { - pixelWidth=width; - pixelHeight=height; - dpi = new double[] { dpiX, dpiY }; - if(4 == bytesPerPixel) { - glFormat = GL.GL_RGBA; - } else if (3 == bytesPerPixel) { - glFormat = GL.GL_RGB; - } else { - throw new InternalError("XXX: bytesPerPixel "+bytesPerPixel); - } - this.bytesPerPixel = bytesPerPixel; - this.reversedChannels = reversedChannels; - this.isGLOriented = isGLOriented; - this.data = data; - } - - private PNGImage(InputStream in) { - final PngReader pngr = new PngReader(new BufferedInputStream(in), null); - final ImageInfo imgInfo = pngr.imgInfo; - final PngChunkPLTE plte = pngr.getMetadata().getPLTE(); - final PngChunkTRNS trns = pngr.getMetadata().getTRNS(); - final boolean indexed = imgInfo.indexed; - final boolean hasAlpha = indexed ? ( trns != null ) : imgInfo.alpha ; - - final int channels = indexed ? ( hasAlpha ? 4 : 3 ) : imgInfo.channels ; - if ( ! ( 1 == channels || 3 == channels || 4 == channels ) ) { - throw new RuntimeException("PNGImage can only handle Lum/RGB/RGBA [1/3/4 channels] images for now. Channels "+channels + " Paletted: " + indexed); - } - - bytesPerPixel = indexed ? channels : imgInfo.bytesPixel ; - if ( ! ( 1 == bytesPerPixel || 3 == bytesPerPixel || 4 == bytesPerPixel ) ) { - throw new RuntimeException("PNGImage can only handle Lum/RGB/RGBA [1/3/4 bpp] images for now. BytesPerPixel "+bytesPerPixel); - } - if( channels != bytesPerPixel ) { - throw new RuntimeException("PNGImage currently only handles Channels [1/3/4] == BytePerPixel [1/3/4], channels: "+channels+", bytesPerPixel "+bytesPerPixel); - } - pixelWidth = imgInfo.cols; - pixelHeight = imgInfo.rows; - dpi = new double[2]; - { - final double[] dpi2 = pngr.getMetadata().getDpi(); - dpi[0]=dpi2[0]; - dpi[1]=dpi2[1]; - } - if ( indexed ) { - if ( hasAlpha ) { - glFormat = GL.GL_RGBA; - } else { - glFormat = GL.GL_RGB; - } - } else { - switch( channels ) { - case 1: glFormat = GL.GL_LUMINANCE; break; - case 3: glFormat = GL.GL_RGB; break; - case 4: glFormat = GL.GL_RGBA; break; - default: throw new InternalError("XXX: channels: "+channels+", bytesPerPixel "+bytesPerPixel); - } - } - if(DEBUG) { - System.err.println("PNGImage: "+imgInfo); - System.err.println("PNGImage: indexed "+indexed+", alpha "+hasAlpha+", channels "+channels+"/"+imgInfo.channels+ - ", bytesPerPixel "+bytesPerPixel+"/"+imgInfo.bytesPixel+ - ", pixels "+pixelWidth+"x"+pixelHeight+", dpi "+dpi[0]+"x"+dpi[1]+", glFormat 0x"+Integer.toHexString(glFormat)); - } - - data = Buffers.newDirectByteBuffer(bytesPerPixel * pixelWidth * pixelHeight); - reversedChannels = false; // RGB[A] - isGLOriented = true; - int dataOff = bytesPerPixel * pixelWidth * pixelHeight - 1; // start at end-of-buffer, reverse store - - int[] rgbaScanline = indexed ? new int[imgInfo.cols * channels] : null; - - for (int row = 0; row < pixelHeight; row++) { - final ImageLine l1 = pngr.readRow(row); - int lineOff = ( pixelWidth - 1 ) * bytesPerPixel ; // start w/ last pixel in line, reverse read (PNG top-left -> OpenGL bottom-left origin) - if( indexed ) { - for (int j = pixelWidth - 1; j >= 0; j--) { - rgbaScanline = ImageLineHelper.palette2rgb(l1, plte, trns, rgbaScanline); // reuse rgbaScanline and update if resized - dataOff = getPixelRGBA8(data, dataOff, rgbaScanline, lineOff, hasAlpha); - lineOff -= bytesPerPixel; - } - } else if( 1 == channels ) { - for (int j = pixelWidth - 1; j >= 0; j--) { - data.put(dataOff--, (byte)l1.scanline[lineOff--]); // Luminance, 1 bytesPerPixel - } - } else { - for (int j = pixelWidth - 1; j >= 0; j--) { - dataOff = getPixelRGBA8(data, dataOff, l1.scanline, lineOff, hasAlpha); - lineOff -= bytesPerPixel; - } - } - } - pngr.end(); - } - private final int pixelWidth, pixelHeight, glFormat, bytesPerPixel; - private final boolean reversedChannels; - private final boolean isGLOriented; - private final double[] dpi; - private final ByteBuffer data; - - /** Returns the width of the image. */ - public int getWidth() { return pixelWidth; } - - /** Returns the height of the image. */ - public int getHeight() { return pixelHeight; } - - /** Returns true if data has the channels reversed to BGR or BGRA, otherwise RGB or RGBA is expected. */ - public boolean getHasReversedChannels() { return reversedChannels; } - - /** - * Returns true if the drawable is rendered in - * OpenGL's coordinate system, origin at bottom left. - * Otherwise returns false, i.e. origin at top left. - *

- * Default impl. is true, i.e. OpenGL coordinate system. - *

- */ - public boolean isGLOriented() { return isGLOriented; } - - /** Returns the dpi of the image. */ - public double[] getDpi() { return dpi; } - - /** Returns the OpenGL format for this texture; e.g. GL.GL_LUMINANCE, GL.GL_RGB or GL.GL_RGBA. */ - public int getGLFormat() { return glFormat; } - - /** Returns the OpenGL data type: GL.GL_UNSIGNED_BYTE. */ - public int getGLType() { return GL.GL_UNSIGNED_BYTE; } - - /** Returns the bytes per pixel */ - public int getBytesPerPixel() { return bytesPerPixel; } - - /** Returns the raw data for this texture in the correct - (bottom-to-top) order for calls to glTexImage2D. */ - public ByteBuffer getData() { return data; } - - public void write(File out, boolean allowOverwrite) throws IOException { - final ImageInfo imi = new ImageInfo(pixelWidth, pixelHeight, 8, (4 == bytesPerPixel) ? true : false); // 8 bits per channel, no alpha - // open image for writing to a output stream - final OutputStream outs = new BufferedOutputStream(IOUtil.getFileOutputStream(out, allowOverwrite)); - try { - final PngWriter png = new PngWriter(outs, imi); - // add some optional metadata (chunks) - png.getMetadata().setDpi(dpi[0], dpi[1]); - png.getMetadata().setTimeNow(0); // 0 seconds fron now = now - png.getMetadata().setText(PngChunkTextVar.KEY_Title, "JogAmp PNGImage"); - // png.getMetadata().setText("my key", "my text"); - final boolean hasAlpha = 4 == bytesPerPixel; - final ImageLine l1 = new ImageLine(imi); - if( isGLOriented ) { - // start at last pixel at end-of-buffer, reverse read (OpenGL bottom-left -> PNG top-left origin) - int dataOff = ( pixelWidth * bytesPerPixel * ( pixelHeight - 1 ) ) + // full lines - 1 line - ( ( pixelWidth - 1 ) * bytesPerPixel ); // one line - 1 pixel - for (int row = 0; row < pixelHeight; row++) { - int lineOff = ( pixelWidth - 1 ) * bytesPerPixel ; // start w/ last pixel in line, reverse store (OpenGL bottom-left -> PNG top-left origin) - if(1 == bytesPerPixel) { - for (int j = pixelWidth - 1; j >= 0; j--) { - l1.scanline[lineOff--] = data.get(dataOff--); // // Luminance, 1 bytesPerPixel - } - } else { - for (int j = pixelWidth - 1; j >= 0; j--) { - dataOff = setPixelRGBA8(l1, lineOff, data, dataOff, hasAlpha); - lineOff -= bytesPerPixel; - } - } - png.writeRow(l1, row); - } - } else { - int dataOff = 0; // start at first pixel at start-of-buffer, normal read (same origin: top-left) - for (int row = 0; row < pixelHeight; row++) { - int lineOff = 0; // start w/ first pixel in line, normal store (same origin: top-left) - if(1 == bytesPerPixel) { - for (int j = pixelWidth - 1; j >= 0; j--) { - l1.scanline[lineOff++] = data.get(dataOff++); // // Luminance, 1 bytesPerPixel - } - } else { - for (int j = pixelWidth - 1; j >= 0; j--) { - dataOff = setPixelRGBA8(l1, lineOff, data, dataOff, hasAlpha); - lineOff += bytesPerPixel; - } - } - png.writeRow(l1, row); - } - } - png.end(); - } finally { - IOUtil.close(outs, false); - } - } - - @Override - public String toString() { return "PNGImage["+pixelWidth+"x"+pixelHeight+", dpi "+dpi[0]+" x "+dpi[1]+", bytesPerPixel "+bytesPerPixel+", reversedChannels "+reversedChannels+", "+data+"]"; } -} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index b947505cb..ddf513180 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -38,7 +38,6 @@ package com.jogamp.nativewindow.awt; import com.jogamp.common.os.Platform; -import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; @@ -53,7 +52,6 @@ import java.awt.event.ComponentListener; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.applet.Applet; -import java.io.IOException; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; @@ -66,6 +64,7 @@ import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.nativewindow.util.PixelRectangle; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.PointImmutable; import javax.media.nativewindow.util.Rectangle; @@ -433,19 +432,19 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } @Override - public final boolean setCursor(final IOUtil.ClassResources resources, final PointImmutable hotSpot) throws IOException { + public final boolean setCursor(final PixelRectangle pixelrect, final PointImmutable hotSpot) { AWTEDTExecutor.singleton.invoke(false, new Runnable() { public void run() { Cursor c = null; - if( null == resources || null == hotSpot ) { + if( null == pixelrect || null == hotSpot ) { c = Cursor.getDefaultCursor(); } else { final java.awt.Point awtHotspot = new java.awt.Point(hotSpot.getX(), hotSpot.getY()); try { - c = AWTMisc.getCursor(resources, awtHotspot); - } catch (IOException e) { - e.printStackTrace(); - } + c = AWTMisc.getCursor(pixelrect, awtHotspot); + } catch (Exception e) { + e.printStackTrace(); + } } if( null != c ) { component.setCursor(c); @@ -455,7 +454,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } @Override - public boolean hideCursor() { + public final boolean hideCursor() { AWTEDTExecutor.singleton.invoke(false, new Runnable() { public void run() { component.setCursor(AWTMisc.getNullCursor()); diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java index 81983a7c2..cf8cf89d2 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java @@ -27,11 +27,9 @@ */ package javax.media.nativewindow; -import java.io.IOException; - +import javax.media.nativewindow.util.PixelRectangle; import javax.media.nativewindow.util.PointImmutable; -import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.locks.RecursiveLock; /** @@ -73,12 +71,12 @@ public interface OffscreenLayerSurface { /** * Optional method setting cursor in the corresponding on-screen surface/window, if exists. * - * @param resources maybe null for default cursor + * @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. - * @throws IOException */ - public boolean setCursor(IOUtil.ClassResources resources, PointImmutable hotSpot) throws IOException; + public boolean setCursor(PixelRectangle pixelrect, PointImmutable hotSpot); + /** * Optional method hiding the cursor in the corresponding on-screen surface/window, if exists. * diff --git a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java index b690aff4d..069cffeb8 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java +++ b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java @@ -37,21 +37,19 @@ import java.awt.Component; import java.awt.Container; import java.awt.Frame; import java.awt.image.BufferedImage; -import java.io.IOException; -import java.net.URLConnection; import java.util.HashMap; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JRootPane; import javax.swing.WindowConstants; -import javax.imageio.ImageIO; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PixelFormat; +import javax.media.nativewindow.util.PixelFormatUtil; import javax.swing.MenuSelectionManager; -import com.jogamp.common.util.IOUtil; - public class AWTMisc { public static JFrame getJFrame(Component c) { @@ -173,7 +171,7 @@ public class AWTMisc { MenuSelectionManager.defaultManager().clearSelectedPath(); } - static final HashMap cursorMap = new HashMap(); + static final HashMap cursorMap = new HashMap(); static final Cursor nulCursor; static { final Toolkit toolkit = Toolkit.getDefaultToolkit(); @@ -183,21 +181,43 @@ public class AWTMisc { public static synchronized Cursor getNullCursor() { return nulCursor; } - public static synchronized Cursor getCursor(IOUtil.ClassResources resources, Point hotSpot) throws IOException { - final String key = resources.getClass().getName()+":"+resources.resourcePaths[0]; + public static synchronized Cursor getCursor(PixelRectangle pixelrect, Point hotSpot) { + // 31 * x == (x << 5) - x + int hash = 31 + pixelrect.hashCode(); + hash = ((hash << 5) - hash) + hotSpot.hashCode(); + final Integer key = Integer.valueOf(hash); + Cursor cursor = cursorMap.get(key); if( null == cursor ) { - cursor = createAWTCursor(resources, hotSpot); + cursor = createCursor(pixelrect, hotSpot); cursorMap.put(key, cursor); } return cursor; } - private static synchronized Cursor createAWTCursor(IOUtil.ClassResources resources, Point hotSpot) throws IOException { - final URLConnection urlConn = resources.resolve(0); - final BufferedImage img = ImageIO.read(urlConn.getInputStream()); - + private static synchronized Cursor createCursor(PixelRectangle pixelrect, Point hotSpot) { + final int width = pixelrect.getSize().getWidth(); + final int height = pixelrect.getSize().getHeight(); + final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // PixelFormat.BGRA8888 + final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() { + public void store(int x, int y, int pixel) { + img.setRGB(x, y, pixel); + } + @Override + public final PixelFormat getPixelformat() { + return PixelFormat.BGRA8888; + } + @Override + public int getStride() { + return width*4; + } + @Override + public final boolean isGLOriented() { + return false; + } + }; + PixelFormatUtil.convert32(imgSink, pixelrect); final Toolkit toolkit = Toolkit.getDefaultToolkit(); - return toolkit.createCustomCursor(img, hotSpot, resources.resourcePaths[0]); + return toolkit.createCustomCursor(img, hotSpot, pixelrect.toString()); } public static WindowClosingProtocol.WindowClosingMode AWT2NWClosingOperation(int awtClosingOperation) { diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 8d1445f80..4b38fcca5 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -30,14 +30,14 @@ package com.jogamp.newt; import java.io.IOException; import java.lang.ref.WeakReference; -import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.util.DimensionImmutable; +import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PixelFormat; import javax.media.nativewindow.util.PointImmutable; import jogamp.newt.Debug; @@ -47,6 +47,7 @@ import com.jogamp.newt.util.EDTUtil; public abstract class Display { public static final boolean DEBUG = Debug.debug("Display"); + protected static final boolean DEBUG_POINTER_ICON = Debug.debug("Display.PointerIcon"); /** return precomputed hashCode from FQN {@link #getFQName()} */ @Override @@ -66,7 +67,9 @@ public abstract class Display { /** * Native PointerIcon handle. *

- * Instances can be created via {@link Display}'s {@link Display#createPointerIcon(com.jogamp.common.util.IOUtil.ClassResources, int, int) createPointerIcon(..)}. + * Instances can be created via {@link Display}'s + * {@link Display#createPointerIcon(com.jogamp.common.util.IOUtil.ClassResources, int, int) createPointerIcon(pngResource, ..)} + * or {@link Display#createPointerIcon(PixelRectangle, int, int) createPointerIcon(pixelrect, ..)}. *

*

* Instance is {@link #destroy()}'ed automatically if it's {@link #getDisplay() associated Display} is destroyed. @@ -75,23 +78,65 @@ public abstract class Display { * Instance can be re-validated after destruction via {@link #validate()}. *

*

+ * {@link PointerIcon} must not be {@link #destroy() destroyed} while in use! + *

+ *

* {@link PointerIcon} may be {@link #destroy() destroyed} manually after use, * i.e. when no {@link Window} {@link Window#setPointerIcon(PointerIcon) uses them} anymore. + * However, this is not required. *

*

* PointerIcons can be used via {@link Window#setPointerIcon(PointerIcon)}. *

*/ - public static interface PointerIcon { + public static interface PointerIcon extends PixelRectangle { /** - * @return the associated Display + * Always neatly packed, i.e. width * bytes_per_pixel. + *

+ * {@inheritDoc} + *

*/ - Display getDisplay(); + @Override + int getStride(); + + /** + * Always false, i.e. origin is TOP-LEFT. + *

+ * {@inheritDoc} + *

+ */ + boolean isGLOriented(); + + /** + * Computes a hash code over: + *
    + *
  • display
  • + *
  • pixelformat
  • + *
  • size
  • + *
  • stride
  • + *
  • isGLOriented
  • + *
  • pixels
  • + *
  • hotspot
  • + *
+ * Dismissing the native handle! + *

+ * The hashCode shall be computed only once with first call + * and stored for later retrieval to enhance performance. + *

+ *

+ * {@inheritDoc} + *

+ */ + @Override + int hashCode(); /** - * @return the single {@link IOUtil.ClassResources}. + * @return the associated Display */ - IOUtil.ClassResources getResource(); + Display getDisplay(); + + /** Returns the hotspot. */ + PointImmutable getHotspot(); /** * Returns true if valid, otherwise false. @@ -116,35 +161,69 @@ public abstract class Display { *

*/ void destroy(); + } - /** Returns the size, i.e. width and height. */ - DimensionImmutable getSize(); + /** + * Returns the native platform's {@link PointerIcon.PixelFormat} for pointer-icon pixel data. + *

+ * Using this value will avoid conversion within {@link #createPointerIcon(PixelRectangle, int, int)}. + *

+ */ + public abstract PixelFormat getNativePointerIconPixelFormat(); - /** Returns the hotspot. */ - PointImmutable getHotspot(); + /** + * Returns the native platform's direct NIO buffer requirement pointer-icon pixel data. + *

+ * Using this value will avoid conversion within {@link #createPointerIcon(PixelRectangle, int, int)}. + *

+ */ + public abstract boolean getNativePointerIconForceDirectNIO(); - @Override - String toString(); - } + /** + * Returns the newly created {@link PointerIcon} or null if not implemented on platform. + *

+ * See {@link PointerIcon} for lifecycle semantics. + *

+ * + * @param pngResource single PNG resource for the {@link PointerIcon}. Only the first entry of {@link IOUtil.ClassResources#resourcePaths} is used. + * @param hotX pointer hotspot x-coord, origin is upper-left corner + * @param hotY pointer hotspot y-coord, origin is upper-left corner + * + * @throws IllegalArgumentException if pngResource is null or invalid + * @throws IllegalStateException if this Display instance is not {@link #isNativeValid() valid yet}. + * @throws IOException if the pngResource could not be {@link IOUtil.ClassResources#resolve(int) resolved} + * or via the PNG parser processing the input stream. + * + * @see PointerIcon + * @see Window#setPointerIcon(PointerIcon) + */ + public abstract PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) + throws IllegalArgumentException, IllegalStateException, IOException; /** * Returns the newly created {@link PointerIcon} or null if not implemented on platform. *

* See {@link PointerIcon} for lifecycle semantics. *

+ *

+ * In case {@link #getNativePointerIconPixelFormat()} or {@link #getNativePointerIconForceDirectNIO()} + * is not matched by the given pixelrect, the pixelrect is converted + * into the required {@link PixelFormat} and NIO type. + *

* - * @param pngResource single PNG resource, only the first entry of {@link IOUtil.ClassResources#resourcePaths} is used. + * @param pixelrect {@link PixelRectangle} source for the {@link PointerIcon} * @param hotX pointer hotspot x-coord, origin is upper-left corner * @param hotY pointer hotspot y-coord, origin is upper-left corner + * + * @throws IllegalArgumentException if pixelrect is null. * @throws IllegalStateException if this Display instance is not {@link #isNativeValid() valid yet}. - * @throws MalformedURLException - * @throws InterruptedException - * @throws IOException * * @see PointerIcon * @see Window#setPointerIcon(PointerIcon) + * @see #getNativePointerIconPixelFormat() + * @see #getNativePointerIconForceDirectNIO() */ - public abstract PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws IllegalStateException, MalformedURLException, InterruptedException, IOException; + public abstract PointerIcon createPointerIcon(final PixelRectangle pixelrect, final int hotX, final int hotY) throws IllegalArgumentException, IllegalStateException; /** * Manual trigger the native creation, if it is not done yet.
diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java index 7ffbc2e83..472672fd9 100644 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java @@ -235,10 +235,10 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { glWindow.setVisible(true); glWindow.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); if( null == pointerIconTest ) { - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/jogamp-32x32.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/crosshair-lumina-trans-32x32.png" } ); final Display disp = glWindow.getScreen().getDisplay(); try { - pointerIconTest = disp.createPointerIcon(res, 16, 0); + pointerIconTest = disp.createPointerIcon(res, 16, 16); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index 346c03b15..4c7169ec4 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -34,7 +34,9 @@ package jogamp.newt; +import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.IOUtil; +import com.jogamp.common.util.ReflectionUtil; import com.jogamp.newt.Display; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.event.NEWTEvent; @@ -43,17 +45,25 @@ import com.jogamp.newt.event.NEWTEventConsumer; import jogamp.newt.event.NEWTEventTask; import com.jogamp.newt.util.EDTUtil; +import com.jogamp.opengl.util.PNGPixelRect; import java.io.IOException; -import java.net.MalformedURLException; +import java.net.URLConnection; +import java.nio.ByteBuffer; import java.util.ArrayList; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.util.PixelFormatUtil; +import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PixelFormat; +import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.util.PointImmutable; public abstract class DisplayImpl extends Display { private static int serialno = 1; + private static final boolean pngUtilAvail; static { NativeWindowFactory.addCustomShutdownHook(true /* head */, new Runnable() { @@ -64,8 +74,14 @@ public abstract class DisplayImpl extends Display { DisplayImpl.shutdownAll(); } }); + + final ClassLoader cl = DisplayImpl.class.getClassLoader(); + pngUtilAvail = ReflectionUtil.isClassAvailable("jogamp.opengl.util.pngj.PngReader", cl) && + ReflectionUtil.isClassAvailable("com.jogamp.opengl.util.PNGPixelRect", cl); } + public static final boolean isPNGUtilAvailable() { return pngUtilAvail; } + final ArrayList pointerIconList = new ArrayList(); /** Executed from EDT! */ @@ -86,13 +102,94 @@ public abstract class DisplayImpl extends Display { } @Override - public final PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { - return createPointerIcon(false /* isTemp */, pngResource, hotX, hotY); + public PixelFormat getNativePointerIconPixelFormat() { return PixelFormat.BGRA8888; } + @Override + public boolean getNativePointerIconForceDirectNIO() { return false; } + + @Override + public final PointerIcon createPointerIcon(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) + throws IllegalArgumentException, IllegalStateException, IOException + { + if( !isNativeValid() ) { + throw new IllegalStateException("Display.createPointerIcon(1): Display invalid "+this); + } + if( null == pngResource || 0 >= pngResource.resourceCount() ) { + throw new IllegalArgumentException("Null or invalid pngResource "+pngResource); + } + if( !pngUtilAvail ) { + return null; + } + final PointerIconImpl[] res = { null }; + runOnEDTIfAvail(true, new Runnable() { + public void run() { + try { + if( !DisplayImpl.this.isNativeValid() ) { + throw new IllegalStateException("Display.createPointerIcon(2): Display invalid "+DisplayImpl.this); + } + final URLConnection urlConn = pngResource.resolve(0); + if( null == urlConn ) { + throw new IOException("Could not resolve "+pngResource.resourcePaths[0]); + } + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), + getNativePointerIconPixelFormat(), + getNativePointerIconForceDirectNIO(), + 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + final long handle = createPointerIconImplChecked(image.getPixelformat(), image.getSize().getWidth(), image.getSize().getHeight(), + image.getPixels(), hotX, hotY); + final PointImmutable hotspot = new Point(hotX, hotY); + if( DEBUG_POINTER_ICON ) { + System.err.println("createPointerIconPNG.0: "+image+", handle: "+toHexString(handle)+", hot "+hotspot); + } + if( 0 != handle ) { + res[0] = new PointerIconImpl(DisplayImpl.this, image, hotspot, handle); + if( DEBUG_POINTER_ICON ) { + System.err.println("createPointerIconPNG.0: "+res[0]); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } } ); + if( null != res[0] ) { + synchronized(pointerIconList) { + pointerIconList.add(res[0]); + } + } + return res[0]; } - PointerIcon createPointerIcon(final boolean isTemp, final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { + + @Override + public final PointerIcon createPointerIcon(final PixelRectangle pixelrect, final int hotX, final int hotY) + throws IllegalArgumentException, IllegalStateException + { if( !isNativeValid() ) { throw new IllegalStateException("Display.createPointerIcon(1): Display invalid "+this); } + if( null == pixelrect ) { + throw new IllegalArgumentException("Null or pixelrect"); + } + final PixelRectangle fpixelrect; + if( getNativePointerIconPixelFormat() != pixelrect.getPixelformat() || pixelrect.isGLOriented() ) { + // conversion ! + fpixelrect = PixelFormatUtil.convert32(pixelrect, getNativePointerIconPixelFormat(), + 0 /* ddestStride */, false /* isGLOriented */, getNativePointerIconForceDirectNIO() ); + if( DEBUG_POINTER_ICON ) { + System.err.println("createPointerIconRES.0: Conversion-FMT "+pixelrect+" -> "+fpixelrect); + } + } else if( getNativePointerIconForceDirectNIO() && !Buffers.isDirect(pixelrect.getPixels()) ) { + // transfer to direct NIO + final ByteBuffer sBB = pixelrect.getPixels(); + final ByteBuffer dBB = Buffers.newDirectByteBuffer(sBB.array(), sBB.arrayOffset()); + fpixelrect = new PixelRectangle.GenericPixelRect(pixelrect.getPixelformat(), pixelrect.getSize(), pixelrect.getStride(), pixelrect.isGLOriented(), dBB); + if( DEBUG_POINTER_ICON ) { + System.err.println("createPointerIconRES.0: Conversion-NIO "+pixelrect+" -> "+fpixelrect); + } + } else { + fpixelrect = pixelrect; + if( DEBUG_POINTER_ICON ) { + System.err.println("createPointerIconRES.0: No conversion "+fpixelrect); + } + } final PointerIconImpl[] res = { null }; runOnEDTIfAvail(true, new Runnable() { public void run() { @@ -100,22 +197,63 @@ public abstract class DisplayImpl extends Display { if( !DisplayImpl.this.isNativeValid() ) { throw new IllegalStateException("Display.createPointerIcon(2): Display invalid "+DisplayImpl.this); } - res[0] = createPointerIconImpl(pngResource, hotX, hotY); + if( null != fpixelrect ) { + final long handle = createPointerIconImplChecked(fpixelrect.getPixelformat(), + fpixelrect.getSize().getWidth(), + fpixelrect.getSize().getHeight(), + fpixelrect.getPixels(), hotX, hotY); + if( 0 != handle ) { + res[0] = new PointerIconImpl(DisplayImpl.this, fpixelrect, new Point(hotX, hotY), handle); + } + } } catch (Exception e) { e.printStackTrace(); } } } ); - if( !isTemp ) { + if( null != res[0] ) { synchronized(pointerIconList) { pointerIconList.add(res[0]); } } return res[0]; } - /** Executed from EDT! */ - protected PointerIconImpl createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { - return null; + + /** + * Executed from EDT! + * + * @param pixelformat the pixels's format + * @param width the pixels's width + * @param height the pixels's height + * @param pixels the pixels + * @param hotX the PointerIcon's hot-spot x-coord + * @param hotY the PointerIcon's hot-spot x-coord + * @return if successful a valid handle (not null), otherwise null. + */ + protected final long createPointerIconImplChecked(PixelFormat pixelformat, int width, int height, final ByteBuffer pixels, final int hotX, final int hotY) { + if( getNativePointerIconPixelFormat() != pixelformat ) { + throw new IllegalArgumentException("Pixelformat no "+getNativePointerIconPixelFormat()+", but "+pixelformat); + } + if( getNativePointerIconForceDirectNIO() && !Buffers.isDirect(pixels) ) { + throw new IllegalArgumentException("pixel buffer is not direct "+pixels); + } + return createPointerIconImpl(pixelformat, width, height, pixels, hotX, hotY); + } + + /** + * Executed from EDT! + * + * @param pixelformat the pixels's format + * @param width the pixels's width + * @param height the pixels's height + * @param pixels the pixels + * @param hotX the PointerIcon's hot-spot x-coord + * @param hotY the PointerIcon's hot-spot x-coord + * @return if successful a valid handle (not null), otherwise null. + */ + protected long createPointerIconImpl(PixelFormat pixelformat, int width, int height, final ByteBuffer pixels, final int hotX, final int hotY) { + return 0; } + /** Executed from EDT! */ protected void destroyPointerIconImpl(final long displayHandle, long piHandle) { } diff --git a/src/newt/classes/jogamp/newt/PointerIconImpl.java b/src/newt/classes/jogamp/newt/PointerIconImpl.java index e2388be67..7c8535f20 100644 --- a/src/newt/classes/jogamp/newt/PointerIconImpl.java +++ b/src/newt/classes/jogamp/newt/PointerIconImpl.java @@ -27,27 +27,63 @@ */ package jogamp.newt; +import java.nio.ByteBuffer; + import javax.media.nativewindow.util.DimensionImmutable; +import javax.media.nativewindow.util.PixelFormat; +import javax.media.nativewindow.util.PixelRectangle; import javax.media.nativewindow.util.PointImmutable; -import com.jogamp.common.util.IOUtil; -import com.jogamp.common.util.IOUtil.ClassResources; import com.jogamp.newt.Display; import com.jogamp.newt.Display.PointerIcon; public class PointerIconImpl implements PointerIcon { private final DisplayImpl display; - private final IOUtil.ClassResources resource; + private final PixelFormat pixelformat; private final DimensionImmutable size; + private final ByteBuffer pixels; private final PointImmutable hotspot; private long handle; - public PointerIconImpl(DisplayImpl display, ClassResources resource, final DimensionImmutable size, final PointImmutable hotspot, final long handle) { + private int hashCode = 0; + private volatile boolean hashCodeComputed = false; + + public PointerIconImpl(final DisplayImpl display, final PixelFormat pixelformat, final DimensionImmutable size, final ByteBuffer pixels, final PointImmutable hotspot, final long handle) { this.display = display; - this.resource = resource; + this.pixelformat = pixelformat; this.size = size; + this.pixels = pixels; this.hotspot = hotspot; + this.handle=handle; } + public PointerIconImpl(final DisplayImpl display, final PixelRectangle pixelrect, final PointImmutable hotspot, final long handle) { + this.display = display; + this.pixelformat = pixelrect.getPixelformat(); + this.size = pixelrect.getSize(); + this.pixels = pixelrect.getPixels(); + this.hotspot = hotspot; + this.handle=handle; + } + + @Override + public int hashCode() { + if( !hashCodeComputed ) { // DBL CHECKED OK VOLATILE + synchronized (this) { + if( !hashCodeComputed ) { + // 31 * x == (x << 5) - x + int hash = 31 + display.getFQName().hashCode(); + hash = ((hash << 5) - hash) + pixelformat.hashCode(); + hash = ((hash << 5) - hash) + size.hashCode(); + hash = ((hash << 5) - hash) + getStride(); + hash = ((hash << 5) - hash) + ( isGLOriented() ? 1 : 0); + hash = ((hash << 5) - hash) + pixels.hashCode(); + hashCode = ((hash << 5) - hash) + hotspot.hashCode(); + } + } + } + return hashCode; + } + public synchronized final long getHandle() { return handle; } public synchronized final long validatedHandle() { synchronized(display.pointerIconList) { @@ -57,8 +93,7 @@ public class PointerIconImpl implements PointerIcon { } if( 0 == handle ) { try { - final PointerIconImpl temp = (PointerIconImpl) display.createPointerIcon(true /* isTemp */, resource, hotspot.getX(), hotspot.getY()); - handle = temp.handle; + handle = display.createPointerIconImpl(pixelformat, size.getWidth(), size.getHeight(), pixels, hotspot.getX(), hotspot.getY()); return handle; } catch (Exception e) { e.printStackTrace(); @@ -71,7 +106,9 @@ public class PointerIconImpl implements PointerIcon { @Override public final Display getDisplay() { return display; } @Override - public final IOUtil.ClassResources getResource() { return resource; } + public final PixelFormat getPixelformat() { return pixelformat; } + @Override + public final ByteBuffer getPixels() { return pixels; } @Override public synchronized final boolean isValid() { return 0 != handle; } @Override @@ -116,11 +153,19 @@ public class PointerIconImpl implements PointerIcon { return size; } @Override + public final int getStride() { + return size.getWidth() * pixelformat.bytesPerPixel(); + } + @Override + public final boolean isGLOriented() { + return false; + } + @Override public final PointImmutable getHotspot() { return hotspot; } @Override public final String toString() { - return "PointerIcon["+DisplayImpl.toHexString(super.hashCode())+", "+display.getFQName()+", "+resource.resourcePaths[0]+", 0x"+Long.toHexString(handle)+", "+size+", "+hotspot+"]"; + return "PointerIcon[obj 0x"+Integer.toHexString(super.hashCode())+", "+display.getFQName()+", 0x"+Long.toHexString(handle)+", "+pixelformat+", "+size+", "+hotspot+", pixels "+pixels+"]"; } } \ No newline at end of file diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 50f30f04d..dc9affd63 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -53,6 +53,7 @@ import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.util.DimensionImmutable; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.nativewindow.util.PixelRectangle; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.PointImmutable; import javax.media.nativewindow.util.Rectangle; @@ -61,7 +62,6 @@ import javax.media.nativewindow.util.RectangleImmutable; import jogamp.nativewindow.SurfaceUpdatedHelper; import com.jogamp.common.util.ArrayHashSet; -import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.IntBitfield; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.common.util.locks.LockFactory; @@ -1700,7 +1700,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } /** * Helper method to delegate {@link #setPointerVisibleImpl(boolean)} to - * {@link OffscreenLayerSurface#hideCursor()} or {@link OffscreenLayerSurface#setCursor(IOUtil.ClassResources, PointImmutable)}. + * {@link OffscreenLayerSurface#hideCursor()} or {@link OffscreenLayerSurface#setCursor(PixelRectangle, PointImmutable)}. *

* Note: JAWTWindow is an OffscreenLayerSurface. *

@@ -1755,7 +1755,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } /** * Helper method to delegate {@link #setPointerIconIntern(PointerIconImpl)} to - * {@link OffscreenLayerSurface#setCursor(IOUtil.ClassResources, PointImmutable)}. + * {@link OffscreenLayerSurface#setCursor(PixelRectangle, PointImmutable)} *

* Note: JAWTWindow is an OffscreenLayerSurface. *

@@ -1777,7 +1777,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer final OffscreenLayerSurface ols = (OffscreenLayerSurface) parent; try { if( null != pi ) { - return ols.setCursor(pi.getResource(), pi.getHotspot()); + return ols.setCursor(pi, pi.getHotspot()); } else { return ols.setCursor(null, null); // default } diff --git a/src/newt/classes/jogamp/newt/driver/PNGIcon.java b/src/newt/classes/jogamp/newt/driver/PNGIcon.java index ffa62978f..967acd413 100644 --- a/src/newt/classes/jogamp/newt/driver/PNGIcon.java +++ b/src/newt/classes/jogamp/newt/driver/PNGIcon.java @@ -32,6 +32,7 @@ import java.net.MalformedURLException; import java.nio.ByteBuffer; import jogamp.newt.Debug; +import jogamp.newt.DisplayImpl; import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.ReflectionUtil; @@ -45,8 +46,7 @@ public class PNGIcon { Debug.initSingleton(); final ClassLoader cl = PNGIcon.class.getClassLoader(); - avail = ReflectionUtil.isClassAvailable("jogamp.newt.driver.opengl.JoglUtilPNGIcon", cl) && - ReflectionUtil.isClassAvailable("com.jogamp.opengl.util.texture.spi.PNGImage", cl); + avail = DisplayImpl.isPNGUtilAvailable() && ReflectionUtil.isClassAvailable("jogamp.newt.driver.opengl.JoglUtilPNGIcon", cl); } /** Returns true if PNG decoder is available. */ @@ -55,7 +55,11 @@ public class PNGIcon { } /** - * Implemented for X11. + * Special implementation for X11 Window Icons + *

+ * The returned byte buffer is a direct buffer! + *

+ * * @param resources * @param data_size * @param elem_bytesize @@ -73,29 +77,4 @@ public class PNGIcon { } throw new UnsupportedOperationException(err0); } - - /** - * Implemented for Windows. - * @param resources - * @param toBGRA if true, arranges stores in BGRA888 order, otherwise RGBA888 - * @param width - * @param height - * @param data_size - * @param resourcesIdx - * @return pixels with origin at upper-left corner. - * If storing RGBA8888, component R is located on the lowest 8-bit. - * If storing BGRA8888, component B is located on the lowest 8-bit. - * Component A is located on the highest 8-bit. - * - * @throws UnsupportedOperationException if not implemented - * @throws InterruptedException - * @throws IOException - * @throws MalformedURLException - */ - public static ByteBuffer singleToRGBAImage(IOUtil.ClassResources resources, int resourceIdx, boolean toBGRA, int[] width, int[] height, int[] data_size) throws UnsupportedOperationException, InterruptedException, IOException, MalformedURLException { - if( avail ) { - return jogamp.newt.driver.opengl.JoglUtilPNGIcon.singleToRGBAImage(resources, resourceIdx, toBGRA, width, height, data_size); - } - throw new UnsupportedOperationException(err0); - } } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java index 30583c48c..d850a18af 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/DisplayDriver.java @@ -34,28 +34,25 @@ package jogamp.newt.driver.macosx; -import java.io.IOException; -import java.net.MalformedURLException; +import java.net.URLConnection; import java.nio.Buffer; import java.nio.ByteBuffer; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.util.Dimension; -import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.util.PixelFormat; +import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.IOUtil; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.newt.NewtFactory; +import com.jogamp.opengl.util.PNGPixelRect; import jogamp.newt.DisplayImpl; import jogamp.newt.NEWTJNILibLoader; -import jogamp.newt.PointerIconImpl; -import jogamp.newt.driver.PNGIcon; public class DisplayDriver extends DisplayImpl { - private static final int defaultIconWidth, defaultIconHeight; - private static final Buffer defaultIconData; + private static final PNGPixelRect defaultIconData; static { NEWTJNILibLoader.loadNEWT(); @@ -67,21 +64,23 @@ public class DisplayDriver extends DisplayImpl { throw new NativeWindowException("Failed to initialize jmethodIDs"); } { - final int[] width = { 0 }, height = { 0 }, data_size = { 0 }; - Buffer data=null; - if( PNGIcon.isAvailable() ) { + PNGPixelRect image=null; + if( DisplayImpl.isPNGUtilAvailable() ) { try { + // NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly! final IOUtil.ClassResources iconRes = NewtFactory.getWindowIcons(); - data = PNGIcon.singleToRGBAImage(iconRes, iconRes.resourceCount()-1, false /* toBGRA */, width, height, data_size); + final URLConnection urlConn = iconRes.resolve(iconRes.resourceCount()-1); + image = PNGPixelRect.read(urlConn.getInputStream(), PixelFormat.BGRA8888, true /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); } catch (Exception e) { e.printStackTrace(); } } - defaultIconWidth = width[0]; - defaultIconHeight = height[0]; - defaultIconData = data; + defaultIconData = image; if( null != defaultIconData ) { - DisplayDriver.setAppIcon0(defaultIconData, defaultIconWidth, defaultIconHeight); + final Buffer pixels = defaultIconData.getPixels(); + DisplayDriver.setAppIcon0( + pixels, Buffers.getDirectBufferByteOffset(pixels), true /* pixels_is_direct */, + defaultIconData.getSize().getWidth(), defaultIconData.getSize().getHeight()); } } @@ -112,17 +111,20 @@ public class DisplayDriver extends DisplayImpl { aDevice.close(); } + /** + * {@inheritDoc} + *

+ * NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly! + *

+ */ @Override - protected PointerIconImpl createPointerIconImpl(final IOUtil.ClassResources pngResource, final int hotX, final int hotY) throws MalformedURLException, InterruptedException, IOException { - if( PNGIcon.isAvailable() ) { - final int[] width = { 0 }, height = { 0 }, data_size = { 0 }; - if( null != pngResource && 0 < pngResource.resourceCount() ) { - final ByteBuffer data = PNGIcon.singleToRGBAImage(pngResource, 0, true /* toBGRA */, width, height, data_size); - return new PointerIconImpl( this, pngResource, new Dimension(width[0], height[0]), - new Point(hotX, hotY), createPointerIcon0(data, width[0], height[0], hotX, hotY)); - } - } - return null; + public final boolean getNativePointerIconForceDirectNIO() { return true; } + + @Override + protected final long createPointerIconImpl(PixelFormat pixelformat, int width, int height, final ByteBuffer pixels, final int hotX, final int hotY) { + return createPointerIcon0( + pixels, Buffers.getDirectBufferByteOffset(pixels), true /* pixels_is_direct */, + width, height, hotX, hotY); } @Override @@ -140,8 +142,8 @@ public class DisplayDriver extends DisplayImpl { private static native boolean initNSApplication0(); private static native void runNSApplication0(); private static native void stopNSApplication0(); - /* pp */ static native void setAppIcon0(Object iconData, int iconWidth, int iconHeight); - private static native long createPointerIcon0(Object iconData, int iconWidth, int iconHeight, int hotX, int hotY); + /* pp */ static native void setAppIcon0(Object pixels, int pixels_byte_offset, boolean pixels_is_direct, int width, int height); + private static native long createPointerIcon0(Object pixels, int pixels_byte_offset, boolean pixels_is_direct, int width, int height, int hotX, int hotY); private static native long destroyPointerIcon0(long handle); } diff --git a/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java b/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java index 216a0cb20..551929b8d 100644 --- a/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java +++ b/src/newt/classes/jogamp/newt/driver/opengl/JoglUtilPNGIcon.java @@ -32,20 +32,22 @@ import java.net.MalformedURLException; import java.net.URLConnection; import java.nio.ByteBuffer; +import javax.media.nativewindow.util.PixelFormat; + import com.jogamp.common.nio.Buffers; import com.jogamp.common.os.Platform; import com.jogamp.common.util.IOUtil; -import com.jogamp.opengl.util.texture.spi.PNGImage; +import com.jogamp.opengl.util.PNGPixelRect; public class JoglUtilPNGIcon { public static ByteBuffer arrayToX11BGRAImages(IOUtil.ClassResources resources, int[] data_size, int[] elem_bytesize) throws UnsupportedOperationException, InterruptedException, IOException, MalformedURLException { - final PNGImage[] images = new PNGImage[resources.resourceCount()]; + final PNGPixelRect[] images = new PNGPixelRect[resources.resourceCount()]; data_size[0] = 0; for(int i=0; iGetDirectBufferAddress(env, jiconData); +static NSImage * createNSImageFromData(JNIEnv *env, unsigned char * iconData, jint jiconWidth, jint jiconHeight) { + if( NULL != iconData ) { NSInteger iconWidth = (NSInteger) jiconWidth; NSInteger iconHeight = (NSInteger) jiconHeight; const NSInteger bpc = 8 /* bits per component */, spp=4 /* RGBA */, bpp = bpc * spp; @@ -319,28 +318,47 @@ static NSImage * createNSImageFromData(JNIEnv *env, jobject jiconData, jint jico * Method: setAppIcon0 */ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_setAppIcon0 - (JNIEnv *env, jobject unused, jobject jiconData, jint jiconWidth, jint jiconHeight) + (JNIEnv *env, jobject unused, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height) { + if( 0 == pixels ) { + return; + } NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSImage * nsImage = createNSImageFromData(env, jiconData, jiconWidth, jiconHeight); + // NOTE: MUST BE DIRECT BUFFER, since NSBitmapImageRep uses buffer directly! + unsigned char * pixelPtr = (unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + NSImage * nsImage = createNSImageFromData(env, pixelPtr + pixels_byte_offset, width, height); if( NULL != nsImage ) { [nsImage autorelease]; [NSApp setApplicationIconImage: nsImage]; } + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } [pool release]; } JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_macosx_DisplayDriver_createPointerIcon0 - (JNIEnv *env, jobject unused, jobject jiconData, jint jiconWidth, jint jiconHeight, jint hotX, jint hotY) + (JNIEnv *env, jobject unused, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jint hotX, jint hotY) { + if( 0 == pixels ) { + return 0; + } NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSImage * nsImage = createNSImageFromData(env, jiconData, jiconWidth, jiconHeight); + unsigned char * pixelPtr = (unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + NSImage * nsImage = createNSImageFromData(env, pixelPtr + pixels_byte_offset, width, height); NSCursor * res = NULL; if( NULL != nsImage ) { [nsImage autorelease]; NSPoint hotP = { hotX, hotY }; res = [[NSCursor alloc] initWithImage: nsImage hotSpot: hotP]; } + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } [pool release]; DBG_PRINT( "createPointerIcon0 %p\n", res); return (jlong) (intptr_t) res; diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 1fd8d0039..c20e156c1 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -2368,9 +2368,15 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowDriver_warpPointer0 JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_DisplayDriver_createBGRA8888Icon0(JNIEnv *env, jobject _unused, - jobject data, jint data_offset, jint width, jint height, jboolean isCursor, jint hotX, jint hotY) { + jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jboolean isCursor, jint hotX, jint hotY) { - const unsigned char * data_ptr = (const unsigned char *) (*env)->GetDirectBufferAddress(env, data) + data_offset; + if( 0 == pixels ) { + return 0; + } + + const unsigned char * pixelPtr = (const unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); const int bytes = 4 * width * height; // BGRA8888 DWORD dwWidth, dwHeight; @@ -2403,10 +2409,14 @@ Java_jogamp_newt_driver_windows_DisplayDriver_createBGRA8888Icon0(JNIEnv *env, j hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD)0); - memcpy(lpBits, data_ptr, bytes); + memcpy(lpBits, pixelPtr + pixels_byte_offset, bytes); ReleaseDC(NULL,hdc); + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + // Create an empty mask bitmap. HBITMAP hMonoBitmap = CreateBitmap(dwWidth,dwHeight,1,1,NULL); diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index 19e733111..b62a9b234 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -678,13 +678,15 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_DispatchMessage * Signature: (JJILjava/lang/Object;I)V */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_createPointerIcon0 - (JNIEnv *env, jclass clazz, jlong display, jobject data, jint data_offset, jint width, jint height, jint hotX, jint hotY) + (JNIEnv *env, jclass clazz, jlong display, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct, jint width, jint height, jint hotX, jint hotY) { Cursor c; - if( 0 != data ) { + if( 0 != pixels ) { Display * dpy = (Display *) (intptr_t) display; - char * data_ptr = (char *) (*env)->GetDirectBufferAddress(env, data) + data_offset; + const unsigned char * pixelPtr = (const unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); XcursorImage ci; ci.version = 1; // XCURSOR_IMAGE_VERSION; ci.size = width; // nominal size (assume square ..) @@ -693,11 +695,14 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_DisplayDriver_createPointerI ci.xhot = hotX; ci.yhot = hotY; ci.delay = 0; - ci.pixels = (XcursorPixel *)(intptr_t)data_ptr; + ci.pixels = (XcursorPixel *)(intptr_t)(pixelPtr + pixels_byte_offset); c = XcursorImageLoadCursor (dpy, &ci); - DBG_PRINT( "X11: createPointerIcon0: %p %dx%d %d/%d -> %p\n", data_ptr, width, height, hotX, hotY, (void *)c); + if ( JNI_FALSE == pixels_is_direct ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + DBG_PRINT( "X11: createPointerIcon0: %p %dx%d %d/%d -> %p\n", (pixelPtr+pixels_byte_offset), width, height, hotX, hotY, (void *)c); } else { c = 0; diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index da2778004..54b85c243 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -512,7 +512,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 jint visualID, jlong javaObjectAtom, jlong windowDeleteAtom, jint x, jint y, jint width, jint height, jboolean autoPosition, int flags, - jint iconDataSize, jobject iconData) + jint pixelDataSize, jobject pixels, jint pixels_byte_offset, jboolean pixels_is_direct) { Display * dpy = (Display *)(intptr_t)display; Atom wm_delete_atom = (Atom)windowDeleteAtom; @@ -632,10 +632,16 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 { XEvent event; int left=0, right=0, top=0, bottom=0; - - if( 0 < iconDataSize && NULL != iconData ) { - const unsigned char * iconDataPtr = (const unsigned char *) (*env)->GetDirectBufferAddress(env, iconData); - NewtWindows_setIcon(dpy, window, (int)iconDataSize, iconDataPtr); + const unsigned char * pixelPtr = NULL; + + // NOTE: MUST BE DIRECT BUFFER, since _NET_WM_ICON Atom uses buffer directly! + DBG_PRINT("X11: CreateWindow icon: size %d, pixels %p, offset %d, direct %d\n", pixelDataSize, (void*)pixels, pixels_byte_offset, pixels_is_direct); + if( 0 < pixelDataSize && NULL != pixels ) { + pixelPtr = (const unsigned char *) ( JNI_TRUE == pixels_is_direct ? + (*env)->GetDirectBufferAddress(env, pixels) : + (*env)->GetPrimitiveArrayCritical(env, pixels, NULL) ); + DBG_PRINT("X11: CreateWindow icon: NIO %p\n", pixelPtr); + NewtWindows_setIcon(dpy, window, (int)pixelDataSize, pixelPtr+pixels_byte_offset); } XMapWindow(dpy, window); @@ -643,6 +649,10 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_WindowDriver_CreateWindow0 XSync(dpy, False); + if( JNI_FALSE == pixels_is_direct && NULL != pixelPtr ) { + (*env)->ReleasePrimitiveArrayCritical(env, pixels, (void*)pixelPtr, JNI_ABORT); + } + // send insets before visibility, allowing java code a proper sync point! NewtWindows_updateInsets(env, jwindow, dpy, window, &left, &right, &top, &bottom); (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java index 8cc676291..780338492 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java @@ -29,6 +29,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es2.newt; import java.io.IOException; +import java.net.URLConnection; import com.jogamp.common.util.IOUtil; import com.jogamp.newt.Display; @@ -47,6 +48,7 @@ import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.PNGPixelRect; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import javax.media.nativewindow.NativeWindowFactory; @@ -171,25 +173,55 @@ public class TestGearsES2NEWT extends UITestCase { } }); - final PointerIcon pointerIconOne; + final PointerIcon[] pointerIcons = { null, null, null }; { - PointerIcon _pointerIconOne = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); final Display disp = glWindow.getScreen().getDisplay(); disp.createNative(); - try { - _pointerIconOne = disp.createPointerIcon(res, 32, 0); - } catch (Exception e) { - e.printStackTrace(); + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/crosshair-lumina-trans-32x32.png" } ); + try { + _pointerIcon = disp.createPointerIcon(res, 16, 16); + System.err.println("Create PointerIcon #01: "+_pointerIcon); + } catch (Exception e) { + e.printStackTrace(); + } + pointerIcons[0] = _pointerIcon; + } + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); + try { + _pointerIcon = disp.createPointerIcon(res, 32, 0); + System.err.println("Create PointerIcon #02: "+_pointerIcon); + } catch (Exception e) { + e.printStackTrace(); + } + pointerIcons[1] = _pointerIcon; + } + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "crosshair-lumina-trans-64x64.png" } ); + try { + final URLConnection urlConn = res.resolve(0); + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + System.err.println("Create PointerIcon #03: "+image); + _pointerIcon = disp.createPointerIcon(image, 32, 32); + System.err.println("Create PointerIcon #03: "+_pointerIcon); + } catch (Exception e) { + e.printStackTrace(); + } + pointerIcons[2] = _pointerIcon; } - pointerIconOne = _pointerIconOne; } if( setPointerIcon ) { - glWindow.setPointerIcon(pointerIconOne); + glWindow.setPointerIcon(pointerIcons[0]); System.err.println("Set PointerIcon: "+glWindow.getPointerIcon()); } glWindow.addKeyListener(new KeyAdapter() { + int pointerIconIdx = 0; + @Override public void keyPressed(final KeyEvent e) { if( e.isAutoRepeat() ) { @@ -246,7 +278,14 @@ public class TestGearsES2NEWT extends UITestCase { final Thread t = glWindow.setExclusiveContextThread(null); System.err.println("[set pointer-icon pre]"); final PointerIcon currentPI = glWindow.getPointerIcon(); - glWindow.setPointerIcon( currentPI == pointerIconOne ? null : pointerIconOne); + final PointerIcon newPI; + if( pointerIconIdx >= pointerIcons.length ) { + newPI=null; + pointerIconIdx=0; + } else { + newPI=pointerIcons[pointerIconIdx++]; + } + glWindow.setPointerIcon( newPI ); System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon()); glWindow.setExclusiveContextThread(t); } }.start(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java new file mode 100644 index 000000000..bb9bc42a8 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java @@ -0,0 +1,54 @@ +/** + * 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.opengl.test.junit.jogl.util.texture; + +public class PNGTstFiles { + static public final String[] allBasenames = { + "test-ntscN_3-01-160x90", + "test-ntscN_4-01-160x90", + "test-ntscNG4-01-160x90", + "test-ntscI_3-01-160x90", + "test-ntscI_4-01-160x90", + "test-ntscIG3-01-160x90", + "test-ntscIG4-01-160x90", + "test-ntscP_3-01-160x90", + "test-ntscP_4-01-160x90", + "grayscale_texture", + "bug724-transparent-grey_orig", + "bug724-transparent-grey_gimpexp", + "crosshair-lumina-trans-32x32", + "crosshair-lumina-trans-64x64", + }; + static public final String[] greyBasenames = { + "grayscale_texture", + "bug724-transparent-grey_orig", + "bug724-transparent-grey_gimpexp", + "crosshair-lumina-trans-32x32", + "crosshair-lumina-trans-64x64", + }; +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage00NEWT.java deleted file mode 100644 index 3ace5ab6a..000000000 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage00NEWT.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.test.junit.jogl.util.texture; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URLConnection; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.FixMethodOrder; -import org.junit.runners.MethodSorters; - -import com.jogamp.common.util.IOUtil; -import com.jogamp.opengl.test.junit.util.UITestCase; -import com.jogamp.opengl.util.texture.spi.PNGImage; - -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestPNGImage00NEWT extends UITestCase { - @Test - public void testPNGReadWriteAndCompare() throws InterruptedException, IOException, MalformedURLException { - final File out1_f=new File(getSimpleTestName(".")+"-PNGImageTest1.png"); - final File out2_f=new File(getSimpleTestName(".")+"-PNGImageTest2.png"); - final File out2F_f=new File(getSimpleTestName(".")+"-PNGImageTest2Flipped.png"); - final File out2R_f=new File(getSimpleTestName(".")+"-PNGImageTest2Reversed.png"); - final File out2RF_f=new File(getSimpleTestName(".")+"-PNGImageTest2ReversedFlipped.png"); - final String url_s="jogl/util/data/av/test-ntsc01-57x32.png"; - URLConnection urlConn = IOUtil.getResource(url_s, this.getClass().getClassLoader()); - PNGImage image1 = PNGImage.read(urlConn.getInputStream()); - System.err.println("PNGImage - Orig: "+image1); - image1.write(out1_f, true); - { - Assert.assertEquals(image1.getData(), PNGImage.read(out1_f.toURI().toURL().openStream()).getData()); - } - - final PNGImage image2 = PNGImage.createFromData(image1.getWidth(), image1.getHeight(), - image1.getDpi()[0], image1.getDpi()[1], - image1.getBytesPerPixel(), false /* reverseChannels */, image1.isGLOriented(), image1.getData()); - image2.write(out2_f, true); - { - Assert.assertEquals(image1.getData(), PNGImage.read(out2_f.toURI().toURL().openStream()).getData()); - } - - // flipped - final PNGImage image2F = PNGImage.createFromData(image1.getWidth(), image1.getHeight(), - image1.getDpi()[0], image1.getDpi()[1], - image1.getBytesPerPixel(), false /* reverseChannels */, !image1.isGLOriented(), image1.getData()); - image2F.write(out2F_f, true); - - // reversed channels - final PNGImage image2R = PNGImage.createFromData(image1.getWidth(), image1.getHeight(), - image1.getDpi()[0], image1.getDpi()[1], - image1.getBytesPerPixel(), true /* reverseChannels */, image1.isGLOriented(), image1.getData()); - image2R.write(out2R_f, true); - - // reversed channels and flipped - final PNGImage image2RF = PNGImage.createFromData(image1.getWidth(), image1.getHeight(), - image1.getDpi()[0], image1.getDpi()[1], - image1.getBytesPerPixel(), true /* reverseChannels */, !image1.isGLOriented(), image1.getData()); - image2RF.write(out2RF_f, true); - } - - public static void main(String args[]) { - org.junit.runner.JUnitCore.main(TestPNGImage00NEWT.class.getName()); - } -} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage01NEWT.java deleted file mode 100644 index 29e041908..000000000 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGImage01NEWT.java +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.test.junit.jogl.util.texture; - -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URLConnection; - -import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLProfile; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.FixMethodOrder; -import org.junit.runners.MethodSorters; - -import com.jogamp.common.util.IOUtil; -import com.jogamp.newt.opengl.GLWindow; -import com.jogamp.opengl.test.junit.jogl.demos.TextureDraw01Accessor; -import com.jogamp.opengl.test.junit.jogl.demos.es2.TextureDraw01ES2Listener; -import com.jogamp.opengl.test.junit.util.MiscUtils; -import com.jogamp.opengl.test.junit.util.QuitAdapter; -import com.jogamp.opengl.test.junit.util.UITestCase; -import com.jogamp.opengl.util.Animator; -import com.jogamp.opengl.util.GLReadBufferUtil; -import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; -import com.jogamp.opengl.util.texture.TextureData; -import com.jogamp.opengl.util.texture.TextureIO; -import com.jogamp.opengl.util.texture.spi.PNGImage; - -/** - * Test reading and displaying a PNG image. - *

- * Main function accepts arbitrary PNG file name for manual tests. - *

- */ -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestPNGImage01NEWT extends UITestCase { - - static boolean showFPS = false; - static long duration = 200; // ms - - public void testImpl(final InputStream istream) throws InterruptedException, IOException { - final PNGImage image = PNGImage.read(istream); - Assert.assertNotNull(image); - final boolean hasAlpha = 4 == image.getBytesPerPixel(); - System.err.println("PNGImage: "+image); - - final GLReadBufferUtil screenshot = new GLReadBufferUtil(true, false); - final GLProfile glp = GLProfile.getGL2ES2(); - final GLCapabilities caps = new GLCapabilities(glp); - if( hasAlpha ) { - caps.setAlphaBits(1); - } - - final int internalFormat; - if(glp.isGL2ES3()) { - internalFormat = hasAlpha ? GL.GL_RGBA8 : GL.GL_RGB8; - } else { - internalFormat = hasAlpha ? GL.GL_RGBA : GL.GL_RGB; - } - final TextureData texData = new TextureData(glp, internalFormat, - image.getWidth(), - image.getHeight(), - 0, - new GLPixelAttributes(image.getGLFormat(), image.getGLType()), - false /* mipmap */, - false /* compressed */, - false /* must flip-vert */, - image.getData(), - null); - - // final TextureData texData = TextureIO.newTextureData(glp, istream, false /* mipmap */, TextureIO.PNG); - System.err.println("TextureData: "+texData); - - final GLWindow glad = GLWindow.create(caps); - glad.setTitle("TestPNGImage01NEWT"); - // Size OpenGL to Video Surface - glad.setSize(texData.getWidth(), texData.getHeight()); - - // load texture from file inside current GL context to match the way - // the bug submitter was doing it - final TextureDraw01ES2Listener gle = new TextureDraw01ES2Listener( texData, 0 ) ; - // gle.setClearColor(new float[] { 1.0f, 0.0f, 0.0f, 1.0f } ); - - glad.addGLEventListener(gle); - glad.addGLEventListener(new GLEventListener() { - boolean shot = false; - - @Override public void init(GLAutoDrawable drawable) { - System.err.println("Chosen Caps: " + drawable.getChosenGLCapabilities()); - System.err.println("GL ctx: " + drawable.getGL().getContext()); - } - - @Override public void display(GLAutoDrawable drawable) { - // 1 snapshot - if(null!=((TextureDraw01Accessor)gle).getTexture() && !shot) { - shot = true; - snapshot(0, null, drawable.getGL(), screenshot, TextureIO.PNG, null); - } - } - - @Override public void dispose(GLAutoDrawable drawable) { } - @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { } - }); - - Animator animator = new Animator(glad); - animator.setUpdateFPSFrames(60, showFPS ? System.err : null); - QuitAdapter quitAdapter = new QuitAdapter(); - glad.addKeyListener(quitAdapter); - glad.addWindowListener(quitAdapter); - glad.setVisible(true); - animator.start(); - - while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration() + * Main function accepts arbitrary PNG file name for manual tests. + *

+ */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestPNGPixelRect01NEWT extends UITestCase { + static boolean showFPS = false; + static long duration = 200; // ms + + public void testImpl(final int num, final String basename, final InputStream istream, final PixelFormat destFmt) throws InterruptedException, IOException { + final GLProfile glp = GLProfile.getGL2ES2(); + final PNGPixelRect image = PNGPixelRect.read(istream, destFmt, true /* directBuffer */, 0 /* destMinStrideInBytes */, true /* destIsGLOriented */); + Assert.assertNotNull(image); + final GLPixelAttributes glpa = GLPixelAttributes.convert(image.getPixelformat(), glp); + final boolean hasAlpha = 4 == glpa.bytesPerPixel; + System.err.println("PNGPixelRect: "+basename+", "+image+", glpa "+glpa); + + final GLReadBufferUtil screenshot = new GLReadBufferUtil(true, false); + final GLCapabilities caps = new GLCapabilities(glp); + if( hasAlpha ) { + caps.setAlphaBits(1); + } + + final int internalFormat; + if(glp.isGL2ES3()) { + internalFormat = hasAlpha ? GL.GL_RGBA8 : GL.GL_RGB8; + } else { + internalFormat = hasAlpha ? GL.GL_RGBA : GL.GL_RGB; + } + final TextureData texData = new TextureData(glp, internalFormat, + image.getSize().getWidth(), + image.getSize().getHeight(), + 0, + glpa, + false /* mipmap */, + false /* compressed */, + false /* must flip-vert */, + image.getPixels(), + null); + + // final TextureData texData = TextureIO.newTextureData(glp, istream, false /* mipmap */, TextureIO.PNG); + System.err.println("TextureData: "+texData); + + final GLWindow glad = GLWindow.create(caps); + glad.setTitle(this.getSimpleTestName(".")); + // Size OpenGL to Video Surface + glad.setSize(texData.getWidth(), texData.getHeight()); + + // load texture from file inside current GL context to match the way + // the bug submitter was doing it + final TextureDraw01ES2Listener gle = new TextureDraw01ES2Listener( texData, 0 ) ; + // gle.setClearColor(new float[] { 1.0f, 0.0f, 0.0f, 1.0f } ); + + glad.addGLEventListener(gle); + glad.addGLEventListener(new GLEventListener() { + boolean shot = false; + + @Override public void init(GLAutoDrawable drawable) { + System.err.println("Chosen Caps: " + drawable.getChosenGLCapabilities()); + System.err.println("GL ctx: " + drawable.getGL().getContext()); + } + + @Override public void display(GLAutoDrawable drawable) { + // 1 snapshot + if(null!=((TextureDraw01Accessor)gle).getTexture() && !shot) { + shot = true; + snapshot(num, basename, drawable.getGL(), screenshot, TextureIO.PNG, null); + } + } + + @Override public void dispose(GLAutoDrawable drawable) { } + @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { } + }); + + Animator animator = new Animator(glad); + animator.setUpdateFPSFrames(60, showFPS ? System.err : null); + QuitAdapter quitAdapter = new QuitAdapter(); + glad.addKeyListener(quitAdapter); + glad.addWindowListener(quitAdapter); + glad.setVisible(true); + animator.start(); + + while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration() "+destFmt); + final PixelRectangle imageConv1 = PixelFormatUtil.convert32(image1, destFmt, destMinStrideInBytes, destIsGLOriented, false /* nio */); + System.err.println("PNGPixelRect - Conv1: "+imageConv1); + final PixelRectangle imageConv2 = PixelFormatUtil.convert32(imageConv1, image1.getPixelformat(), image1.getStride(), image1.isGLOriented(), false /* nio */); + System.err.println("PNGPixelRect - Conv2: "+imageConv2); + Assert.assertEquals(image1.getPixels(), imageConv2.getPixels()); + } + } + + public static void main(String args[]) { + org.junit.runner.JUnitCore.main(TestPixelFormatUtil01NEWT.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png new file mode 100644 index 000000000..92279640b Binary files /dev/null and b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png differ diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png new file mode 100644 index 000000000..9be285335 Binary files /dev/null and b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png differ diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java index 69874df6b..70d01ae66 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java @@ -28,25 +28,27 @@ package com.jogamp.opengl.test.junit.newt.parenting; import java.awt.Frame; +import java.net.URLConnection; import javax.media.nativewindow.util.InsetsImmutable; import com.jogamp.common.util.IOUtil; import com.jogamp.newt.Display; -import com.jogamp.newt.Window; import com.jogamp.newt.Display.PointerIcon; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.QuitAdapter; +import com.jogamp.opengl.util.PNGPixelRect; public class NewtAWTReparentingKeyAdapter extends KeyAdapter { final Frame frame; final NewtCanvasAWT newtCanvasAWT; final GLWindow glWindow; final QuitAdapter quitAdapter; - PointerIcon pointerIconTest = null; + PointerIcon[] pointerIcons = null; + int pointerIconIdx = 0; public NewtAWTReparentingKeyAdapter(Frame frame, NewtCanvasAWT newtCanvasAWT, GLWindow glWindow, QuitAdapter quitAdapter) { this.frame = frame; @@ -144,13 +146,46 @@ public class NewtAWTReparentingKeyAdapter extends KeyAdapter { } } }.start(); } else if(e.getKeySymbol() == KeyEvent.VK_C ) { - if( null == pointerIconTest ) { - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/jogamp-32x32.png" } ); - final Display disp = glWindow.getScreen().getDisplay(); - try { - pointerIconTest = disp.createPointerIcon(res, 16, 0); - } catch (Exception err) { - err.printStackTrace(); + if( null == pointerIcons ) { + { + pointerIcons = new PointerIcon[3]; + final Display disp = glWindow.getScreen().getDisplay(); + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/crosshair-lumina-trans-32x32.png" } ); + try { + _pointerIcon = disp.createPointerIcon(res, 16, 16); + System.err.println("Create PointerIcon #01: "+_pointerIcon); + } catch (Exception ex) { + ex.printStackTrace(); + } + pointerIcons[0] = _pointerIcon; + } + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); + try { + _pointerIcon = disp.createPointerIcon(res, 32, 0); + System.err.println("Create PointerIcon #02: "+_pointerIcon); + } catch (Exception ex) { + ex.printStackTrace(); + } + pointerIcons[1] = _pointerIcon; + } + { + PointerIcon _pointerIcon = null; + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "crosshair-lumina-trans-64x64.png" } ); + try { + final URLConnection urlConn = res.resolve(0); + final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + System.err.println("Create PointerIcon #03: "+image); + _pointerIcon = disp.createPointerIcon(image, 32, 32); + System.err.println("Create PointerIcon #03: "+_pointerIcon); + } catch (Exception ex) { + ex.printStackTrace(); + } + pointerIcons[2] = _pointerIcon; + } } } new Thread() { @@ -158,7 +193,14 @@ public class NewtAWTReparentingKeyAdapter extends KeyAdapter { final Thread t = glWindow.setExclusiveContextThread(null); System.err.println("[set pointer-icon pre]"); final PointerIcon currentPI = glWindow.getPointerIcon(); - glWindow.setPointerIcon( currentPI == pointerIconTest ? null : pointerIconTest); + final PointerIcon newPI; + if( pointerIconIdx >= pointerIcons.length ) { + newPI=null; + pointerIconIdx=0; + } else { + newPI=pointerIcons[pointerIconIdx++]; + } + glWindow.setPointerIcon( newPI ); System.err.println("[set pointer-icon post] "+currentPI+" -> "+glWindow.getPointerIcon()); glWindow.setExclusiveContextThread(t); } }.start(); -- cgit v1.2.3 From 1a0b3287870beca22b0a03aa604fc6a5574a962b Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 9 Jan 2014 18:34:33 +0100 Subject: Bug 676: Use proper pointer icon images (artwork) .. shameless inspired by KDE's Oxgen scheme .. (they are best) --- make/resources/assets-test/crosshair-grey-alpha-64x64.png | Bin 0 -> 424 bytes .../assets-test/crosshair-lumina-trans-64x64.png | Bin 424 -> 0 bytes .../resources/assets/newt/data/cross-grey-alpha-16x16.png | Bin 0 -> 286 bytes .../assets/newt/data/crosshair-lumina-trans-32x32.png | Bin 213 -> 0 bytes .../assets/newt/data/pointer-grey-alpha-16x24.png | Bin 0 -> 511 bytes .../com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java | 4 ++-- .../test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java | 12 ++++++------ .../opengl/test/junit/jogl/util/texture/PNGTstFiles.java | 8 ++++---- .../junit/jogl/util/texture/cross-grey-alpha-16x16.png | Bin 0 -> 286 bytes .../jogl/util/texture/crosshair-lumina-trans-32x32.png | Bin 213 -> 0 bytes .../jogl/util/texture/crosshair-lumina-trans-64x64.png | Bin 424 -> 0 bytes .../junit/jogl/util/texture/pointer-grey-alpha-16x24.png | Bin 0 -> 511 bytes .../newt/parenting/NewtAWTReparentingKeyAdapter.java | 14 +++++++------- 13 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 make/resources/assets-test/crosshair-grey-alpha-64x64.png delete mode 100644 make/resources/assets-test/crosshair-lumina-trans-64x64.png create mode 100644 make/resources/assets/newt/data/cross-grey-alpha-16x16.png delete mode 100644 make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png create mode 100644 make/resources/assets/newt/data/pointer-grey-alpha-16x24.png create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/cross-grey-alpha-16x16.png delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png delete mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/texture/pointer-grey-alpha-16x24.png (limited to 'make/resources/assets/newt/data') diff --git a/make/resources/assets-test/crosshair-grey-alpha-64x64.png b/make/resources/assets-test/crosshair-grey-alpha-64x64.png new file mode 100644 index 000000000..9be285335 Binary files /dev/null and b/make/resources/assets-test/crosshair-grey-alpha-64x64.png differ diff --git a/make/resources/assets-test/crosshair-lumina-trans-64x64.png b/make/resources/assets-test/crosshair-lumina-trans-64x64.png deleted file mode 100644 index 9be285335..000000000 Binary files a/make/resources/assets-test/crosshair-lumina-trans-64x64.png and /dev/null differ diff --git a/make/resources/assets/newt/data/cross-grey-alpha-16x16.png b/make/resources/assets/newt/data/cross-grey-alpha-16x16.png new file mode 100644 index 000000000..303c454fa Binary files /dev/null and b/make/resources/assets/newt/data/cross-grey-alpha-16x16.png differ diff --git a/make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png b/make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png deleted file mode 100644 index 92279640b..000000000 Binary files a/make/resources/assets/newt/data/crosshair-lumina-trans-32x32.png and /dev/null differ diff --git a/make/resources/assets/newt/data/pointer-grey-alpha-16x24.png b/make/resources/assets/newt/data/pointer-grey-alpha-16x24.png new file mode 100644 index 000000000..98b2c8640 Binary files /dev/null and b/make/resources/assets/newt/data/pointer-grey-alpha-16x24.png differ diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java index 472672fd9..7a36505c1 100644 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java @@ -235,10 +235,10 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { glWindow.setVisible(true); glWindow.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); if( null == pointerIconTest ) { - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/crosshair-lumina-trans-32x32.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-gray-alpha-16x16.png" } ); final Display disp = glWindow.getScreen().getDisplay(); try { - pointerIconTest = disp.createPointerIcon(res, 16, 16); + pointerIconTest = disp.createPointerIcon(res, 8, 8); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java index 780338492..059a930ed 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java @@ -179,9 +179,9 @@ public class TestGearsES2NEWT extends UITestCase { disp.createNative(); { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/crosshair-lumina-trans-32x32.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } ); try { - _pointerIcon = disp.createPointerIcon(res, 16, 16); + _pointerIcon = disp.createPointerIcon(res, 8, 8); System.err.println("Create PointerIcon #01: "+_pointerIcon); } catch (Exception e) { e.printStackTrace(); @@ -190,9 +190,9 @@ public class TestGearsES2NEWT extends UITestCase { } { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/pointer-grey-alpha-16x24.png" } ); try { - _pointerIcon = disp.createPointerIcon(res, 32, 0); + _pointerIcon = disp.createPointerIcon(res, 0, 0); System.err.println("Create PointerIcon #02: "+_pointerIcon); } catch (Exception e) { e.printStackTrace(); @@ -201,12 +201,12 @@ public class TestGearsES2NEWT extends UITestCase { } { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "crosshair-lumina-trans-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); try { final URLConnection urlConn = res.resolve(0); final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); System.err.println("Create PointerIcon #03: "+image); - _pointerIcon = disp.createPointerIcon(image, 32, 32); + _pointerIcon = disp.createPointerIcon(image, 32, 0); System.err.println("Create PointerIcon #03: "+_pointerIcon); } catch (Exception e) { e.printStackTrace(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java index bb9bc42a8..e3ad7fc03 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/PNGTstFiles.java @@ -41,14 +41,14 @@ public class PNGTstFiles { "grayscale_texture", "bug724-transparent-grey_orig", "bug724-transparent-grey_gimpexp", - "crosshair-lumina-trans-32x32", - "crosshair-lumina-trans-64x64", + "cross-gray-alpha-16x16", + "pointer-gray-alpha-16x24", }; static public final String[] greyBasenames = { "grayscale_texture", "bug724-transparent-grey_orig", "bug724-transparent-grey_gimpexp", - "crosshair-lumina-trans-32x32", - "crosshair-lumina-trans-64x64", + "cross-gray-alpha-16x16", + "pointer-gray-alpha-16x24", }; } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/cross-grey-alpha-16x16.png b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/cross-grey-alpha-16x16.png new file mode 100644 index 000000000..303c454fa Binary files /dev/null and b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/cross-grey-alpha-16x16.png differ diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png deleted file mode 100644 index 92279640b..000000000 Binary files a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-32x32.png and /dev/null differ diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png deleted file mode 100644 index 9be285335..000000000 Binary files a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/crosshair-lumina-trans-64x64.png and /dev/null differ diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/pointer-grey-alpha-16x24.png b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/pointer-grey-alpha-16x24.png new file mode 100644 index 000000000..98b2c8640 Binary files /dev/null and b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/pointer-grey-alpha-16x24.png differ diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java index 70d01ae66..dc9aac8ea 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java @@ -152,9 +152,9 @@ public class NewtAWTReparentingKeyAdapter extends KeyAdapter { final Display disp = glWindow.getScreen().getDisplay(); { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/crosshair-lumina-trans-32x32.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/cross-grey-alpha-16x16.png" } ); try { - _pointerIcon = disp.createPointerIcon(res, 16, 16); + _pointerIcon = disp.createPointerIcon(res, 8, 8); System.err.println("Create PointerIcon #01: "+_pointerIcon); } catch (Exception ex) { ex.printStackTrace(); @@ -163,9 +163,9 @@ public class NewtAWTReparentingKeyAdapter extends KeyAdapter { } { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "newt/data/pointer-grey-alpha-16x24.png" } ); try { - _pointerIcon = disp.createPointerIcon(res, 32, 0); + _pointerIcon = disp.createPointerIcon(res, 0, 0); System.err.println("Create PointerIcon #02: "+_pointerIcon); } catch (Exception ex) { ex.printStackTrace(); @@ -174,12 +174,12 @@ public class NewtAWTReparentingKeyAdapter extends KeyAdapter { } { PointerIcon _pointerIcon = null; - final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "crosshair-lumina-trans-64x64.png" } ); + final IOUtil.ClassResources res = new IOUtil.ClassResources(glWindow.getClass(), new String[] { "jogamp-pointer-64x64.png" } ); try { final URLConnection urlConn = res.resolve(0); final PNGPixelRect image = PNGPixelRect.read(urlConn.getInputStream(), null, false /* directBuffer */, 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); System.err.println("Create PointerIcon #03: "+image); - _pointerIcon = disp.createPointerIcon(image, 32, 32); + _pointerIcon = disp.createPointerIcon(image, 32, 0); System.err.println("Create PointerIcon #03: "+_pointerIcon); } catch (Exception ex) { ex.printStackTrace(); @@ -231,4 +231,4 @@ public class NewtAWTReparentingKeyAdapter extends KeyAdapter { } }.start(); } } -} \ No newline at end of file +} -- cgit v1.2.3