diff options
author | Sven Gothel <[email protected]> | 2023-03-31 11:06:44 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-03-31 11:06:44 +0200 |
commit | 4f32f3aba62a73cafecec8af461cff4d0d475882 (patch) | |
tree | 58f6e7f0800a1ca8b793966520d6008cc6f2080b /src/graphui/classes/com/jogamp/graph/ui/gl | |
parent | 759a381963476e2e64b7afba0d6ef2bafeb35417 (diff) |
GraphUI: Relocate com.jogamp.graph.ui.gl.* -> com.jogamp.graph.ui.*, resolve GL/VK abstraction at a later time differently
Actual GPU rendering toolkit dependency can be abstracted differently, i.e. GPU <- { GL, VK } etc.
Diffstat (limited to 'src/graphui/classes/com/jogamp/graph/ui/gl')
13 files changed, 0 insertions, 3893 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/GraphShape.java b/src/graphui/classes/com/jogamp/graph/ui/gl/GraphShape.java deleted file mode 100644 index f2c60a12c..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/GraphShape.java +++ /dev/null @@ -1,200 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl; - -import java.util.ArrayList; -import java.util.List; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.curve.opengl.GLRegion; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.Vertex.Factory; -import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.math.geom.AABBox; -import com.jogamp.opengl.util.texture.TextureSequence; - -/** - * Graph based {@link GLRegion} UI {@link Shape} - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * GraphUI is intended to become an immediate- and retained-mode API. - * </p> - * @see Scene - */ -public abstract class GraphShape extends Shape { - protected final Factory<? extends Vertex> vertexFactory; - - protected final int renderModes; - protected GLRegion region = null; - protected float oshapeSharpness = OutlineShape.DEFAULT_SHARPNESS; - private int regionQuality = Region.MAX_QUALITY; - private final List<GLRegion> dirtyRegions = new ArrayList<GLRegion>(); - - /** - * Create a Graph based {@link GLRegion} UI {@link Shape}. - * - * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. - */ - public GraphShape(final int renderModes) { - super(); - this.vertexFactory = OutlineShape.getDefaultVertexFactory(); - this.renderModes = renderModes; - } - - /** Return Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. */ - public final int getRenderModes() { return renderModes; } - - public final int getQuality() { return regionQuality; } - public final void setQuality(final int q) { - this.regionQuality = q; - if( null != region ) { - region.setQuality(q); - } - } - public final void setSharpness(final float sharpness) { - this.oshapeSharpness = sharpness; - markShapeDirty(); - } - public final float getSharpness() { - return oshapeSharpness; - } - - @Override - public boolean hasColorChannel() { - return Region.hasColorChannel(renderModes) || Region.hasColorTexture(renderModes); - } - - private final void clearDirtyRegions(final GL2ES2 gl) { - for(final GLRegion r : dirtyRegions) { - r.destroy(gl); - } - dirtyRegions.clear(); - } - - @Override - protected final void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer) { - clearImpl(gl, renderer); - clearDirtyRegions(gl); - if( null != region ) { - region.clear(gl); - } - } - - @Override - protected final void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer) { - destroyImpl(gl, renderer); - clearDirtyRegions(gl); - if( null != region ) { - region.destroy(gl); - region = null; - } - } - - @Override - protected final void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount, final float[] rgba) { - if( null != rgba ) { - renderer.getRenderState().setColorStatic(rgba); - } - region.draw(gl, renderer, sampleCount); - } - - protected GLRegion createGLRegion(final GLProfile glp) { - return GLRegion.create(glp, renderModes, null); - } - - @Override - protected final void validateImpl(final GLProfile glp, final GL2ES2 gl) { - if( null != gl ) { - clearDirtyRegions(gl); - } - if( isShapeDirty() || null == region ) { - if( null == region ) { - region = createGLRegion(glp); - } else if( null == gl ) { - dirtyRegions.add(region); - region = createGLRegion(glp); - } else { - region.clear(gl); - } - addShapeToRegion(); - if( hasDebugBox() ) { - addDebugOutline(); - } - region.setQuality(regionQuality); - } else if( isStateDirty() ) { - region.markStateDirty(); - } - } - - private final float[] dbgColor = {0.3f, 0.3f, 0.3f, 0.5f}; - - protected void addDebugOutline() { - final OutlineShape shape = new OutlineShape(vertexFactory); - final float x1 = box.getMinX(); - final float x2 = box.getMaxX(); - final float y1 = box.getMinY(); - final float y2 = box.getMaxY(); - final float z = box.getCenter()[2]; // 0; // box.getMinZ() + 0.025f; - { - // Outer OutlineShape as Winding.CCW. - shape.moveTo(x1, y1, z); - shape.lineTo(x2, y1, z); - shape.lineTo(x2, y2, z); - shape.lineTo(x1, y2, z); - shape.lineTo(x1, y1, z); - shape.closeLastOutline(true); - shape.addEmptyOutline(); - } - { - // Inner OutlineShape as Winding.CW. - final float dxy0 = box.getWidth() < box.getHeight() ? box.getWidth() : box.getHeight(); - final float dxy = dxy0 * getDebugBox(); - shape.moveTo(x1+dxy, y1+dxy, z); - shape.lineTo(x1+dxy, y2-dxy, z); - shape.lineTo(x2-dxy, y2-dxy, z); - shape.lineTo(x2-dxy, y1+dxy, z); - shape.lineTo(x1+dxy, y1+dxy, z); - shape.closeLastOutline(true); - } - shape.setIsQuadraticNurbs(); - shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, null, dbgColor); - } - - protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { } - - protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { } - - protected abstract void addShapeToRegion(); - -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/gl/Scene.java deleted file mode 100644 index 3326f9e97..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/Scene.java +++ /dev/null @@ -1,1073 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl; - -import java.io.File; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.Locale; - -import com.jogamp.opengl.FPSCounter; -import com.jogamp.opengl.GL; -import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLAutoDrawable; -import com.jogamp.opengl.GLCapabilitiesImmutable; -import com.jogamp.opengl.GLEventListener; -import com.jogamp.opengl.GLException; -import com.jogamp.opengl.GLRunnable; -import com.jogamp.opengl.fixedfunc.GLMatrixFunc; -import com.jogamp.common.nio.Buffers; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.curve.opengl.RenderState; -import com.jogamp.newt.event.GestureHandler; -import com.jogamp.newt.event.InputEvent; -import com.jogamp.newt.event.MouseEvent; -import com.jogamp.newt.event.MouseListener; -import com.jogamp.newt.event.PinchToZoomGesture; -import com.jogamp.newt.event.GestureHandler.GestureEvent; -import com.jogamp.newt.opengl.GLWindow; -import com.jogamp.opengl.math.FloatUtil; -import com.jogamp.opengl.math.Ray; -import com.jogamp.opengl.math.geom.AABBox; -import com.jogamp.opengl.util.GLPixelStorageModes; -import com.jogamp.opengl.util.GLReadBufferUtil; -import com.jogamp.opengl.util.PMVMatrix; - -/** - * GraphUI Scene - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * GraphUI is intended to become an immediate- and retained-mode API. - * </p> - * <p> - * To utilize a Scene instance directly as a {@link GLEventListener}, - * user needs to {@link #setClearParams(float[], int)}. - * - * Otherwise user may just call provided {@link GLEventListener} from within their own workflow - * - {@link GLEventListener#init(GLAutoDrawable)} - * - {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int)} - * - {@link GLEventListener#display(GLAutoDrawable)} - * - {@link GLEventListener#dispose(GLAutoDrawable)} - * </p> - * <p> - * {@link #setPMVMatrixSetup(PMVMatrixSetup)} maybe used to provide a custom {@link PMVMatrix} setup. - * </p> - * @see Shape - */ -public final class Scene implements GLEventListener { - /** Default scene distance on z-axis to projection is -1/5f. */ - public static final float DEFAULT_SCENE_DIST = -1/5f; - /** Default projection angle in degrees value is 45.0. */ - public static final float DEFAULT_ANGLE = 45.0f; - /** Default projection z-near value is 0.1. */ - public static final float DEFAULT_ZNEAR = 0.1f; - /** Default projection z-far value is 7000. */ - public static final float DEFAULT_ZFAR = 7000.0f; - - @SuppressWarnings("unused") - private static final boolean DEBUG = false; - - private final ArrayList<Shape> shapes = new ArrayList<Shape>(); - private float dbgbox_thickness = 0f; - private boolean doFrustumCulling = false; - - private float[] clearColor = null; - private int clearMask; - - private final RegionRenderer renderer; - - private final int[] sampleCount = new int[1]; - - /** Describing the bounding box in shape's object model-coordinates of the near-plane parallel at its scene-distance, post {@link #translate(PMVMatrix)} */ - private final AABBox planeBox = new AABBox(0f, 0f, 0f, 0f, 0f, 0f); - - private volatile Shape activeShape = null; - - private SBCMouseListener sbcMouseListener = null; - private SBCGestureListener sbcGestureListener = null; - private PinchToZoomGesture pinchToZoomGesture = null; - - final GLReadBufferUtil screenshot; - - private GLAutoDrawable cDrawable = null; - - private static RegionRenderer createRenderer() { - return RegionRenderer.create(RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); - } - - /** - * Create a new scene with an internally created RegionRenderer - * and using default values {@link #DEFAULT_SCENE_DIST}, {@link #DEFAULT_ANGLE}, {@link #DEFAULT_ZNEAR} and {@link #DEFAULT_ZFAR}. - */ - public Scene() { - this(createRenderer()); - } - - /** - * Create a new scene taking ownership of the given RegionRenderer - * and using default values {@link #DEFAULT_SCENE_DIST}, {@link #DEFAULT_ANGLE}, {@link #DEFAULT_ZNEAR} and {@link #DEFAULT_ZFAR}. - */ - public Scene(final RegionRenderer renderer) { - if( null == renderer ) { - throw new IllegalArgumentException("Null RegionRenderer"); - } - this.renderer = renderer; - this.sampleCount[0] = 4; - this.screenshot = new GLReadBufferUtil(false, false); - } - - /** Returns the associated RegionRenderer */ - public RegionRenderer getRenderer() { return renderer; } - - /** Returns the associated RegionRenderer's RenderState. */ - public RenderState getRenderState() { return renderer.getRenderState(); } - - /** - * Sets the clear parameter for {@link GL#glClearColor(float, float, float, float) glClearColor(..)} and {@link GL#glClear(int) glClear(..)} - * to be issued at {@link #display(GLAutoDrawable)}. - * - * Without setting these parameter, user has to issue - * {@link GL#glClearColor(float, float, float, float) glClearColor(..)} and {@link GL#glClear(int) glClear(..)} - * before calling {@link #display(GLAutoDrawable)}. - * - * @param clearColor {@link GL#glClearColor(float, float, float, float) glClearColor(..)} arguments - * @param clearMask {@link GL#glClear(int) glClear(..)} mask, default is {@link GL#GL_COLOR_BUFFER_BIT} | {@link GL#GL_DEPTH_BUFFER_BIT} - */ - public final void setClearParams(final float[] clearColor, final int clearMask) { this.clearColor = clearColor; this.clearMask = clearMask; } - - /** Returns the {@link GL#glClearColor(float, float, float, float) glClearColor(..)} arguments, see {@link #setClearParams(float[], int)}. */ - public final float[] getClearColor() { return clearColor; } - - /** Returns the {@link GL#glClear(int) glClear(..)} mask, see {@link #setClearParams(float[], int)}. */ - public final int getClearMask() { return clearMask; } - - /** Enable or disable {@link PMVMatrix#glGetFrustum()} culling per {@link Shape}. Default is disabled. */ - public final void setFrustumCullingEnabled(final boolean v) { doFrustumCulling = v; } - - /** Return whether {@link #setFrustumCullingEnabled(boolean) frustum culling} is enabled. */ - public final boolean isFrustumCullingEnabled() { return doFrustumCulling; } - - public void attachInputListenerTo(final GLWindow window) { - if(null == sbcMouseListener) { - sbcMouseListener = new SBCMouseListener(); - window.addMouseListener(sbcMouseListener); - sbcGestureListener = new SBCGestureListener(); - window.addGestureListener(sbcGestureListener); - pinchToZoomGesture = new PinchToZoomGesture(window.getNativeSurface(), false); - window.addGestureHandler(pinchToZoomGesture); - } - } - - public void detachInputListenerFrom(final GLWindow window) { - if(null != sbcMouseListener) { - window.removeMouseListener(sbcMouseListener); - sbcMouseListener = null; - window.removeGestureListener(sbcGestureListener); - sbcGestureListener = null; - window.removeGestureHandler(pinchToZoomGesture); - pinchToZoomGesture = null; - } - } - - public ArrayList<Shape> getShapes() { - return shapes; - } - public void addShape(final Shape s) { - s.setDebugBox(dbgbox_thickness); - shapes.add(s); - } - /** Removes given shape, keeps it alive. */ - public void removeShape(final Shape s) { - s.setDebugBox(0f); - shapes.remove(s); - } - /** Removes all given shapes and destroys them. */ - public void removeShape(final GL2ES2 gl, final Shape s) { - s.setDebugBox(0f); - shapes.remove(s); - s.destroy(gl, renderer); - } - public void addShapes(final Collection<? extends Shape> shapes) { - for(final Shape s : shapes) { - addShape(s); - } - } - /** Removes all given shapes, keeps them alive. */ - public void removeShapes(final Collection<? extends Shape> shapes) { - for(final Shape s : shapes) { - removeShape(s); - } - } - /** Removes all given shapes and destroys them. */ - public void removeShapes(final GL2ES2 gl, final Collection<? extends Shape> shapes) { - for(final Shape s : shapes) { - removeShape(gl, s); - } - } - public Shape getShapeByIdx(final int id) { - if( 0 > id ) { - return null; - } - return shapes.get(id); - } - public Shape getShapeByName(final int name) { - for(final Shape b : shapes) { - if(b.getName() == name ) { - return b; - } - } - return null; - } - - public int getSampleCount() { return sampleCount[0]; } - public int setSampleCount(final int v) { - sampleCount[0] = Math.min(8, Math.max(v, 0)); // clip - markAllShapesDirty(); - return sampleCount[0]; - } - - public void setAllShapesQuality(final int q) { - for(int i=0; i<shapes.size(); i++) { - final Shape shape = shapes.get(i); - if( shape instanceof GraphShape ) { - ((GraphShape)shape).setQuality(q); - } - } - } - public void setAllShapesSharpness(final float sharpness) { - for(int i=0; i<shapes.size(); i++) { - final Shape shape = shapes.get(i); - if( shape instanceof GraphShape ) { - ((GraphShape)shape).setSharpness(sharpness); - } - } - } - public void markAllShapesDirty() { - for(int i=0; i<shapes.size(); i++) { - shapes.get(i).markShapeDirty(); - } - } - - /** - * Sets the {@link #getBounds()} fractional thickness of the debug box ranging [0..1] for all shapes, zero for no debug box (default). - * @param v fractional thickness of {@link #getBounds()} ranging [0..1], zero for no debug box - */ - public final void setDebugBox(final float v) { - dbgbox_thickness = v; - for(int i=0; i<shapes.size(); i++) { - shapes.get(i).setDebugBox(v); - } - } - - @Override - public void init(final GLAutoDrawable drawable) { - cDrawable = drawable; - renderer.init(drawable.getGL().getGL2ES2()); - } - - /** - * Reshape scene using {@link #setupMatrix(PMVMatrix, int, int, int, int)} using {@link PMVMatrixSetup}. - * <p> - * {@inheritDoc} - * </p> - * @see PMVMatrixSetup - * @see #setPMVMatrixSetup(PMVMatrixSetup) - * @see #setupMatrix(PMVMatrix, int, int, int, int) - * @see #getBounds() - * @see #getBoundsCenter() - */ - @Override - public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { - renderer.reshapeNotify(x, y, width, height); - - setupMatrix(renderer.getMatrix(), x, y, width, height); - pmvMatrixSetup.setPlaneBox(planeBox, renderer.getMatrix(), x, y, width, height); - } - - private static Comparator<Shape> shapeZAscComparator = new Comparator<Shape>() { - @Override - public int compare(final Shape s1, final Shape s2) { - final float s1Z = s1.getBounds().getMinZ()+s1.getPosition()[2]; - final float s2Z = s2.getBounds().getMinZ()+s2.getPosition()[2]; - if( FloatUtil.isEqual(s1Z, s2Z, FloatUtil.EPSILON) ) { - return 0; - } else if( s1Z < s2Z ){ - return -1; - } else { - return 1; - } - } }; - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public void display(final GLAutoDrawable drawable) { - final Object[] shapesS = shapes.toArray(); - Arrays.sort(shapesS, (Comparator)shapeZAscComparator); - - display(drawable, shapesS, false); - } - - private static final int[] sampleCountGLSelect = { -1 }; - - private void display(final GLAutoDrawable drawable, final Object[] shapes, final boolean glSelect) { - final GL2ES2 gl = drawable.getGL().getGL2ES2(); - - final int[] sampleCount0; - if( glSelect ) { - gl.glClearColor(0f, 0f, 0f, 1f); - sampleCount0 = sampleCountGLSelect; - gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - } else { - if( null != clearColor ) { - gl.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); - gl.glClear(clearMask); - } - sampleCount0 = sampleCount; - } - - final PMVMatrix pmv = renderer.getMatrix(); - pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - - if( glSelect ) { - renderer.enable(gl, true, RegionRenderer.defaultBlendDisable, RegionRenderer.defaultBlendDisable); - } else { - renderer.enable(gl, true); - } - - //final int shapeCount = shapes.size(); - final int shapeCount = shapes.length; - for(int i=0; i<shapeCount; i++) { - // final UIShape uiShape = shapes.get(i); - final Shape shape = (Shape)shapes[i]; - // System.err.println("Id "+i+": "+uiShape); - if( shape.isEnabled() ) { - pmv.glPushMatrix(); - shape.setTransform(pmv); - - if( !doFrustumCulling || !pmv.glGetFrustum().isAABBoxOutside( shape.getBounds() ) ) { - if( glSelect ) { - final float color = ( i + 1f ) / ( shapeCount + 2f ); - // FIXME - // System.err.printf("drawGL: color %f, index %d of [0..%d[%n", color, i, shapeCount); - renderer.getRenderState().setColorStatic(color, color, color, 1f); - shape.drawToSelect(gl, renderer, sampleCount0); - } else { - shape.draw(gl, renderer, sampleCount0); - } - } - pmv.glPopMatrix(); - } - } - if( glSelect ) { - renderer.enable(gl, false, RegionRenderer.defaultBlendDisable, RegionRenderer.defaultBlendDisable); - } else { - renderer.enable(gl, false); - } - synchronized ( syncDisplayedOnce ) { - displayedOnce = true; - syncDisplayedOnce.notifyAll(); - } - } - - private volatile boolean displayedOnce = false; - private final Object syncDisplayedOnce = new Object(); - - /** Blocks until first {@link #display(GLAutoDrawable)} has completed after construction or {@link #dispose(GLAutoDrawable). */ - public void waitUntilDisplayed() { - synchronized( syncDisplayedOnce ) { - while( !displayedOnce ) { - try { - syncDisplayedOnce.wait(); - } catch (final InterruptedException e) { } - } - } - } - - /** - * Disposes all {@link #addShape(Shape) added} {@link Shape}s. - * <p> - * Implementation also issues {@link RegionRenderer#destroy(GL2ES2)} if set - * and {@link #detachInputListenerFrom(GLWindow)} in case the drawable is of type {@link GLWindow}. - * </p> - * <p> - * {@inheritDoc} - * </p> - */ - @Override - public void dispose(final GLAutoDrawable drawable) { - synchronized ( syncDisplayedOnce ) { - displayedOnce = false; - syncDisplayedOnce.notifyAll(); - } - if( drawable instanceof GLWindow ) { - final GLWindow glw = (GLWindow) drawable; - detachInputListenerFrom(glw); - } - final GL2ES2 gl = drawable.getGL().getGL2ES2(); - for(int i=0; i<shapes.size(); i++) { - shapes.get(i).destroy(gl, renderer); - } - shapes.clear(); - cDrawable = null; - renderer.destroy(gl); - screenshot.dispose(gl); - } - - /** - * Attempt to pick a {@link Shape} using the window coordinates and contained {@ling Shape}'s {@link AABBox} {@link Shape#getBounds() bounds} - * using a ray-intersection algorithm. - * <p> - * If {@link Shape} was found the given action is performed. - * </p> - * <p> - * Method performs on current thread and returns after probing every {@link Shape}. - * </p> - * @param glWinX window X coordinate, bottom-left origin - * @param glWinY window Y coordinate, bottom-left origin - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link Shape#setTransform(PMVMatrix) shape-transformed} and can be reused by the caller and runnable. - * @param objPos storage for found object position in model-space of found {@link Shape} - * @param shape storage for found {@link Shape} or null - * @param runnable the action to perform if {@link Shape} was found - */ - public Shape pickShape(final int glWinX, final int glWinY, final PMVMatrix pmv, final float[] objPos, final Shape[] shape, final Runnable runnable) { - shape[0] = pickShapeImpl(glWinX, glWinY, pmv, objPos); - if( null != shape[0] ) { - runnable.run(); - } - return shape[0]; - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - private Shape pickShapeImpl(final int glWinX, final int glWinY, final PMVMatrix pmv, final float[] objPos) { - final float winZ0 = 0f; - final float winZ1 = 0.3f; - /** - final FloatBuffer winZRB = Buffers.newDirectFloatBuffer(1); - gl.glReadPixels( x, y, 1, 1, GL2ES2.GL_DEPTH_COMPONENT, GL.GL_FLOAT, winZRB); - winZ1 = winZRB.get(0); // dir - */ - setupMatrix(pmv); - - final Ray ray = new Ray(); - - final Object[] shapesS = shapes.toArray(); - Arrays.sort(shapesS, (Comparator)shapeZAscComparator); - - for(int i=shapesS.length-1; i>=0; i--) { - final Shape uiShape = (Shape)shapesS[i]; - - if( uiShape.isEnabled() ) { - pmv.glPushMatrix(); - uiShape.setTransform(pmv); - final boolean ok = pmv.gluUnProjectRay(glWinX, glWinY, winZ0, winZ1, getViewport(), 0, ray); - if( ok ) { - final AABBox sbox = uiShape.getBounds(); - if( sbox.intersectsRay(ray) ) { - // System.err.printf("Pick.0: shape %d, [%d, %d, %f/%f] -> %s%n", i, glWinX, glWinY, winZ0, winZ1, ray); - if( null == sbox.getRayIntersection(objPos, ray, FloatUtil.EPSILON, true, dpyTmp1V3, dpyTmp2V3, dpyTmp3V3) ) { - throw new InternalError("Ray "+ray+", box "+sbox); - } - // System.err.printf("Pick.1: shape %d @ [%f, %f, %f], within %s%n", i, objPos[0], objPos[1], objPos[2], uiShape.getBounds()); - return uiShape; - } - } - pmv.glPopMatrix(); // we leave the stack open if picked above, allowing the modelview shape transform to be reused - } - } - return null; - } - private final float[] dpyTmp1V3 = new float[3]; - private final float[] dpyTmp2V3 = new float[3]; - private final float[] dpyTmp3V3 = new float[3]; - - /** - * Attempt to pick a {@link Shape} using the OpenGL false color rendering. - * <p> - * If {@link Shape} was found the given action is performed on the rendering thread. - * </p> - * <p> - * Method is non blocking and performs on rendering-thread, it returns immediately. - * </p> - * @param glWinX window X coordinate, bottom-left origin - * @param glWinY window Y coordinate, bottom-left origin - * @param objPos storage for found object position in model-space of found {@link Shape} - * @param shape storage for found {@link Shape} or null - * @param runnable the action to perform if {@link Shape} was found - */ - public void pickShapeGL(final int glWinX, final int glWinY, final float[] objPos, final Shape[] shape, final Runnable runnable) { - if( null == cDrawable ) { - return; - } - cDrawable.invoke(false, new GLRunnable() { - @Override - public boolean run(final GLAutoDrawable drawable) { - final Shape s = pickShapeGLImpl(drawable, glWinX, glWinY); - shape[0] = s; - if( null != s ) { - final PMVMatrix pmv = renderer.getMatrix(); - pmv.glPushMatrix(); - s.setTransform(pmv); - final boolean ok = null != shape[0].winToShapeCoord(getMatrix(), getViewport(), glWinX, glWinY, objPos); - pmv.glPopMatrix(); - if( ok ) { - runnable.run(); - } - } - return false; // needs to re-render to wash away our false-color glSelect - } } ); - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - private Shape pickShapeGLImpl(final GLAutoDrawable drawable, final int glWinX, final int glWinY) { - final Object[] shapesS = shapes.toArray(); - Arrays.sort(shapesS, (Comparator)shapeZAscComparator); - - final GLPixelStorageModes psm = new GLPixelStorageModes(); - final ByteBuffer pixel = Buffers.newDirectByteBuffer(4); - - final GL2ES2 gl = drawable.getGL().getGL2ES2(); - - display(drawable, shapesS, true); - - psm.setPackAlignment(gl, 4); - // psm.setUnpackAlignment(gl, 4); - try { - // gl.glReadPixels(glWinX, getHeight() - glWinY, 1, 1, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixel); - gl.glReadPixels(glWinX, glWinY, 1, 1, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixel); - } catch(final GLException gle) { - gle.printStackTrace(); - return null; - } - psm.restore(gl); - - // final float color = ( i + 1f ) / ( shapeCount + 2f ); - final int shapeCount = shapes.size(); - final int qp = pixel.get(0) & 0xFF; - final float color = qp / 255.0f; - final int index = Math.round( ( color * ( shapeCount + 2f) ) - 1f ); - - // FIXME drawGL: color 0.333333, index 0 of [0..1[ - System.err.printf("pickGL: glWin %d / %d, byte %d, color %f, index %d of [0..%d[%n", - glWinX, glWinY, qp, color, index, shapeCount); - - if( 0 <= index && index < shapeCount ) { - return (Shape)shapesS[index]; - } else { - return null; - } - } - - /** - * Calling {@link Shape#winToObjCoord(Scene, int, int, float[])}, retrieving its Shape object position. - * @param shape - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link Shape#setTransform(PMVMatrix) shape-transformed} and can be reused by the caller and runnable. - * @param objPos resulting object position - * @param runnable action - */ - public void winToShapeCoord(final Shape shape, final int glWinX, final int glWinY, final PMVMatrix pmv, final float[] objPos, final Runnable runnable) { - if( null != shape && null != shape.winToShapeCoord(pmvMatrixSetup, renderer.getViewport(), glWinX, glWinY, pmv, objPos) ) { - runnable.run(); - } - } - - /** - * Interface providing {@link #set(PMVMatrix, int, int, int, int) a method} to - * setup {@link PMVMatrix}'s {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW}. - * <p> - * At the end of operations, the {@link GLMatrixFunc#GL_MODELVIEW} matrix has to be selected. - * </p> - * <p> - * Implementation is being called by {@link Scene#setupMatrix(PMVMatrix, int, int, int, int)} - * and hence {@link Scene#reshape(GLAutoDrawable, int, int, int, int)}. - * </p> - * <p> - * Custom implementations can be set via {@link Scene#setPMVMatrixSetup(PMVMatrixSetup)}. - * </p> - * <p> - * The default implementation is described below: - * <ul> - * <li>{@link GLMatrixFunc#GL_PROJECTION} Matrix - * <ul> - * <li>Identity</li> - * <li>Perspective {@link Scene#DEFAULT_ANGLE} with {@link Scene#DEFAULT_ZNEAR} and {@link Scene#DEFAULT_ZFAR}</li> - * <li>Translated to given {@link Scene#DEFAULT_SCENE_DIST}</li> - * <li>Scale (back) to have normalized {@link Scene#getBounds() plane dimensions}, 1 for the greater of width and height.</li> - * </ul></li> - * <li>{@link GLMatrixFunc#GL_MODELVIEW} Matrix - * <ul> - * <li>identity</li> - * </ul></li> - * </ul> - * </p> - */ - public static interface PMVMatrixSetup { - /** - * Setup {@link PMVMatrix}'s {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW}. - * <p> - * See {@link PMVMatrixSetup} for details. - * </p> - * <p> - * At the end of operations, the {@link GLMatrixFunc#GL_MODELVIEW} matrix is selected. - * </p> - * @param pmv the {@link PMVMatrix} to setup - * @param x lower left corner of the viewport rectangle - * @param y lower left corner of the viewport rectangle - * @param width width of the viewport rectangle - * @param height height of the viewport rectangle - */ - void set(PMVMatrix pmv, final int x, final int y, final int width, final int height); - - /** - * Optional method to set the {@link Scene#getBounds()} {@link AABBox}, maybe a {@code nop} if not desired. - * <p> - * Will be called by {@link Scene#reshape(GLAutoDrawable, int, int, int, int)} after {@link #set(PMVMatrix, int, int, int, int)}. - * </p> - * @param planeBox the {@link AABBox} to define - * @param pmv the {@link PMVMatrix}, already setup via {@link #set(PMVMatrix, int, int, int, int)}. - * @param x lower left corner of the viewport rectangle - * @param y lower left corner of the viewport rectangle - * @param width width of the viewport rectangle - * @param height height of the viewport rectangle - */ - void setPlaneBox(final AABBox planeBox, final PMVMatrix pmv, int x, int y, final int width, final int height); - } - - /** Return the default or {@link #setPMVMatrixSetup(PMVMatrixSetup)} {@link PMVMatrixSetup}. */ - public final PMVMatrixSetup getPMVMatrixSetup() { return pmvMatrixSetup; } - - /** Set a custom {@link PMVMatrixSetup}. */ - public final void setPMVMatrixSetup(final PMVMatrixSetup setup) { pmvMatrixSetup = setup; } - - /** Return the default {@link PMVMatrixSetup}. */ - public static PMVMatrixSetup getDefaultPMVMatrixSetup() { return defaultPMVMatrixSetup; } - - /** - * Setup {@link PMVMatrix} {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} - * by calling {@link #getPMVMatrixSetup()}'s {@link PMVMatrixSetup#set(PMVMatrix, int, int, int, int)}. - * @param pmv the {@link PMVMatrix} to setup - * @param x lower left corner of the viewport rectangle - * @param y lower left corner of the viewport rectangle - * @param width width of the viewport rectangle - * @param height height of the viewport rectangle - */ - public void setupMatrix(final PMVMatrix pmv, final int x, final int y, final int width, final int height) { - pmvMatrixSetup.set(pmv, x, y, width, height); - } - - /** - * Setup {@link PMVMatrix} {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} - * using implicit {@link #getViewport()} surface dimension by calling {@link #getPMVMatrixSetup()}'s {@link PMVMatrixSetup#set(PMVMatrix, int, int, int, int)}. - * @param pmv the {@link PMVMatrix} to setup - */ - public void setupMatrix(final PMVMatrix pmv) { - final int[] viewport = renderer.getViewport(); - setupMatrix(pmv, viewport[0], viewport[1], viewport[2], viewport[3]); - } - - /** Copies the current int[4] viewport in given target and returns it for chaining. It is set after initial {@link #reshape(GLAutoDrawable, int, int, int, int)}. */ - public final int[/*4*/] getViewport(final int[/*4*/] target) { return renderer.getViewport(target); } - - /** Borrows the current int[4] viewport w/o copying. It is set after initial {@link #reshape(GLAutoDrawable, int, int, int, int)}. */ - public int[/*4*/] getViewport() { return renderer.getViewport(); } - - /** Returns the {@link #getViewport()}'s width, set after initial {@link #reshape(GLAutoDrawable, int, int, int, int)}. */ - public int getWidth() { return renderer.getWidth(); } - /** Returns the {@link #getViewport()}'s height, set after initial {@link #reshape(GLAutoDrawable, int, int, int, int)}. */ - public int getHeight() { return renderer.getHeight(); } - - /** Borrow the current {@link PMVMatrix}. */ - public PMVMatrix getMatrix() { return renderer.getMatrix(); } - - /** - * Describing the scene's object model-dimensions of the plane at scene-distance covering the visible viewport rectangle. - * <p> - * The value is evaluated at {@link #reshape(GLAutoDrawable, int, int, int, int)} via {@link } - * </p> - * <p> - * {@link AABBox#getWidth()} and {@link AABBox#getHeight()} define scene's dimension covered by surface size. - * </p> - * <p> - * {@link AABBox} is setup via {@link #getPMVMatrixSetup()}'s {@link PMVMatrixSetup#setPlaneBox(AABBox, PMVMatrix, int, int, int, int)}. - * </p> - * <p> - * The default {@link PMVMatrixSetup} implementation scales to normalized plane dimensions, 1 for the greater of width and height. - * </p> - */ - public AABBox getBounds() { return planeBox; } - - /** - * - * @param pmv - * @param viewport - * @param zNear - * @param zFar - * @param winX - * @param winY - * @param objOrthoZ - * @param objPos float[3] storage for object coord result - * @param winZ - */ - public static void winToPlaneCoord(final PMVMatrix pmv, final int[] viewport, - final float zNear, final float zFar, - final float winX, final float winY, final float objOrthoZ, - final float[] objPos) { - final float winZ = FloatUtil.getOrthoWinZ(objOrthoZ, zNear, zFar); - pmv.gluUnProject(winX, winY, winZ, viewport, 0, objPos, 0); - } - - /** - * Map given window surface-size to object coordinates relative to this scene using - * the give projection parameters. - * @param viewport viewport rectangle - * @param zNear custom {@link #DEFAULT_ZNEAR} - * @param zFar custom {@link #DEFAULT_ZFAR} - * @param objOrthoDist custom {@link #DEFAULT_SCENE_DIST} - * @param objSceneSize float[2] storage for object surface size result - */ - public void surfaceToPlaneSize(final int[] viewport, final float zNear, final float zFar, final float objOrthoDist, final float[/*2*/] objSceneSize) { - final PMVMatrix pmv = new PMVMatrix(); - setupMatrix(pmv, viewport[0], viewport[1], viewport[2], viewport[3]); - { - final float[] obj00Coord = new float[3]; - final float[] obj11Coord = new float[3]; - - winToPlaneCoord(pmv, viewport, DEFAULT_ZNEAR, DEFAULT_ZFAR, viewport[0], viewport[1], objOrthoDist, obj00Coord); - winToPlaneCoord(pmv, viewport, DEFAULT_ZNEAR, DEFAULT_ZFAR, viewport[2], viewport[3], objOrthoDist, obj11Coord); - objSceneSize[0] = obj11Coord[0] - obj00Coord[0]; - objSceneSize[1] = obj11Coord[1] - obj00Coord[1]; - } - } - - /** - * Map given window surface-size to object coordinates relative to this scene using - * the default {@link PMVMatrixSetup}, i.e. {@link #DEFAULT_ZNEAR}, {@link #DEFAULT_ZFAR} and {@link #DEFAULT_SCENE_DIST} - * @param viewport viewport rectangle - * @param objSceneSize float[2] storage for object surface size result - */ - public void surfaceToPlaneSize(final int[] viewport, final float[/*2*/] objSceneSize) { - surfaceToPlaneSize(viewport, DEFAULT_ZNEAR, DEFAULT_ZFAR, -DEFAULT_SCENE_DIST, objSceneSize); - } - - public final Shape getActiveShape() { - return activeShape; - } - - public void releaseActiveShape() { - activeShape = null; - } - private void setActiveShape(final Shape shape) { - activeShape = shape; - } - - private final class SBCGestureListener implements GestureHandler.GestureListener { - @Override - public void gestureDetected(final GestureEvent gh) { - if( null != activeShape ) { - // gesture .. delegate to active shape! - final InputEvent orig = gh.getTrigger(); - if( orig instanceof MouseEvent ) { - final MouseEvent e = (MouseEvent) orig; - // flip to GL window coordinates - final int glWinX = e.getX(); - final int glWinY = getHeight() - e.getY() - 1; - final PMVMatrix pmv = new PMVMatrix(); - final float[] objPos = new float[3]; - final Shape shape = activeShape; - winToShapeCoord(shape, glWinX, glWinY, pmv, objPos, () -> { - shape.dispatchGestureEvent(gh, glWinX, glWinY, pmv, renderer.getViewport(), objPos); - }); - } - } - } - } - - /** - * Dispatch mouse event, either directly sending to activeShape or picking one - * @param e original Newt {@link MouseEvent} - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - */ - final void dispatchMouseEvent(final MouseEvent e, final int glWinX, final int glWinY) { - if( null == activeShape ) { - dispatchMouseEventPickShape(e, glWinX, glWinY); - } else { - dispatchMouseEventForShape(activeShape, e, glWinX, glWinY); - } - } - /** - * Pick the shape using the event coordinates - * @param e original Newt {@link MouseEvent} - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - */ - final void dispatchMouseEventPickShape(final MouseEvent e, final int glWinX, final int glWinY) { - final PMVMatrix pmv = new PMVMatrix(); - final float[] objPos = new float[3]; - final Shape[] shape = { null }; - if( null == pickShape(glWinX, glWinY, pmv, objPos, shape, () -> { - setActiveShape(shape[0]); - shape[0].dispatchMouseEvent(e, glWinX, glWinY, objPos); - } ) ) - { - releaseActiveShape(); - } - } - /** - * Dispatch event to shape - * @param shape target active shape of event - * @param e original Newt {@link MouseEvent} - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - */ - final void dispatchMouseEventForShape(final Shape shape, final MouseEvent e, final int glWinX, final int glWinY) { - final PMVMatrix pmv = new PMVMatrix(); - final float[] objPos = new float[3]; - winToShapeCoord(shape, glWinX, glWinY, pmv, objPos, () -> { shape.dispatchMouseEvent(e, glWinX, glWinY, objPos); }); - } - - private class SBCMouseListener implements MouseListener { - int lx=-1, ly=-1, lId=-1; - - void clear() { - lx = -1; ly = -1; lId = -1; - } - - @Override - public void mousePressed(final MouseEvent e) { - if( -1 == lId || e.getPointerId(0) == lId ) { - lx = e.getX(); - ly = e.getY(); - lId = e.getPointerId(0); - } - // flip to GL window coordinates, origin bottom-left - final int glWinX = e.getX(); - final int glWinY = getHeight() - e.getY() - 1; - dispatchMouseEvent(e, glWinX, glWinY); - } - - @Override - public void mouseReleased(final MouseEvent e) { - // flip to GL window coordinates, origin bottom-left - final int glWinX = e.getX(); - final int glWinY = getHeight() - e.getY() - 1; - dispatchMouseEvent(e, glWinX, glWinY); - if( 1 == e.getPointerCount() ) { - // Release active shape: last pointer has been lifted! - releaseActiveShape(); - clear(); - } - } - - @Override - public void mouseClicked(final MouseEvent e) { - // flip to GL window coordinates - final int glWinX = e.getX(); - final int glWinY = getHeight() - e.getY() - 1; - // activeId should have been released by mouseRelease() already! - dispatchMouseEventPickShape(e, glWinX, glWinY); - // Release active shape: last pointer has been lifted! - releaseActiveShape(); - clear(); - } - - @Override - public void mouseDragged(final MouseEvent e) { - // drag activeShape, if no gesture-activity, only on 1st pointer - if( null != activeShape && !pinchToZoomGesture.isWithinGesture() && e.getPointerId(0) == lId ) { - lx = e.getX(); - ly = e.getY(); - - // dragged .. delegate to active shape! - // flip to GL window coordinates, origin bottom-left - final int glWinX = lx; - final int glWinY = getHeight() - ly - 1; - dispatchMouseEventForShape(activeShape, e, glWinX, glWinY); - } - } - - @Override - public void mouseWheelMoved(final MouseEvent e) { - // flip to GL window coordinates - final int glWinX = lx; - final int glWinY = getHeight() - ly - 1; - dispatchMouseEvent(e, glWinX, glWinY); - } - - @Override - public void mouseMoved(final MouseEvent e) { - if( -1 == lId || e.getPointerId(0) == lId ) { - lx = e.getX(); - ly = e.getY(); - lId = e.getPointerId(0); - } - final int glWinX = lx; - final int glWinY = getHeight() - ly - 1; - // dispatchMouseEvent(e, glWinX, glWinY); - dispatchMouseEventPickShape(e, glWinX, glWinY); - } - @Override - public void mouseEntered(final MouseEvent e) { } - @Override - public void mouseExited(final MouseEvent e) { - releaseActiveShape(); - clear(); - } - } - - /** - * Return a formatted status string containing avg fps and avg frame duration. - * @param glad GLAutoDrawable instance for FPSCounter, its chosen GLCapabilities and its GL's swap-interval - * @param renderModes render modes for {@link Region#getRenderModeString(int)} - * @param quality the Graph-Curve quality setting or -1 to be ignored - * @param dpi the monitor's DPI (vertical preferred) - * @return formatted status string - */ - public String getStatusText(final GLAutoDrawable glad, final int renderModes, final int quality, final float dpi) { - final FPSCounter fpsCounter = glad.getAnimator(); - final float lfps, tfps, td; - if( null != fpsCounter ) { - lfps = fpsCounter.getLastFPS(); - tfps = fpsCounter.getTotalFPS(); - td = (float)fpsCounter.getLastFPSPeriod() / (float)fpsCounter.getUpdateFPSFrames(); - } else { - lfps = 0f; - tfps = 0f; - td = 0f; - } - final String modeS = Region.getRenderModeString(renderModes); - final GLCapabilitiesImmutable caps = glad.getChosenGLCapabilities(); - final String sampleCountStr1, sampleCountStr2, qualityStr, blendStr; - if( Region.isVBAA(renderModes) || Region.isMSAA(renderModes) ) { - sampleCountStr1 = "-samples "+getSampleCount(); - } else { - sampleCountStr1 = ""; - } - if( caps.getNumSamples() > 0 ) { - sampleCountStr2 = ", smsaa "+caps.getNumSamples(); - } else { - sampleCountStr2 = ""; - } - if( 0 <= quality ) { - qualityStr = ", q "+quality; - } else { - qualityStr = ""; - } - if( getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED) ) { - blendStr = ", blend"; - } else { - blendStr = ""; - } - return String.format("%03.1f/%03.1f fps, %.1f ms/f, vsync %d, dpi %.1f, %s%s%s%s%s, a %d", - lfps, tfps, td, glad.getGL().getSwapInterval(), dpi, modeS, sampleCountStr1, sampleCountStr2, - qualityStr, blendStr, caps.getAlphaBits()); - } - - /** - * Return a formatted status string containing avg fps and avg frame duration. - * @param fpsCounter the counter, must not be null - * @return formatted status string - */ - public static String getStatusText(final FPSCounter fpsCounter) { - final float lfps = fpsCounter.getLastFPS(); - final float tfps = fpsCounter.getTotalFPS(); - final float td = (float)fpsCounter.getLastFPSPeriod() / (float)fpsCounter.getUpdateFPSFrames(); - return String.format("%03.1f/%03.1f fps, %.1f ms/f", lfps, tfps, td); - } - - /** - * Write current read drawable (screen) to a PNG file. - * @see #getScreenshotCount() - */ - public void screenshot(final GL gl, final int renderModes, final String prefix) { - final RegionRenderer renderer = getRenderer(); - final String modeS = Region.getRenderModeString(renderModes); - final String filename = String.format((Locale)null, "%s-shot%03d-%03dx%03d-S_%s_%02d.png", - prefix, shotCount++, renderer.getWidth(), renderer.getHeight(), - modeS, getSampleCount()); - gl.glFinish(); // just make sure rendering finished .. - if(screenshot.readPixels(gl, false)) { - screenshot.write(new File(filename)); - System.err.println("Wrote: "+filename); - } - } - private int shotCount = 0; - - /** Return the number of {@link #screenshot(GL, int, String)}s being taken. */ - public int getScreenshotCount() { return shotCount; } - - private static final PMVMatrixSetup defaultPMVMatrixSetup = new PMVMatrixSetup() { - @Override - public void set(final PMVMatrix pmv, final int x, final int y, final int width, final int height) { - final float ratio = (float)width/(float)height; - pmv.glMatrixMode(GLMatrixFunc.GL_PROJECTION); - pmv.glLoadIdentity(); - pmv.gluPerspective(DEFAULT_ANGLE, ratio, DEFAULT_ZNEAR, DEFAULT_ZFAR); - pmv.glTranslatef(0f, 0f, DEFAULT_SCENE_DIST); - - pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - pmv.glLoadIdentity(); - - // Scale (back) to have normalized plane dimensions, 1 for the greater of width and height. - final AABBox planeBox0 = new AABBox(); - setPlaneBox(planeBox0, pmv, x, y, width, height); - final float sx = planeBox0.getWidth(); - final float sy = planeBox0.getHeight(); - final float sxy = sx > sy ? sx : sy; - pmv.glMatrixMode(GLMatrixFunc.GL_PROJECTION); - pmv.glScalef(sxy, sxy, 1f); - pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - } - - @Override - public void setPlaneBox(final AABBox planeBox, final PMVMatrix pmv, final int x, final int y, final int width, final int height) { - final float orthoDist = -DEFAULT_SCENE_DIST; - final float[] obj00Coord = new float[3]; - final float[] obj11Coord = new float[3]; - final int[] viewport = { x, y, width, height }; - - winToPlaneCoord(pmv, viewport, DEFAULT_ZNEAR, DEFAULT_ZFAR, x, y, orthoDist, obj00Coord); - winToPlaneCoord(pmv, viewport, DEFAULT_ZNEAR, DEFAULT_ZFAR, width, height, orthoDist, obj11Coord); - - planeBox.setSize( obj00Coord[0], // lx - obj00Coord[1], // ly - obj00Coord[2], // lz - obj11Coord[0], // hx - obj11Coord[1], // hy - obj11Coord[2] );// hz } - } - }; - private PMVMatrixSetup pmvMatrixSetup = defaultPMVMatrixSetup; -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java deleted file mode 100644 index 7d6f139ba..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java +++ /dev/null @@ -1,1191 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl; - -import java.util.ArrayList; - -import com.jogamp.nativewindow.NativeWindowException; -import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.fixedfunc.GLMatrixFunc; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.newt.event.GestureHandler.GestureEvent; -import com.jogamp.newt.event.GestureHandler.GestureListener; -import com.jogamp.newt.event.MouseAdapter; -import com.jogamp.newt.event.NEWTEvent; -import com.jogamp.newt.event.PinchToZoomGesture; -import com.jogamp.newt.event.MouseEvent; -import com.jogamp.newt.event.MouseListener; -import com.jogamp.opengl.math.FloatUtil; -import com.jogamp.opengl.math.Quaternion; -import com.jogamp.opengl.math.VectorUtil; -import com.jogamp.opengl.math.geom.AABBox; -import com.jogamp.opengl.util.PMVMatrix; - -/** - * Generic UI Shape, potentially using a Graph via {@link GraphShape} or other means of representing content. - * <p> - * A shape includes the following build-in user-interactions - * - drag shape w/ 1-pointer click, see {@link #setDraggable(boolean)} - * - resize shape w/ 1-pointer click and drag in 1/4th bottom-left and bottom-right corner, see {@link #setResizable(boolean)}. - * </p> - * <p> - * A shape is expected to have its 0/0 origin in its bottom-left corner, otherwise the drag-zoom sticky-edge will not work as expected. - * </p> - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * GraphUI is intended to become an immediate- and retained-mode API. - * </p> - * @see Scene - */ -public abstract class Shape { - public static interface Listener { - void run(final Shape shape); - } - protected static final boolean DEBUG_DRAW = false; - private static final boolean DEBUG = false; - - private static final int DIRTY_SHAPE = 1 << 0 ; - private static final int DIRTY_STATE = 1 << 1 ; - - protected final AABBox box; - - private final float[] position = new float[] { 0f, 0f, 0f }; - private final Quaternion rotation = new Quaternion(); - private final float[] rotPivot = new float[] { 0f, 0f, 0f }; - private final float[] scale = new float[] { 1f, 1f, 1f }; - - private volatile int dirty = DIRTY_SHAPE | DIRTY_STATE; - private final Object dirtySync = new Object(); - - /** Default base-color w/o color channel, will be modulated w/ pressed- and toggle color */ - protected final float[] rgbaColor = {0.75f, 0.75f, 0.75f, 1.0f}; - /** Default pressed color-factor w/o color channel, modulated base-color. 0.75 * 1.2 = 0.9 */ - protected final float[] pressedRGBAModulate = {1.2f, 1.2f, 1.2f, 0.7f}; - /** Default toggle color-factor w/o color channel, modulated base-color. 0.75 * 1.13 ~ 0.85 */ - protected final float[] toggleOnRGBAModulate = {1.13f, 1.13f, 1.13f, 1.0f}; - /** Default toggle color-factor w/o color channel, modulated base-color. 0.75 * 0.86 ~ 0.65 */ - protected final float[] toggleOffRGBAModulate = {0.86f, 0.86f, 0.86f, 1.0f}; - - private int name = -1; - - private boolean down = false; - private boolean toggle = false; - private boolean toggleable = false; - private boolean draggable = true; - private boolean resizable = true; - private boolean enabled = true; - private float dbgbox_thickness = 0f; // fractional thickness of bounds, 0f for no debug box - private ArrayList<MouseGestureListener> mouseListeners = new ArrayList<MouseGestureListener>(); - - private Listener onMoveListener = null; - - public Shape() { - this.box = new AABBox(); - } - - /** Set a symbolic name for this shape for identification. Default is -1 for noname. */ - public final void setName(final int name) { this.name = name; } - /** Return the optional symbolic name for this shape. */ - public final int getName() { return this.name; } - - /** Returns true if this shape is enabled and hence visible, otherwise false. */ - public final boolean isEnabled() { return enabled; } - /** Enable or disable this shape, i.e. its visibility. */ - public final void setEnabled(final boolean v) { enabled = v; } - - /** - * Sets the {@link #getBounds()} fractional thickness of the debug box ranging [0..1], zero for no debug box (default). - * @param v fractional thickness of {@link #getBounds()} ranging [0..1], zero for no debug box - */ - public final void setDebugBox(final float v) { - dbgbox_thickness = Math.min(1f, Math.max(0f, v)); - } - /** Returns true if a debug box has been enabled via {@link #setDebugBox(float)}. */ - public final boolean hasDebugBox() { return !FloatUtil.isZero(dbgbox_thickness); } - /** Returns the fractional thickness of the debug box ranging [0..1], see {@link #setDebugBox(float)}. */ - public final float getDebugBox() { return dbgbox_thickness; } - - /** - * Clears all data and reset all states as if this instance was newly created - * @param gl TODO - * @param renderer TODO - */ - public final void clear(final GL2ES2 gl, final RegionRenderer renderer) { - synchronized ( dirtySync ) { - clearImpl0(gl, renderer); - position[0] = 0f; - position[1] = 0f; - position[2] = 0f; - rotation.setIdentity(); - rotPivot[0] = 0f; - rotPivot[1] = 0f; - rotPivot[2] = 0f; - scale[0] = 1f; - scale[1] = 1f; - scale[2] = 1f; - box.reset(); - markShapeDirty(); - } - } - - /** - * Destroys all data - * @param gl - * @param renderer - */ - public final void destroy(final GL2ES2 gl, final RegionRenderer renderer) { - destroyImpl0(gl, renderer); - position[0] = 0f; - position[1] = 0f; - position[2] = 0f; - rotation.setIdentity(); - rotPivot[0] = 0f; - rotPivot[1] = 0f; - rotPivot[2] = 0f; - scale[0] = 1f; - scale[1] = 1f; - scale[2] = 1f; - box.reset(); - markShapeDirty(); - } - - public final void onMove(final Listener l) { onMoveListener = l; } - - /** Move to scaled position. Position ends up in PMVMatrix unmodified. */ - public final void moveTo(final float tx, final float ty, final float tz) { - position[0] = tx; - position[1] = ty; - position[2] = tz; - if( null != onMoveListener ) { - onMoveListener.run(this); - } - // System.err.println("Shape.setTranslate: "+tx+"/"+ty+"/"+tz+": "+toString()); - } - - /** Move about scaled distance. Position ends up in PMVMatrix unmodified. */ - public final void move(final float dtx, final float dty, final float dtz) { - position[0] += dtx; - position[1] += dty; - position[2] += dtz; - if( null != onMoveListener ) { - onMoveListener.run(this); - } - // System.err.println("Shape.translate: "+tx+"/"+ty+"/"+tz+": "+toString()); - } - - /** Returns float[3] position, i.e. scaled translation as set via {@link #moveTo(float, float, float) or {@link #move(float, float, float)}}. */ - public final float[] getPosition() { return position; } - - /** Returns {@link Quaternion} for rotation. */ - public final Quaternion getRotation() { return rotation; } - /** Return float[3] unscaled rotation origin, aka pivot. */ - public final float[] getRotationPivot() { return rotPivot; } - /** Set unscaled rotation origin, aka pivot. Usually the {@link #getBounds()} center and should be set while {@link #validateImpl(GLProfile, GL2ES2)}. */ - public final void setRotationPivot(final float rx, final float ry, final float rz) { - rotPivot[0] = rx; - rotPivot[1] = ry; - rotPivot[2] = rz; - } - /** - * Set unscaled rotation origin, aka pivot. Usually the {@link #getBounds()} center and should be set while {@link #validateImpl(GLProfile, GL2ES2)}. - * @param pivot float[3] rotation origin - */ - public final void setRotationPivot(final float[/*3*/] pivot) { - System.arraycopy(pivot, 0, rotPivot, 0, 3); - } - - /** - * Set scale factor to given scale. - * @see #scale(float, float, float) - * @see #getScale() - */ - public final void setScale(final float sx, final float sy, final float sz) { - scale[0] = sx; - scale[1] = sy; - scale[2] = sz; - } - /** - * Multiply current scale factor by given scale. - * @see #setScale(float, float, float) - * @see #getScale() - */ - public final void scale(final float sx, final float sy, final float sz) { - scale[0] *= sx; - scale[1] *= sy; - scale[2] *= sz; - } - /** - * Returns float[3] scale factors. - * @see #setScale(float, float, float) - * @see #scale(float, float, float) - */ - public final float[] getScale() { return scale; } - /** Returns X-axis scale factor. */ - public final float getScaleX() { return scale[0]; } - /** Returns Y-axis scale factor. */ - public final float getScaleY() { return scale[1]; } - /** Returns Z-axis scale factor. */ - public final float getScaleZ() { return scale[2]; } - - /** - * Marks the shape dirty, causing next {@link #draw(GL2ES2, RegionRenderer, int[]) draw()} - * to recreate the Graph shape and reset the region. - */ - public final void markShapeDirty() { - synchronized ( dirtySync ) { - dirty |= DIRTY_SHAPE; - } - } - - /** - * Marks the rendering state dirty, causing next {@link #draw(GL2ES2, RegionRenderer, int[]) draw()} - * to notify the Graph region to reselect shader and repaint potentially used FBOs. - */ - public final void markStateDirty() { - synchronized ( dirtySync ) { - dirty |= DIRTY_STATE; - } - } - - protected final boolean isShapeDirty() { - return 0 != ( dirty & DIRTY_SHAPE ) ; - } - protected final boolean isStateDirty() { - return 0 != ( dirty & DIRTY_STATE ) ; - } - - /** - * Returns the unscaled bounding {@link AABBox} for this shape, borrowing internal instance. - * - * The returned {@link AABBox} will only cover this unscaled shape - * after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} - * or {@link #validate(GL2ES2)}. - * - * @see #getBounds(GLProfile) - */ - public final AABBox getBounds() { return box; } - - /** - * Returns the scaled width of the bounding {@link AABBox} for this shape. - * - * The returned width will only cover the scaled shape - * after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} - * or {@link #validate(GL2ES2)}. - * - * @see #getBounds() - */ - public final float getScaledWidth() { - return box.getWidth() * getScaleX(); - } - - /** - * Returns the scaled height of the bounding {@link AABBox} for this shape. - * - * The returned height will only cover the scaled shape - * after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} - * or {@link #validate(GL2ES2)}. - * - * @see #getBounds() - */ - public final float getScaledHeight() { - return box.getHeight() * getScaleY(); - } - - /** - * Returns the unscaled bounding {@link AABBox} for this shape. - * - * This variant differs from {@link #getBounds()} as it - * returns a valid {@link AABBox} even before {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} - * and having an OpenGL instance available. - * - * @see #getBounds() - */ - public final AABBox getBounds(final GLProfile glp) { - validate(glp); - return box; - } - - /** Experimental selection draw command used by {@link Scene}. */ - public void drawToSelect(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { - synchronized ( dirtySync ) { - validate(gl); - drawImpl0(gl, renderer, sampleCount, null); - } - } - - private final float[] rgba_tmp = { 0, 0, 0, 1 }; - - /** - * Renders the shape. - * <p> - * {@link #setTransform(PMVMatrix)} is expected to be completed beforehand. - * </p> - * @param gl the current GL object - * @param renderer {@link RegionRenderer} which might be used for Graph Curve Rendering, also source of {@link RegionRenderer#getMatrix()} and {@link RegionRenderer#getViewport()}. - * @param sampleCount sample count if used by Graph renderModes - */ - public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { - final boolean isPressed = isPressed(), isToggleOn = isToggleOn(); - final float[] rgba; - if( hasColorChannel() ) { - if( isPressed ) { - rgba = pressedRGBAModulate; - } else if( isToggleable() ) { - if( isToggleOn ) { - rgba = toggleOnRGBAModulate; - } else { - rgba = toggleOffRGBAModulate; - } - } else { - rgba = rgbaColor; - } - } else { - rgba = rgba_tmp; - if( isPressed ) { - rgba[0] = rgbaColor[0]*pressedRGBAModulate[0]; - rgba[1] = rgbaColor[1]*pressedRGBAModulate[1]; - rgba[2] = rgbaColor[2]*pressedRGBAModulate[2]; - rgba[3] = rgbaColor[3]*pressedRGBAModulate[3]; - } else if( isToggleable() ) { - if( isToggleOn ) { - rgba[0] = rgbaColor[0]*toggleOnRGBAModulate[0]; - rgba[1] = rgbaColor[1]*toggleOnRGBAModulate[1]; - rgba[2] = rgbaColor[2]*toggleOnRGBAModulate[2]; - rgba[3] = rgbaColor[3]*toggleOnRGBAModulate[3]; - } else { - rgba[0] = rgbaColor[0]*toggleOffRGBAModulate[0]; - rgba[1] = rgbaColor[1]*toggleOffRGBAModulate[1]; - rgba[2] = rgbaColor[2]*toggleOffRGBAModulate[2]; - rgba[3] = rgbaColor[3]*toggleOffRGBAModulate[3]; - } - } else { - rgba[0] = rgbaColor[0]; - rgba[1] = rgbaColor[1]; - rgba[2] = rgbaColor[2]; - rgba[3] = rgbaColor[3]; - } - } - synchronized ( dirtySync ) { - validate(gl); - drawImpl0(gl, renderer, sampleCount, rgba); - } - } - - /** - * Validates the shape's underlying {@link GLRegion}. - * <p> - * If the region is dirty, it gets {@link GLRegion#clear(GL2ES2) cleared} and is reused. - * </p> - * @param gl current {@link GL2ES2} object - * @see #validate(GLProfile) - */ - public final void validate(final GL2ES2 gl) { - synchronized ( dirtySync ) { - if( isShapeDirty() ) { - box.reset(); - } - validateImpl(gl.getGLProfile(), gl); - dirty = 0; - } - } - - /** - * Validates the shape's underlying {@link GLRegion} w/o a current {@link GL2ES2} object - * <p> - * If the region is dirty a new region is created - * and the old one gets pushed to a dirty-list to get disposed when a GL context is available. - * </p> - * @see #validate(GL2ES2) - */ - public final void validate(final GLProfile glp) { - synchronized ( dirtySync ) { - if( isShapeDirty() ) { - box.reset(); - } - validateImpl(glp, null); - dirty = 0; - } - } - - /** - * Setup the pre-selected {@link GLMatrixFunc#GL_MODELVIEW} {@link PMVMatrix} for this object. - * - Scale shape from its center position - * - Rotate shape around optional scaled pivot, see {@link #setRotationPivot(float[])}), otherwise rotate around its scaled center (default) - * <p> - * Shape's origin should be bottom-left @ 0/0 to have build-in drag-zoom work properly. - * </p> - * @param pmv the matrix - * @see #setRotationPivot(float[]) - * @see #getRotation() - * @see #moveTo(float, float, float) - * @see #setScale(float, float, float) - */ - public void setTransform(final PMVMatrix pmv) { - final boolean hasScale = !VectorUtil.isVec3Equal(scale, 0, VectorUtil.VEC3_ONE, 0, FloatUtil.EPSILON); - final boolean hasRotate = !rotation.isIdentity(); - final boolean hasRotPivot = !VectorUtil.isVec3Zero(rotPivot, 0, FloatUtil.EPSILON); - final float[] ctr = box.getCenter(); - final boolean sameScaleRotatePivot = hasScale && hasRotate && ( !hasRotPivot || VectorUtil.isVec3Equal(rotPivot, 0, ctr, 0, FloatUtil.EPSILON) ); - - pmv.glTranslatef(position[0], position[1], position[2]); // translate, scaled - - if( sameScaleRotatePivot ) { - // Scale shape from its center position and rotate around its center - pmv.glTranslatef(ctr[0]*scale[0], ctr[1]*scale[1], ctr[2]*scale[2]); // add-back center, scaled - pmv.glRotate(rotation); - pmv.glScalef(scale[0], scale[1], scale[2]); - pmv.glTranslatef(-ctr[0], -ctr[1], -ctr[2]); // move to center - } else if( hasRotate || hasScale ) { - if( hasRotate ) { - if( hasRotPivot ) { - // Rotate shape around its scaled pivot - pmv.glTranslatef(rotPivot[0]*scale[0], rotPivot[1]*scale[1], rotPivot[2]*scale[2]); // pivot back from rot-pivot, scaled - pmv.glRotate(rotation); - pmv.glTranslatef(-rotPivot[0]*scale[0], -rotPivot[1]*scale[1], -rotPivot[2]*scale[2]); // pivot to rot-pivot, scaled - } else { - // Rotate shape around its scaled center - pmv.glTranslatef(ctr[0]*scale[0], ctr[1]*scale[1], ctr[2]*scale[2]); // pivot back from center-pivot, scaled - pmv.glRotate(rotation); - pmv.glTranslatef(-ctr[0]*scale[0], -ctr[1]*scale[1], -ctr[2]*scale[2]); // pivot to center-pivot, scaled - } - } - if( hasScale ) { - // Scale shape from its center position - pmv.glTranslatef(ctr[0]*scale[0], ctr[1]*scale[1], ctr[2]*scale[2]); // add-back center, scaled - pmv.glScalef(scale[0], scale[1], scale[2]); - pmv.glTranslatef(-ctr[0], -ctr[1], -ctr[2]); // move to center - } - } - // TODO: Add alignment features. - } - - /** - * Retrieve surface (view) size of this shape. - * <p> - * The given {@link PMVMatrix} has to be setup properly for this object, - * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param pmv well formed {@link PMVMatrix}, e.g. could have been setup via {@link Scene#setupMatrix(PMVMatrix) setupMatrix(..)} and {@link #setTransform(PMVMatrix)}. - * @param viewport the int[4] viewport - * @param surfaceSize int[2] target surface size - * @return given int[2] {@code surfaceSize} for successful gluProject(..) operation, otherwise {@code null} - * @see #getSurfaceSize(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], PMVMatrix, int[]) - * @see #getSurfaceSize(Scene, PMVMatrix, int[]) - */ - public int[/*2*/] getSurfaceSize(final PMVMatrix pmv, final int[/*4*/] viewport, final int[/*2*/] surfaceSize) { - // System.err.println("Shape::getSurfaceSize.VP "+viewport[0]+"/"+viewport[1]+" "+viewport[2]+"x"+viewport[3]); - final float[] winCoordHigh = new float[3]; - final float[] winCoordLow = new float[3]; - final float[] high = getBounds().getHigh(); - final float[] low = getBounds().getLow(); - - if( pmv.gluProject(high[0], high[1], high[2], viewport, 0, winCoordHigh, 0) ) { - // System.err.printf("Shape::surfaceSize.H: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", getName(), high[0], high[1], high[2], winCoordHigh[0], winCoordHigh[1], winCoordHigh[2]); - if( pmv.gluProject(low[0], low[1], low[2], viewport, 0, winCoordLow, 0) ) { - // System.err.printf("Shape::surfaceSize.L: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", getName(), low[0], low[1], low[2], winCoordLow[0], winCoordLow[1], winCoordLow[2]); - surfaceSize[0] = (int)(winCoordHigh[0] - winCoordLow[0]); - surfaceSize[1] = (int)(winCoordHigh[1] - winCoordLow[1]); - // System.err.printf("Shape::surfaceSize.S: shape %d: %f x %f -> %d x %d%n", getName(), winCoordHigh[0] - winCoordLow[0], winCoordHigh[1] - winCoordLow[1], surfaceSize[0], surfaceSize[1]); - return surfaceSize; - } - } - return null; - } - - /** - * Retrieve surface (view) size of this shape. - * <p> - * The given {@link PMVMatrix} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} properly for this shape - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param pmvMatrixSetup {@link Scene.PMVMatrixSetup} to {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} given {@link PMVMatrix} {@code pmv}. - * @param viewport used viewport for {@link PMVMatrix#gluProject(float, float, float, int[], int, float[], int)} - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link #setTransform(PMVMatrix) shape-transformed} and can be reused by the caller. - * @param surfaceSize int[2] target surface size - * @return given int[2] {@code surfaceSize} for successful gluProject(..) operation, otherwise {@code null} - * @see #getSurfaceSize(PMVMatrix, int[], int[]) - * @see #getSurfaceSize(Scene, PMVMatrix, int[]) - */ - public int[/*2*/] getSurfaceSize(final Scene.PMVMatrixSetup pmvMatrixSetup, final int[/*4*/] viewport, final PMVMatrix pmv, final int[/*2*/] surfaceSize) { - pmvMatrixSetup.set(pmv, viewport[0], viewport[1], viewport[2], viewport[3]); - setTransform(pmv); - return getSurfaceSize(pmv, viewport, surfaceSize); - } - - /** - * Retrieve surface (view) size of this shape. - * <p> - * The given {@link PMVMatrix} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} properly for this shape - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport. - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link #setTransform(PMVMatrix) shape-transformed} and can be reused by the caller. - * @param surfaceSize int[2] target surface size - * @return given int[2] {@code surfaceSize} for successful gluProject(..) operation, otherwise {@code null} - * @see #getSurfaceSize(PMVMatrix, int[], int[]) - * @see #getSurfaceSize(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], PMVMatrix, int[]) - */ - public int[/*2*/] getSurfaceSize(final Scene scene, final PMVMatrix pmv, final int[/*2*/] surfaceSize) { - return getSurfaceSize(scene.getPMVMatrixSetup(), scene.getViewport(), pmv, surfaceSize); - } - - /** - * Retrieve pixel per scaled shape-coordinate unit, i.e. [px]/[obj]. - * <p> - * The given {@link PMVMatrix} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} properly for this shape - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport. - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link #setTransform(PMVMatrix) shape-transformed} and can be reused by the caller. - * @param pixPerShape float[2] pixel per scaled shape-coordinate unit result storage - * @return given float[2] {@code pixPerShape} for successful gluProject(..) operation, otherwise {@code null} - * @see #getPixelPerShapeUnit(int[], float[]) - * @see #getSurfaceSize(Scene, PMVMatrix, int[]) - * @see #getScaledWidth() - * @see #getScaledHeight() - */ - public float[] getPixelPerShapeUnit(final Scene scene, final PMVMatrix pmv, final float[] pixPerShape) { - final int[] shapeSizePx = new int[2]; - if( null != getSurfaceSize(scene, new PMVMatrix(), shapeSizePx) ) { - return getPixelPerShapeUnit(shapeSizePx, pixPerShape); - } else { - return null; - } - } - - /** - * Retrieve pixel per scaled shape-coordinate unit, i.e. [px]/[obj]. - * @param shapeSizePx int[2] shape size in pixel as retrieved via e.g. {@link #getSurfaceSize(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], PMVMatrix, int[])} - * @param pixPerShape float[2] pixel scaled per shape-coordinate unit result storage - * @return given float[2] {@code pixPerShape} - * @see #getPixelPerShapeUnit(Scene, PMVMatrix, float[]) - * @see #getSurfaceSize(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], PMVMatrix, int[]) - * @see #getScaledWidth() - * @see #getScaledHeight() - */ - public float[] getPixelPerShapeUnit(final int[] shapeSizePx, final float[] pixPerShape) { - pixPerShape[0] = shapeSizePx[0] / getScaledWidth(); - pixPerShape[0] = shapeSizePx[1] / getScaledHeight(); - return pixPerShape; - } - - /** - * Map given object coordinate relative to this shape to window coordinates. - * <p> - * The given {@link PMVMatrix} has to be setup properly for this object, - * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param pmv well formed {@link PMVMatrix}, e.g. could have been setup via {@link Scene#setupMatrix(PMVMatrix) setupMatrix(..)} and {@link #setTransform(PMVMatrix)}. - * @param viewport the int[4] viewport - * @param objPos float[3] object position relative to this shape's center - * @param glWinPos int[2] target window position of objPos relative to this shape - * @return given int[2] {@code glWinPos} for successful gluProject(..) operation, otherwise {@code null} - * @see #shapeToWinCoord(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], float[], PMVMatrix, int[]) - * @see #shapeToWinCoord(Scene, float[], PMVMatrix, int[]) - */ - public int[/*2*/] shapeToWinCoord(final PMVMatrix pmv, final int[/*4*/] viewport, final float[/*3*/] objPos, final int[/*2*/] glWinPos) { - // System.err.println("Shape::objToWinCoordgetSurfaceSize.VP "+viewport[0]+"/"+viewport[1]+" "+viewport[2]+"x"+viewport[3]); - final float[] winCoord = new float[3]; - - if( pmv.gluProject(objPos[0], objPos[1], objPos[2], viewport, 0, winCoord, 0) ) { - // System.err.printf("Shape::objToWinCoord.0: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", getName(), objPos[0], objPos[1], objPos[2], winCoord[0], winCoord[1], winCoord[2]); - glWinPos[0] = (int)(winCoord[0]); - glWinPos[1] = (int)(winCoord[1]); - // System.err.printf("Shape::objToWinCoord.X: shape %d: %f / %f -> %d / %d%n", getName(), winCoord[0], winCoord[1], glWinPos[0], glWinPos[1]); - return glWinPos; - } - return null; - } - - /** - * Map given object coordinate relative to this shape to window coordinates. - * <p> - * The given {@link PMVMatrix} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} properly for this shape - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param pmvMatrixSetup {@link Scene.PMVMatrixSetup} to {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} given {@link PMVMatrix} {@code pmv}. - * @param viewport used viewport for {@link PMVMatrix#gluProject(float, float, float, int[], int, float[], int)} - * @param objPos float[3] object position relative to this shape's center - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link #setTransform(PMVMatrix) shape-transformed} and can be reused by the caller. - * @param glWinPos int[2] target window position of objPos relative to this shape - * @return given int[2] {@code glWinPos} for successful gluProject(..) operation, otherwise {@code null} - * @see #shapeToWinCoord(PMVMatrix, int[], float[], int[]) - * @see #shapeToWinCoord(Scene, float[], PMVMatrix, int[]) - */ - public int[/*2*/] shapeToWinCoord(final Scene.PMVMatrixSetup pmvMatrixSetup, final int[/*4*/] viewport, final float[/*3*/] objPos, final PMVMatrix pmv, final int[/*2*/] glWinPos) { - pmvMatrixSetup.set(pmv, viewport[0], viewport[1], viewport[2], viewport[3]); - setTransform(pmv); - return this.shapeToWinCoord(pmv, viewport, objPos, glWinPos); - } - - /** - * Map given object coordinate relative to this shape to window coordinates. - * <p> - * The given {@link PMVMatrix} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} properly for this shape - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport. - * @param objPos float[3] object position relative to this shape's center - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link #setTransform(PMVMatrix) shape-transformed} and can be reused by the caller. - * @param glWinPos int[2] target window position of objPos relative to this shape - * @return given int[2] {@code glWinPos} for successful gluProject(..) operation, otherwise {@code null} - * @see #shapeToWinCoord(PMVMatrix, int[], float[], int[]) - * @see #shapeToWinCoord(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], float[], PMVMatrix, int[]) - */ - public int[/*2*/] shapeToWinCoord(final Scene scene, final float[/*3*/] objPos, final PMVMatrix pmv, final int[/*2*/] glWinPos) { - return this.shapeToWinCoord(scene.getPMVMatrixSetup(), scene.getViewport(), objPos, pmv, glWinPos); - } - - /** - * Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate. - * <p> - * The given {@link PMVMatrix} has to be setup properly for this object, - * i.e. its {@link GLMatrixFunc#GL_PROJECTION} and {@link GLMatrixFunc#GL_MODELVIEW} for the surrounding scene - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param pmv well formed {@link PMVMatrix}, e.g. could have been setup via {@link Scene#setupMatrix(PMVMatrix) setupMatrix(..)} and {@link #setTransform(PMVMatrix)}. - * @param viewport the int[4] viewport - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - * @param objPos float[3] target object position of glWinX/glWinY relative to this shape - * @return given float[3] {@code objPos} for successful gluProject(..) and gluUnProject(..) operation, otherwise {@code null} - * @see #winToShapeCoord(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], int, int, PMVMatrix, float[]) - * @see #winToShapeCoord(Scene, int, int, PMVMatrix, float[]) - */ - public float[/*3*/] winToShapeCoord(final PMVMatrix pmv, final int[/*4*/] viewport, final int glWinX, final int glWinY, final float[/*3*/] objPos) { - final float[] ctr = getBounds().getCenter(); - final float[] tmp = new float[3]; - - if( pmv.gluProject(ctr[0], ctr[1], ctr[2], viewport, 0, tmp, 0) ) { - // System.err.printf("Shape::winToObjCoord.0: shape %d: obj [%15.10ff, %15.10ff, %15.10ff] -> win [%d / %d -> %7.2ff, %7.2ff, %7.2ff, diff %7.2ff x %7.2ff]%n", getName(), ctr[0], ctr[1], ctr[2], glWinX, glWinY, tmp[0], tmp[1], tmp[2], glWinX-tmp[0], glWinY-tmp[1]); - if( pmv.gluUnProject(glWinX, glWinY, tmp[2], viewport, 0, objPos, 0) ) { - // System.err.printf("Shape::winToObjCoord.X: shape %d: win [%d, %d, %7.2ff] -> obj [%15.10ff, %15.10ff, %15.10ff]%n", getName(), glWinX, glWinY, tmp[2], objPos[0], objPos[1], objPos[2]); - return objPos; - } - } - return null; - } - - /** - * Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate. - * <p> - * The given {@link PMVMatrix} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} properly for this shape - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param pmvMatrixSetup {@link Scene.PMVMatrixSetup} to {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} given {@link PMVMatrix} {@code pmv}. - * @param viewport used viewport for {@link PMVMatrix#gluUnProject(float, float, float, int[], int, float[], int)} - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link #setTransform(PMVMatrix) shape-transformed} and can be reused by the caller. - * @param objPos float[3] target object position of glWinX/glWinY relative to this shape - * @return given float[3] {@code objPos} for successful gluProject(..) and gluUnProject(..) operation, otherwise {@code null} - * @see #winToShapeCoord(PMVMatrix, int[], int, int, float[]) - * @see #winToShapeCoord(Scene, int, int, PMVMatrix, float[]) - */ - public float[/*3*/] winToShapeCoord(final Scene.PMVMatrixSetup pmvMatrixSetup, final int[/*4*/] viewport, final int glWinX, final int glWinY, final PMVMatrix pmv, final float[/*3*/] objPos) { - pmvMatrixSetup.set(pmv, viewport[0], viewport[1], viewport[2], viewport[3]); - setTransform(pmv); - return this.winToShapeCoord(pmv, viewport, glWinX, glWinY, objPos); - } - - /** - * Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate. - * <p> - * The given {@link PMVMatrix} will be {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) setup} properly for this shape - * including this shape's {@link #setTransform(PMVMatrix)}. - * </p> - * @param scene {@link Scene} to retrieve {@link Scene.PMVMatrixSetup} and the viewport. - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - * @param pmv a new {@link PMVMatrix} which will {@link Scene.PMVMatrixSetup#set(PMVMatrix, int, int, int, int) be setup}, - * {@link #setTransform(PMVMatrix) shape-transformed} and can be reused by the caller. - * @param objPos float[3] target object position of glWinX/glWinY relative to this shape - * @return given float[3] {@code objPos} for successful gluProject(..) and gluUnProject(..) operation, otherwise {@code null} - * @see #winToShapeCoord(PMVMatrix, int[], int, int, float[]) - * @see #winToShapeCoord(com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup, int[], int, int, PMVMatrix, float[]) - */ - public float[/*3*/] winToShapeCoord(final Scene scene, final int glWinX, final int glWinY, final PMVMatrix pmv, final float[/*3*/] objPos) { - return this.winToShapeCoord(scene.getPMVMatrixSetup(), scene.getViewport(), glWinX, glWinY, pmv, objPos); - } - - public float[] getColor() { - return rgbaColor; - } - - /** - * Set base color. - * <p> - * Default base-color w/o color channel, will be modulated w/ pressed- and toggle color - * </p> - */ - public final void setColor(final float r, final float g, final float b, final float a) { - this.rgbaColor[0] = r; - this.rgbaColor[1] = g; - this.rgbaColor[2] = b; - this.rgbaColor[3] = a; - } - - /** - * Set pressed color. - * <p> - * Default pressed color-factor w/o color channel, modulated base-color. 0.75 * 1.2 = 0.9 - * </p> - */ - public final void setPressedColorMod(final float r, final float g, final float b, final float a) { - this.pressedRGBAModulate[0] = r; - this.pressedRGBAModulate[1] = g; - this.pressedRGBAModulate[2] = b; - this.pressedRGBAModulate[3] = a; - } - - /** - * Set toggle-on color. - * <p> - * Default toggle-on color-factor w/o color channel, modulated base-color. 0.75 * 1.13 ~ 0.85 - * </p> - */ - public final void setToggleOnColorMod(final float r, final float g, final float b, final float a) { - this.toggleOnRGBAModulate[0] = r; - this.toggleOnRGBAModulate[1] = g; - this.toggleOnRGBAModulate[2] = b; - this.toggleOnRGBAModulate[3] = a; - } - - /** - * Set toggle-off color. - * <p> - * Default toggle-off color-factor w/o color channel, modulated base-color. 0.75 * 0.86 ~ 0.65 - * </p> - */ - public final void setToggleOffColorMod(final float r, final float g, final float b, final float a) { - this.toggleOffRGBAModulate[0] = r; - this.toggleOffRGBAModulate[1] = g; - this.toggleOffRGBAModulate[2] = b; - this.toggleOffRGBAModulate[3] = a; - } - - @Override - public final String toString() { - return getClass().getSimpleName()+"["+getSubString()+"]"; - } - - public String getSubString() { - final String pivotS; - if( !VectorUtil.isVec3Zero(rotPivot, 0, FloatUtil.EPSILON) ) { - pivotS = "pivot["+rotPivot[0]+", "+rotPivot[1]+", "+rotPivot[2]+"], "; - } else { - pivotS = ""; - } - final String scaleS; - if( !VectorUtil.isVec3Equal(scale, 0, VectorUtil.VEC3_ONE, 0, FloatUtil.EPSILON) ) { - scaleS = "scale["+scale[0]+", "+scale[1]+", "+scale[2]+"], "; - } else { - scaleS = "scale 1, "; - } - final String rotateS; - if( !rotation.isIdentity() ) { - rotateS = "rot "+rotation+", "; - } else { - rotateS = ""; - } - return "enabled "+enabled+", toggle[able "+toggleable+", state "+toggle+"], pos["+position[0]+", "+position[1]+", "+position[2]+ - "], "+pivotS+scaleS+rotateS+ - "box "+box; - } - - // - // Input - // - - public void setPressed(final boolean b) { - this.down = b; - markStateDirty(); - } - public boolean isPressed() { - return this.down; - } - - public void setToggleable(final boolean toggleable) { - this.toggleable = toggleable; - } - - /** - * Returns true if this shape is toggable, - * i.e. rendered w/ {@link #setToggleOnColorMod(float, float, float, float)} or {@link #setToggleOffColorMod(float, float, float, float)}. - */ - public boolean isToggleable() { - return toggleable; - } - public void setToggle(final boolean v) { - toggle = v; - markStateDirty(); - } - public void toggle() { - if( isToggleable() ) { - toggle = !toggle; - } - markStateDirty(); - } - public boolean isToggleOn() { return toggle; } - - /** - * Set whether this shape is draggable, - * i.e. translated by 1-pointer-click and drag. - * <p> - * Default draggable is true. - * </p> - */ - public void setDraggable(final boolean draggable) { - this.draggable = draggable; - } - public boolean isDraggable() { - return draggable; - } - - /** - * Set whether this shape is resizable, - * i.e. zoomed by 1-pointer-click and drag in 1/4th bottom-left and bottom-right corner. - * <p> - * Default resizable is true. - * </p> - */ - public void setResizable(final boolean resizable) { - this.resizable = resizable; - } - public boolean isResizable() { - return resizable; - } - - public final void addMouseListener(final MouseGestureListener l) { - if(l == null) { - return; - } - @SuppressWarnings("unchecked") - final ArrayList<MouseGestureListener> clonedListeners = (ArrayList<MouseGestureListener>) mouseListeners.clone(); - clonedListeners.add(l); - mouseListeners = clonedListeners; - } - - public final void removeMouseListener(final MouseGestureListener l) { - if (l == null) { - return; - } - @SuppressWarnings("unchecked") - final ArrayList<MouseGestureListener> clonedListeners = (ArrayList<MouseGestureListener>) mouseListeners.clone(); - clonedListeners.remove(l); - mouseListeners = clonedListeners; - } - - /** - * Combining {@link MouseListener} and {@link GestureListener} - */ - public static interface MouseGestureListener extends MouseListener, GestureListener { - } - - /** - * Convenient adapter combining dummy implementation for {@link MouseListener} and {@link GestureListener} - */ - public static abstract class MouseGestureAdapter extends MouseAdapter implements MouseGestureListener { - @Override - public void gestureDetected(final GestureEvent gh) { - } - } - - /** - * {@link Shape} event info for propagated {@link NEWTEvent}s - * containing reference of {@link #shape the intended shape} as well as - * the {@link #objPos rotated relative position} to this shape. - * The latter is normalized to bottom-left zero origin, allowing easier usage. - */ - public static class EventInfo { - /** The associated {@link Shape} for this event */ - public final Shape shape; - /** The relative object coordinate of glWinX/glWinY to the associated {@link Shape}. */ - public final float[] objPos; - /** The GL window coordinates, origin bottom-left */ - public final int[] winPos; - /** The drag delta of the relative object coordinate of glWinX/glWinY to the associated {@link Shape}. */ - public final float[] objDrag = { 0f, 0f }; - /** The drag delta of GL window coordinates, origin bottom-left */ - public final int[] winDrag = { 0, 0 }; - - /** - * Ctor - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - * @param shape associated shape - * @param objPos relative object coordinate of glWinX/glWinY to the associated shape. - */ - EventInfo(final int glWinX, final int glWinY, final Shape shape, final float[] objPos) { - this.winPos = new int[] { glWinX, glWinY }; - this.shape = shape; - this.objPos = objPos; - } - - @Override - public String toString() { - return "EventDetails[winPos ["+winPos[0]+", "+winPos[1]+"], objPos ["+objPos[0]+", "+objPos[1]+", "+objPos[2]+"], "+shape+"]"; - } - } - - private boolean dragFirst = false; - private final float[] objDraggedFirst = { 0f, 0f }; // b/c its relative to Shape and we stick to it - private final int[] winDraggedLast = { 0, 0 }; // b/c its absolute window pos - private boolean inDrag = false; - private int inResize = 0; // 1 br, 2 bl - private static final float resize_sxy_min = 1f/200f; // 1/2% - TODO: Maybe customizable? - private static final float resize_section = 1f/5f; // resize action in a corner - - /** - * Dispatch given NEWT mouse event to this shape - * @param e original Newt {@link MouseEvent} - * @param glWinX in GL window coordinates, origin bottom-left - * @param glWinY in GL window coordinates, origin bottom-left - * @param objPos object position of mouse event relative to this shape - */ - /* pp */ final void dispatchMouseEvent(final MouseEvent e, final int glWinX, final int glWinY, final float[] objPos) { - final Shape.EventInfo shapeEvent = new EventInfo(glWinX, glWinY, this, objPos); - - final short eventType = e.getEventType(); - if( 1 == e.getPointerCount() ) { - switch( eventType ) { - case MouseEvent.EVENT_MOUSE_CLICKED: - toggle(); - break; - case MouseEvent.EVENT_MOUSE_PRESSED: - dragFirst = true; - setPressed(true); - break; - case MouseEvent.EVENT_MOUSE_RELEASED: - // Release active shape: last pointer has been lifted! - setPressed(false); - inDrag = false; - inResize = 0; - break; - } - } - switch( eventType ) { - case MouseEvent.EVENT_MOUSE_DRAGGED: { - // 1 pointer drag and potential drag-resize - if(dragFirst) { - objDraggedFirst[0] = objPos[0]; - objDraggedFirst[1] = objPos[1]; - winDraggedLast[0] = glWinX; - winDraggedLast[1] = glWinY; - dragFirst=false; - - final float ix = objPos[0]; - final float iy = objPos[1]; - final float minx_br = box.getMaxX() - box.getWidth() * resize_section; - final float miny_br = box.getMinY(); - final float maxx_br = box.getMaxX(); - final float maxy_br = box.getMinY() + box.getHeight() * resize_section; - if( minx_br <= ix && ix <= maxx_br && - miny_br <= iy && iy <= maxy_br ) { - inResize = 1; // bottom-right - } else { - final float minx_bl = box.getMinX(); - final float miny_bl = box.getMinY(); - final float maxx_bl = box.getMinX() + box.getWidth() * resize_section; - final float maxy_bl = box.getMinY() + box.getHeight() * resize_section; - if( minx_bl <= ix && ix <= maxx_bl && - miny_bl <= iy && iy <= maxy_bl ) { - inResize = 2; // bottom-left - } else { - inDrag = true; - } - } - if( DEBUG ) { - System.err.printf("DragFirst: drag %b, resize %d, obj[%.4f, %.4f, %.4f], drag +[%.4f, %.4f]%n", - inDrag, inResize, objPos[0], objPos[1], objPos[2], shapeEvent.objDrag[0], shapeEvent.objDrag[1]); - System.err.printf("DragFirst: %s%n", this); - } - return; - } - shapeEvent.objDrag[0] = objPos[0] - objDraggedFirst[0]; - shapeEvent.objDrag[1] = objPos[1] - objDraggedFirst[1]; - shapeEvent.winDrag[0] = glWinX - winDraggedLast[0]; - shapeEvent.winDrag[1] = glWinY - winDraggedLast[1]; - winDraggedLast[0] = glWinX; - winDraggedLast[1] = glWinY; - if( 1 == e.getPointerCount() ) { - final float sdx = shapeEvent.objDrag[0] * scale[0]; // apply scale, since operation - final float sdy = shapeEvent.objDrag[1] * scale[1]; // is from a scaled-model-viewpoint - if( 0 != inResize && resizable ) { - final float bw = box.getWidth(); - final float bh = box.getHeight(); - final float sx; - if( 1 == inResize ) { - sx = scale[0] + sdx/bw; // bottom-right - } else { - sx = scale[0] - sdx/bw; // bottom-left - } - final float sy = scale[1] - sdy/bh; - if( resize_sxy_min <= sx && resize_sxy_min <= sy ) { // avoid scale flip - if( DEBUG ) { - System.err.printf("DragZoom: resize %d, win[%4d, %4d], obj[%.4f, %.4f, %.4f], dxy +[%.4f, %.4f], sdxy +[%.4f, %.4f], scale [%.4f, %.4f] -> [%.4f, %.4f]%n", - inResize, glWinX, glWinY, objPos[0], objPos[1], objPos[2], - shapeEvent.objDrag[0], shapeEvent.objDrag[1], sdx, sdy, - scale[0], scale[1], sx, sy); - } - if( 1 == inResize ) { - move( 0, sdy, 0f); // bottom-right, sticky left- and top-edge - } else { - move( sdx, sdy, 0f); // bottom-left, sticky right- and top-edge - } - setScale(sx, sy, scale[2]); - } - return; // FIXME: pass through event? Issue zoom event? - } else if( inDrag && draggable ) { - if( DEBUG ) { - System.err.printf("DragMove: win[%4d, %4d] +[%2d, %2d], obj[%.4f, %.4f, %.4f] +[%.4f, %.4f]%n", - glWinX, glWinY, shapeEvent.winDrag[0], shapeEvent.winDrag[1], - objPos[0], objPos[1], objPos[2], shapeEvent.objDrag[0], shapeEvent.objDrag[1]); - } - move( sdx, sdy, 0f); - // FIXME: Pass through event? Issue move event? - } - } - } - break; - } - e.setAttachment(shapeEvent); - - for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) { - final MouseGestureListener l = mouseListeners.get(i); - switch( eventType ) { - case MouseEvent.EVENT_MOUSE_CLICKED: - l.mouseClicked(e); - break; - case MouseEvent.EVENT_MOUSE_ENTERED: - l.mouseEntered(e); - break; - case MouseEvent.EVENT_MOUSE_EXITED: - l.mouseExited(e); - break; - case MouseEvent.EVENT_MOUSE_PRESSED: - l.mousePressed(e); - break; - case MouseEvent.EVENT_MOUSE_RELEASED: - l.mouseReleased(e); - break; - case MouseEvent.EVENT_MOUSE_MOVED: - l.mouseMoved(e); - break; - case MouseEvent.EVENT_MOUSE_DRAGGED: - l.mouseDragged(e); - break; - case MouseEvent.EVENT_MOUSE_WHEEL_MOVED: - l.mouseWheelMoved(e); - break; - default: - throw new NativeWindowException("Unexpected mouse event type " + e.getEventType()); - } - } - } - - /** - * @param e original Newt {@link GestureEvent} - * @param glWinX x-position in OpenGL model space - * @param glWinY y-position in OpenGL model space - * @param pmv well formed PMVMatrix for this shape - * @param viewport the viewport - * @param objPos object position of mouse event relative to this shape - */ - /* pp */ final void dispatchGestureEvent(final GestureEvent e, final int glWinX, final int glWinY, final PMVMatrix pmv, final int[] viewport, final float[] objPos) { - if( resizable && e instanceof PinchToZoomGesture.ZoomEvent ) { - final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) e; - final float pixels = ze.getDelta() * ze.getScale(); // - final int winX2 = glWinX + Math.round(pixels); - final float[] objPos2 = winToShapeCoord(pmv, viewport, winX2, glWinY, new float[3]); - if( null == objPos2 ) { - return; - } - final float dx = objPos2[0]; - final float dy = objPos2[1]; - final float sx = scale[0] + ( dx/box.getWidth() ); // bottom-right - final float sy = scale[1] + ( dy/box.getHeight() ); - if( DEBUG ) { - System.err.printf("DragZoom: resize %b, obj %4d/%4d, %.3f/%.3f/%.3f %.3f/%.3f/%.3f + %.3f/%.3f -> %.3f/%.3f%n", - inResize, glWinX, glWinY, objPos[0], objPos[1], objPos[2], position[0], position[1], position[2], - dx, dy, sx, sy); - } - if( resize_sxy_min <= sx && resize_sxy_min <= sy ) { // avoid scale flip - if( DEBUG ) { - System.err.printf("PinchZoom: pixels %f, obj %4d/%4d, %.3f/%.3f/%.3f %.3f/%.3f/%.3f + %.3f/%.3f -> %.3f/%.3f%n", - pixels, glWinX, glWinY, objPos[0], objPos[1], objPos[2], position[0], position[1], position[2], - dx, dy, sx, sy); - } - // move(dx, dy, 0f); - setScale(sx, sy, scale[2]); - } - return; // FIXME: pass through event? Issue zoom event? - } - final Shape.EventInfo shapeEvent = new EventInfo(glWinX, glWinY, this, objPos); - e.setAttachment(shapeEvent); - - for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) { - mouseListeners.get(i).gestureDetected(e); - } - } - - // - // - // - - protected abstract void validateImpl(final GLProfile glp, final GL2ES2 gl); - - protected abstract void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount, float[] rgba); - - protected abstract void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer); - - protected abstract void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer); - - /** - * Returns true if implementation uses an extra color channel or texture - * which will be modulated with the passed rgba color {@link #drawImpl0(GL2ES2, RegionRenderer, int[], float[])}. - * - * Otherwise the base color will be modulated and passed to {@link #drawImpl0(GL2ES2, RegionRenderer, int[], float[])}. - */ - public abstract boolean hasColorChannel(); - - // - // - // -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Button.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Button.java deleted file mode 100644 index 2f2e4c469..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Button.java +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl.shapes; - -import com.jogamp.opengl.GL2ES2; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.font.Font; -import com.jogamp.graph.geom.plane.AffineTransform; -import com.jogamp.graph.ui.gl.GraphShape; -import com.jogamp.opengl.math.geom.AABBox; - -import jogamp.graph.ui.shapes.Label0; - -/** - * A GraphUI text labeled {@link RoundButton} {@link GraphShape} - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * This button is rendered with a round oval shape. - * To render it rectangular, {@link #setCorner(float)} to zero. - * </p> - */ -public class Button extends RoundButton { - /** {@value} */ - public static final float DEFAULT_SPACING_X = 0.12f; - /** {@value} */ - public static final float DEFAULT_SPACING_Y = 0.42f; - - private static final float DEFAULT_2PASS_LABEL_ZOFFSET = -0.005f; // -0.05f; - private float twoPassLabelZOffset = DEFAULT_2PASS_LABEL_ZOFFSET; - - private final Label0 label; - private float spacingX = DEFAULT_SPACING_X; - private float spacingY = DEFAULT_SPACING_Y; - - private final AffineTransform tempT1 = new AffineTransform(); - private final AffineTransform tempT2 = new AffineTransform(); - private final AffineTransform tempT3 = new AffineTransform(); - - public Button(final int renderModes, final Font labelFont, - final String labelText, final float width, - final float height) { - super(renderModes | Region.COLORCHANNEL_RENDERING_BIT, width, height); - this.label = new Label0(labelFont, labelText, new float[] { 1.33f, 1.33f, 1.33f, 1.0f }); // 0.75 * 1.33 = 1.0 - setColor(0.75f, 0.75f, 0.75f, 1.0f); - setPressedColorMod(0.9f, 0.9f, 0.9f, 0.7f); - setToggleOffColorMod(0.65f, 0.65f, 0.65f, 1.0f); - setToggleOnColorMod(0.85f, 0.85f, 0.85f, 1.0f); - } - - public Font getFont() { return label.getFont(); } - public String getLaben() { return label.getText(); } - - @Override - public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { - // Setup poly offset for z-fighting - // gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); - // gl.glPolygonOffset(0f, 1f); - super.draw(gl, renderer, sampleCount); - // gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); - } - - @Override - protected void addShapeToRegion() { - final OutlineShape shape = new OutlineShape(vertexFactory); - if(corner == 0.0f) { - createSharpOutline(shape, twoPassLabelZOffset); - } else { - createCurvedOutline(shape, twoPassLabelZOffset); - } - shape.setIsQuadraticNurbs(); - shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, null, rgbaColor); - box.resize(shape.getBounds()); - - // Precompute text-box size .. guessing pixelSize - final float lw = box.getWidth() * ( 1f - spacingX ) ; - final float lh = box.getHeight() * ( 1f - spacingY ) ; - final AABBox lbox0_em = label.getFont().getGlyphBounds(label.getText(), tempT1, tempT2); - final float lsx = lw / lbox0_em.getWidth(); - final float lsy = lh / lbox0_em.getHeight(); - final float lScale = lsx < lsy ? lsx : lsy; - - // Setting left-corner transform using text-box in font em-size [0..1] - final AABBox lbox1_s = new AABBox(lbox0_em).scale2(lScale, new float[3]); - // Center text .. (share same center w/ button) - final float[] lctr = lbox1_s.getCenter(); - final float[] ctr = box.getCenter(); - final float[] ltxy = new float[] { ctr[0] - lctr[0], ctr[1] - lctr[1] }; - - if( DEBUG_DRAW ) { - System.err.println("Button: dim "+width+" x "+height+", spacing "+spacingX+", "+spacingY); - System.err.println("Button: net-text "+lw+" x "+lh); - System.err.println("Button: shape "+box); - System.err.println("Button: text_em "+lbox0_em+" em, "+label.getText()); - System.err.println("Button: lscale "+lsx+" x "+lsy+" -> "+lScale); - System.err.printf ("Button: text_s %s%n", lbox1_s); - System.err.printf ("Button: ltxy %f / %f, %f / %f%n", ltxy[0], ltxy[1], ltxy[0] * lScale, ltxy[1] * lScale); - } - - final AABBox lbox2 = label.addShapeToRegion(lScale, region, ltxy, tempT1, tempT2, tempT3); - if( DEBUG_DRAW ) { - System.err.printf("Button.X: lbox2 %s%n", lbox2); - } - - setRotationPivot( ctr ); - - if( DEBUG_DRAW ) { - System.err.println("XXX.Button: Added Shape: "+shape+", "+box); - } - } - - public float get2PassLabelZOffset() { return twoPassLabelZOffset; } - - public void set2PassLabelZOffset(final float v) { - twoPassLabelZOffset = v; - markShapeDirty(); - } - - public final float getSpacingX() { return spacingX; } - public final float getSpacingY() { return spacingY; } - - /** - * In percent of text label - * @param spacingX spacing in percent on X, default is {@link #DEFAULT_SPACING_X} - * @param spacingY spacing in percent on Y, default is {@link #DEFAULT_SPACING_Y} - */ - public final void setSpacing(final float spacingX, final float spacingY) { - if ( spacingX < 0.0f ) { - this.spacingX = 0.0f; - } else if ( spacingX > 1.0f ) { - this.spacingX = 1.0f; - } else { - this.spacingX = spacingX; - } - if ( spacingY < 0.0f ) { - this.spacingY = 0.0f; - } else if ( spacingY > 1.0f ) { - this.spacingY = 1.0f; - } else { - this.spacingY = spacingY; - } - markShapeDirty(); - } - - public final float[] getLabelColor() { - return label.getColor(); - } - - public final void setLabelColor(final float r, final float g, final float b) { - label.setColor(r, g, b, 1.0f); - markShapeDirty(); - } - - public final void setFont(final Font labelFont) { - if( !label.getFont().equals(labelFont) ) { - label.setFont(labelFont); - markShapeDirty(); - } - } - public final void setLabel(final String labelText) { - if( !label.getText().equals(labelText) ) { - label.setText(labelText); - markShapeDirty(); - } - } - public final void setLabel(final Font labelFont, final String labelText) { - if( !label.getText().equals(labelText) || !label.getFont().equals(labelFont) ) { - label.setFont(labelFont); - label.setText(labelText); - markShapeDirty(); - } - } - - @Override - public String getSubString() { - return super.getSubString()+", "+ label + ", " + "spacing["+spacingX+", "+spacingY+"]"; - } -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/CrossHair.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/CrossHair.java deleted file mode 100644 index 534e6fc7b..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/CrossHair.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl.shapes; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.GraphShape; - -/** - * A GraphUI Crosshair {@link GraphShape} - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - */ -public class CrossHair extends GraphShape { - private float width, height, lineWidth; - - public CrossHair(final int renderModes, final float width, final float height, final float linewidth) { - super(renderModes); - this.width = width; - this.height = height; - this.lineWidth = linewidth; - } - - public final float getWidth() { return width; } - public final float getHeight() { return height; } - public final float getLineWidth() { return lineWidth; } - - public void setDimension(final float width, final float height, final float lineWidth) { - this.width = width; - this.height = height; - this.lineWidth = lineWidth; - markShapeDirty(); - } - - @Override - protected void addShapeToRegion() { - final OutlineShape shape = new OutlineShape(vertexFactory); - - final float lwh = lineWidth/2f; - - final float tw = getWidth(); - final float th = getHeight(); - final float twh = tw/2f; - final float thh = th/2f; - - final float ctrX = 0f, ctrY = 0f; - final float ctrZ = 0f; - - // middle vertical (CCW!) - shape.moveTo(ctrX-lwh, ctrY-thh, ctrZ); - shape.lineTo(ctrX+lwh, ctrY-thh, ctrZ); - shape.lineTo(ctrX+lwh, ctrY+thh, ctrZ); - shape.lineTo(ctrX-lwh, ctrY+thh, ctrZ); - shape.closePath(); - - // middle horizontal (CCW!) - shape.moveTo(ctrX-twh, ctrY-lwh, ctrZ); - shape.lineTo(ctrX+twh, ctrY-lwh, ctrZ); - shape.lineTo(ctrX+twh, ctrY+lwh, ctrZ); - shape.lineTo(ctrX-twh, ctrY+lwh, ctrZ); - shape.closePath(); - - shape.setIsQuadraticNurbs(); - shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, null, rgbaColor); - - box.resize(shape.getBounds()); - } - - @Override - public String getSubString() { - return super.getSubString()+", dim "+getWidth() + " x " + getHeight(); - } -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GLButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GLButton.java deleted file mode 100644 index 5fdb7991b..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GLButton.java +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Copyright 2014-2023 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.graph.ui.gl.shapes; - -import com.jogamp.opengl.GL; -import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLCapabilities; -import com.jogamp.opengl.GLCapabilitiesImmutable; -import com.jogamp.opengl.GLContext; -import com.jogamp.opengl.GLDrawable; -import com.jogamp.opengl.GLDrawableFactory; -import com.jogamp.opengl.GLEventListener; -import com.jogamp.opengl.GLOffscreenAutoDrawable; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.ui.gl.GraphShape; -import com.jogamp.opengl.FBObject; -import com.jogamp.opengl.util.texture.ImageSequence; -import com.jogamp.opengl.util.texture.Texture; - -/** - * A GraphUI {@link GLEventListener} based {@link TexSeqButton} {@link GraphShape}. - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * The {@link GLEventListener} is rendered via an {@link GLOffscreenAutoDrawable.FBO} into an {@link ImageSequence}. - * </p> - * <p> - * This button is rendered with a round oval shape. - * To render it rectangular, {@link #setCorner(float)} to zero. - * </p> - */ -public class GLButton extends TexSeqButton { - private final GLEventListener glel; - private final boolean useAlpha; - private volatile int fboWidth = 200; - private volatile int fboHeight = 200; - private volatile GLOffscreenAutoDrawable.FBO fboGLAD = null; - private boolean animateGLEL = false; - - public GLButton(final int renderModes, final float width, final float height, - final int textureUnit, final GLEventListener glel, final boolean useAlpha) { - super(renderModes, width, height, new ImageSequence(textureUnit, true)); - this.glel = glel; - this.useAlpha = useAlpha; - - setColor(0.95f, 0.95f, 0.95f, 1.0f); - setPressedColorMod(1f, 1f, 1f, 0.9f); - setToggleOffColorMod(0.8f, 0.8f, 0.8f, 1.0f); - setToggleOnColorMod(1.0f, 1.0f, 1.0f, 1.0f); - - // fake surface-size, will be overriden in initial FBO setup @ display - this.fboWidth = 320; - this.fboHeight = Math.round( 640 * height / width ); - } - - public final void setAnimate(final boolean v) { animateGLEL = v; } - public final boolean getAnimate() { return animateGLEL; } - - public final void setFBOSize(final int fboWidth, final int fboHeight) { - this.fboWidth = fboWidth; - this.fboHeight = fboHeight; - } - - public final GLOffscreenAutoDrawable.FBO getFBOAutoDrawable() { return fboGLAD; } - - @Override - protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { - ((ImageSequence)texSeq).destroy(gl); - fboGLAD.destroy(); - } - - @Override - public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { - final int[/*2*/] surfaceSize = getSurfaceSize(renderer.getMatrix(), renderer.getViewport(), new int[2]); - final boolean got_sz = null != surfaceSize && 0 < surfaceSize[0] && 0 < surfaceSize[1]; - - if( null == fboGLAD ) { - final ImageSequence imgSeq = (ImageSequence)texSeq; - - final GLContext ctx = gl.getContext(); - final GLDrawable drawable = ctx.getGLDrawable(); - final GLCapabilitiesImmutable reqCaps = drawable.getRequestedGLCapabilities(); - final GLCapabilities caps = (GLCapabilities) reqCaps.cloneMutable(); - caps.setFBO(true); - caps.setDoubleBuffered(false); - if( !useAlpha ) { - caps.setAlphaBits(0); - } - final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); - - // System.err.println("XXX FBO initSurfaceSize got_sz "+got_sz+", "+fboWidth+" x "+fboHeight+" -> "+surfaceSize[0]+" x "+surfaceSize[1]); - if( got_sz ) { - // override with real surface-size - fboWidth = surfaceSize[0]; - fboHeight = surfaceSize[1]; - } - fboGLAD = (GLOffscreenAutoDrawable.FBO) factory.createOffscreenAutoDrawable( - drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(), - caps, null, fboWidth, fboHeight); - fboWidth = 0; - fboHeight = 0; - fboGLAD.setSharedContext(ctx); - fboGLAD.setTextureUnit(imgSeq.getTextureUnit()); - fboGLAD.addGLEventListener(glel); - fboGLAD.display(); // 1st init! - - final FBObject.TextureAttachment texA01 = fboGLAD.getColorbuffer(GL.GL_FRONT).getTextureAttachment(); - final Texture tex = new Texture(texA01.getName(), imgSeq.getTextureTarget(), - fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(), fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(), - false /* mustFlipVertically */); - imgSeq.addFrame(gl, tex); - markStateDirty(); - } else if( 0 != fboWidth*fboHeight ) { - fboGLAD.setSurfaceSize(fboWidth, fboHeight); - fboWidth = 0; - fboHeight = 0; - markStateDirty(); - } else if( got_sz && ( fboGLAD.getSurfaceWidth() != surfaceSize[0] || fboGLAD.getSurfaceHeight() != surfaceSize[1] ) ) { - // System.err.println("XXX FBO setSurfaceSize "+fboGLAD.getSurfaceWidth()+" x "+fboGLAD.getSurfaceHeight()+" -> "+surfaceSize[0]+" x "+surfaceSize[1]); - final ImageSequence imgSeq = (ImageSequence)texSeq; - - fboGLAD.setSurfaceSize(surfaceSize[0], surfaceSize[1]); - fboGLAD.display(); // re-init! - - imgSeq.destroy(gl); - final FBObject.TextureAttachment texA01 = fboGLAD.getColorbuffer(GL.GL_FRONT).getTextureAttachment(); - final Texture tex = new Texture(texA01.getName(), imgSeq.getTextureTarget(), - fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(), fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(), - false /* mustFlipVertically */); - imgSeq.addFrame(gl, tex); - fboWidth = 0; - fboHeight = 0; - markStateDirty(); - } else if( animateGLEL ) { - fboGLAD.display(); - } - - super.draw(gl, renderer, sampleCount); - - if( animateGLEL ) { - markStateDirty(); // keep on going - } - } -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GlyphShape.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GlyphShape.java deleted file mode 100644 index 07c8ae0de..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GlyphShape.java +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl.shapes; - -import java.util.List; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.curve.opengl.GLRegion; -import com.jogamp.graph.font.Font; -import com.jogamp.graph.font.Font.Glyph; -import com.jogamp.graph.geom.plane.AffineTransform; -import com.jogamp.graph.ui.gl.GraphShape; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.math.Vec3f; -import com.jogamp.opengl.math.geom.AABBox; -import com.jogamp.opengl.util.texture.TextureSequence; - -/** - * Representing a single {@link Font.Glyph} as a {@link GraphShape} - * - * A GlyphShape is represented in font em-size [0..1] unscaled w/ bottom-left origin at 0/0 - * while preserving an intended position, see {@link #getOrigPos()} and {@link #getOrigPos(float)}. - * - * Scaling, if any, should be applied via {@link #setScale(float, float, float)} etc. - */ -public class GlyphShape extends GraphShape { - private final char symbol; - private final Glyph glyph; - private final Vec3f origPos; - - /** - * Creates a new GlyphShape - * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. - * @param symbol the represented character - * @param glyph the {@link Font.Glyph} - * @param x the intended unscaled X position of this Glyph, e.g. if part of a string - otherwise use zero. - * @param y the intended unscaled Y position of this Glyph, e.g. if part of a string - otherwise use zero. - * @see #processString(List, int, Font, String) - */ - public GlyphShape(final int renderModes, final char symbol, final Glyph glyph, final float x, final float y) { - super(renderModes); - this.symbol = symbol; - this.glyph = glyph; - this.origPos = new Vec3f(x, y, 0f); - if( glyph.isWhiteSpace() || null == glyph.getShape() ) { - setEnabled(false); - } - } - - /** - * Creates a new GlyphShape - * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. - * @param font the {@link Font} to lookup the symbol's {@link Font.Glyph} - * @param symbol the represented character - * @param x the intended unscaled X position of this Glyph, e.g. if part of a string - otherwise use zero. - * @param y the intended unscaled Y position of this Glyph, e.g. if part of a string - otherwise use zero. - */ - public GlyphShape(final int renderModes, final Font font, final char symbol, final float x, final float y) { - super(renderModes); - this.symbol = symbol; - this.glyph = font.getGlyph( font.getGlyphID(symbol) ); - this.origPos = new Vec3f(x, y, 0f); - if( glyph.isWhiteSpace() || null == glyph.getShape() ) { - setEnabled(false); - } - } - - /** Returns the char symbol to be rendered. */ - public char getSymbol() { - return symbol; - } - - /** - * Returns the {@link Font.Glyph} to be rendered. - */ - public Glyph getGlyph() { - return glyph; - } - - /** - * Returns the {@link Font} used to render the text - */ - public Font getFont() { - return glyph.getFont(); - } - - /** - * Returns the unscaled original position of this glyph, e.g. if part of a string, otherwise zero. - * - * Method borrows and returns the internal instance. - * - * @see #processString(List, int, Font, String) - */ - public Vec3f getOrigPos() { return origPos; } - - /** - * Returns the unscaled original position of this glyph, e.g. if part of a string, otherwise zero. - * - * @param s {@link Vec3f} storage to be returned - * @return storage containing the unscaled original position - * @see #processString(List, int, Font, String) - */ - public Vec3f getOrigPos(final Vec3f s) { return s.set(origPos); } - - /** - * Returns a copy of the scaled original position of this glyph, see {@link #getOrigPos(Vec3f)} - * @see #processString(List, int, Font, String) - */ - public Vec3f getOrigPos(final float scale) { return origPos.mul(scale); } - - /** - * Returns the scaled original position of this glyph, see {@link #getOrigPos(float)} - * @param s {@link Vec3f} storage to be returned - * @return storage containing the scaled original position - * @see #processString(List, int, Font, String) - */ - public Vec3f getOrigPos(final Vec3f s, final float scale) { return s.set(origPos).scale(scale); } - - /** Resets this Shape's position to the scaled original position, see {@link #getOrigPos(float)}. */ - public void resetPos(final float scale) { - moveTo(origPos.x() * scale, origPos.y() * scale, 0f); - } - - /** Resets this Shape's position to the scaled original position and {@link #setScale(float, float, float) set scale}, see {@link #resetPos(float)}. */ - public void resetPosAndScale(final float scale) { - moveTo(origPos.x() * scale, origPos.y() * scale, 0f); - setScale(scale, scale, 1f); - } - - /** Returns {@link Font#getLineHeight()}. */ - public float getLineHeight() { - return glyph.getFont().getLineHeight(); - } - - /** - * Process the given text resulting in a list of {@link GlyphShape}s with stored original position {@link #getOrigX()} and {@link #getOrigY()} each at font em-size [0..1]. - * @param res storage for resulting {@link GlyphShape}s. - * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. - * @param font {@link Font} used - * @param text text to be represented - * @return the bounding box of the given string by taking each glyph's font em-sized [0..1] OutlineShape into account. - * @see #getOrigX() - * @see #getOrigY() - */ - public static final AABBox processString(final List<GlyphShape> res, final int renderModes, final Font font, final String text) { - final Font.GlyphVisitor fgv = new Font.GlyphVisitor() { - @Override - public void visit(final char symbol, final Glyph glyph, final AffineTransform t) { - if( !glyph.isWhiteSpace() && null != glyph.getShape() ) { - res.add( new GlyphShape(renderModes, symbol, glyph, t.getTranslateX(), t.getTranslateY()) ); - } - } - }; - return font.processString(fgv, null, text, new AffineTransform(), new AffineTransform()); - } - - @Override - protected void addShapeToRegion() { - final OutlineShape shape = glyph.getShape(); - box.reset(); - if( null != shape ) { - final AABBox sbox = shape.getBounds(); - final AffineTransform tmp = new AffineTransform(); - // Enforce bottom-left origin @ 0/0 for good drag-zoom experience, - // but keep the underline (decline) intact! - tmp.setToTranslation(-sbox.getMinX(), -sbox.getMinY() + glyph.getBounds().getMinY()); - shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, tmp, rgbaColor); - setRotationPivot( sbox.getCenter() ); - box.resize(tmp.transform(sbox, new AABBox())); - } - } - - @Override - public String getSubString() { - return super.getSubString()+", origPos " + origPos.x() + " / " + origPos.y() + ", '" + symbol + "'"; - } -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/ImageButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/ImageButton.java deleted file mode 100644 index d5718d98a..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/ImageButton.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright 2014-2023 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.graph.ui.gl.shapes; - -import com.jogamp.opengl.GL2ES2; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.ui.gl.GraphShape; -import com.jogamp.opengl.util.texture.ImageSequence; - -/** - * A GraphUI {@link ImageSequence} based {@link TexSeqButton} {@link GraphShape}. - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * This button is rendered with a round oval shape. - * To render it rectangular, {@link #setCorner(float)} to zero. - * </p> - */ -public class ImageButton extends TexSeqButton { - - public ImageButton(final int renderModes, final float width, - final float height, final ImageSequence texSeq) { - super(renderModes, width, height, texSeq); - setColor(0.95f, 0.95f, 0.95f, 1.0f); - setPressedColorMod(1f, 1f, 1f, 0.9f); - setToggleOffColorMod(0.8f, 0.8f, 0.8f, 1.0f); - setToggleOnColorMod(1.0f, 1.0f, 1.0f, 1.0f); - } - - public final void setCurrentIdx(final int idx) { - ((ImageSequence)texSeq).setCurrentIdx(idx); - markStateDirty(); - } - - @Override - public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { - super.draw(gl, renderer, sampleCount); - if( !((ImageSequence)texSeq).getManualStepping() ) { - markStateDirty(); // keep on going - } - }; -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Label.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Label.java deleted file mode 100644 index cad8689ec..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Label.java +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl.shapes; - -import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.math.FloatUtil; -import com.jogamp.opengl.math.geom.AABBox; -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.opengl.GLRegion; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.font.Font; -import com.jogamp.graph.font.Font.Glyph; -import com.jogamp.graph.geom.plane.AffineTransform; -import com.jogamp.graph.ui.gl.GraphShape; - -/** - * A GraphUI text label {@link GraphShape} - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - */ -public class Label extends GraphShape { - private Font font; - private float fontScale; - private String text; - - private final AffineTransform tempT1 = new AffineTransform(); - private final AffineTransform tempT2 = new AffineTransform(); - private final AffineTransform tempT3 = new AffineTransform(); - - /** - * Label ctor using a separate {@code fontScale} to scale the em-sized type glyphs - * @param renderModes region renderModes - * @param font the font - * @param fontScale font-scale factor, by which the em-sized type glyphs shall be scaled - * @param text the text to render - */ - public Label(final int renderModes, final Font font, final float fontScale, final String text) { - super(renderModes); - this.font = font; - this.fontScale = fontScale; - this.text = text; - } - - /** - * Label ctor using em-size type glyphs - * @param renderModes region renderModes - * @param font the font - * @param text the text to render - */ - public Label(final int renderModes, final Font font, final String text) { - super(renderModes); - this.font = font; - this.fontScale = 1f; - this.text = text; - } - - /** Return the text to be rendered. */ - public String getText() { - return text; - } - - /** - * Set the text to be rendered. Shape update is pending until next {@link #draw(GL2ES2, RegionRenderer, int[])} or {@link #validate(GL2ES2)}. - * @param text the text to be set. - * @return true if text has been updated, false if unchanged. - */ - public boolean setText(final String text) { - if( !this.text.equals(text) ) { - this.text = text; - markShapeDirty(); - return true; - } else { - return false; - } - } - - /** - * Set the text to be rendered and immediately updates the shape if necessary. - * @param gl {@link GL2ES2} to issue {@link #validate(GL2ES2)} in case text changed to immediately update shape and {@link #getBounds()} - * @param text the text to be set. - * @return true if text has been updated, false if unchanged. - */ - public boolean setText(final GL2ES2 gl, final String text) { - if( setText(text) ) { - validate(gl); - return true; - } else { - return false; - } - } - - /** - * Set the text to be rendered and immediately updates the shape if necessary. - * @param glp {@link GLProfile} to issue {@link #validate(GLProfile)} in case text changed to immediately update shape and {@link #getBounds()} - * @param text the text to be set. - * @return true if text has been updated, false if unchanged. - */ - public boolean setText(final GLProfile glp, final String text) { - if( setText(text) ) { - validate(glp); - return true; - } else { - return false; - } - } - - /** - * Return the {@link Font} used to render the text - */ - public Font getFont() { - return font; - } - - /** - * Set the {@link Font} used to render the text - * @param font the font to be set. - * @return true if font has been updated, false if unchanged. - */ - public boolean setFont(final Font font) { - if( !this.font.equals(font) ) { - this.font = font; - markShapeDirty(); - return true; - } else { - return false; - } - } - - /** - * Gets the font-scale factor, by which the em-sized type glyphs shall be scaled. - */ - public float getFontScale() { - return fontScale; - } - - /** Returns {@link Font#getLineHeight()} * {@link #getFontScale()}. */ - public float getLineHeight() { - return fontScale * font.getLineHeight(); - } - - /** Returns {@link Font#getLineHeight()} * {@link #getFontScale()} * {@link #getScaleY()}. */ - public float getScaledLineHeight() { - return getScaleY() * fontScale * font.getLineHeight(); - } - - /** - * Sets the font-scale factor, by which the em-sized type glyphs shall be scaled. - * <p> - * This will lead to a recreate the shape's region in case fontScale differs. - * </p> - * <p> - * Use {@link #scale(float, float, float)} for non-expensive shape scaling. - * </p> - * @param fontScale font-scale factor, by which the em-sized type glyphs shall be scaled - * @return true if font-scale has been updated, false if unchanged. - */ - public boolean setFontScale(final float fontScale) { - if( this.fontScale != fontScale ) { - this.fontScale = fontScale; - markShapeDirty(); - return true; - } else { - return false; - } - } - - @Override - protected GLRegion createGLRegion(final GLProfile glp) { - return GLRegion.create(glp, getRenderModes(), null, font, text); - } - - private final Font.GlyphVisitor glyphVisitor = new Font.GlyphVisitor() { - @Override - public void visit(final char symbol, final Glyph glyph, final AffineTransform t) { - if( glyph.isWhiteSpace() ) { - return; - } - final OutlineShape shape = glyph.getShape(); - shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, t, rgbaColor); - } - }; - - @Override - protected void addShapeToRegion() { - AABBox fbox = font.getGlyphBounds(text, tempT2, tempT3); - tempT1.setToScale(fontScale, fontScale); - tempT1.translate(-fbox.getMinX(), -fbox.getMinY(), tempT2); // enforce bottom-left origin @ 0/0 for good drag-zoom experience - fbox = font.processString(glyphVisitor, tempT1, text, tempT2, tempT3); - setRotationPivot( fbox.getCenter() ); - box.copy(fbox); - } - - @Override - public String getSubString() { - final int m = Math.min(text.length(), 8); - return super.getSubString()+", fscale " + fontScale + ", '" + text.substring(0, m)+"'"; - } -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/MediaButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/MediaButton.java deleted file mode 100644 index 6b26c58b8..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/MediaButton.java +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright 2014-2023 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.graph.ui.gl.shapes; - -import com.jogamp.opengl.GL2ES2; -import com.jogamp.common.util.InterruptSource; -import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.ui.gl.GraphShape; -import com.jogamp.opengl.util.av.GLMediaPlayer; -import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener; -import com.jogamp.opengl.util.av.GLMediaPlayer.StreamException; -import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; - -/** - * A GraphUI {@link GLMediaPlayer} based {@link TexSeqButton} {@link GraphShape}. - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * This button is rendered with a round oval shape. - * To render it rectangular, {@link #setCorner(float)} to zero. - * </p> - */ -public class MediaButton extends TexSeqButton { - private boolean verbose = false; - - /** - * @param renderModes - * @param width - * @param height - * @param mPlayer - * @param mPlayerListener - */ - public MediaButton(final int renderModes, final float width, - final float height, final GLMediaPlayer mPlayer) { - super(renderModes, width, height, mPlayer); - setColor(0.8f, 0.8f, 0.8f, 1.0f); - setPressedColorMod(1.1f, 1.1f, 1.1f, 0.7f); - setToggleOffColorMod(0.8f, 0.8f, 0.8f, 1.0f); - setToggleOnColorMod(1.0f, 1.0f, 1.0f, 1.0f); - } - - public void setVerbose(final boolean v) { verbose = v; } - - /** - * Add the default {@link GLMediaEventListener} to {@link #getGLMediaPlayer() this class's GLMediaPlayer}. - */ - public void addDefaultEventListener() { - getGLMediaPlayer().addEventListener(defGLMediaEventListener); - } - - public final GLMediaPlayer getGLMediaPlayer() { return (GLMediaPlayer)texSeq; } - - private final GLMediaEventListener defGLMediaEventListener = new GLMediaEventListener() { - @Override - public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { - // texButton.markStateDirty(); - } - - @Override - public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { - if( verbose ) { - System.err.println("MediaButton AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); - System.err.println("MediaButton State: "+mp); - } - if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { - resetGL = true; - } - if( 0 != ( GLMediaEventListener.EVENT_CHANGE_SIZE & event_mask ) ) { - // FIXME: mPlayer.resetGLState(); - } - if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { - new InterruptSource.Thread() { - @Override - public void run() { - // loop for-ever .. - mp.seek(0); - mp.resume(); - } }.start(); - } else if( 0 != ( GLMediaEventListener.EVENT_CHANGE_ERR & event_mask ) ) { - final StreamException se = mp.getStreamException(); - if( null != se ) { - se.printStackTrace(); - } - } - } }; - - - @Override - protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { - ((GLMediaPlayer)texSeq).destroy(gl); - } - - volatile boolean resetGL = true; - - @Override - public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { - final GLMediaPlayer mPlayer = (GLMediaPlayer)texSeq; - if( resetGL ) { - resetGL = false; - try { - mPlayer.initGL(gl); - if( null != region ) { - region.markShapeDirty(); // reset texture data - } - } catch (final Exception e) { - e.printStackTrace(); - } - } - super.draw(gl, renderer, sampleCount); - markStateDirty(); // keep on going - }; - -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Rectangle.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Rectangle.java deleted file mode 100644 index 4a8c29f2a..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Rectangle.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl.shapes; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.GraphShape; - -/** - * A GraphUI Rectangle {@link GraphShape} - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - */ -public class Rectangle extends GraphShape { - private float width, height, lineWidth; - - public Rectangle(final int renderModes, final float width, final float height, final float linewidth) { - super(renderModes); - this.width = width; - this.height = height; - this.lineWidth = linewidth; - } - - public final float getWidth() { return width; } - public final float getHeight() { return height; } - public final float getLineWidth() { return lineWidth; } - - public void setDimension(final float width, final float height, final float lineWidth) { - this.width = width; - this.height = height; - this.lineWidth = lineWidth; - markShapeDirty(); - } - - @Override - protected void addShapeToRegion() { - final OutlineShape shape = new OutlineShape(vertexFactory); - - final float lwh = lineWidth/2f; - - final float tw = getWidth(); - final float th = getHeight(); - - final float twh = tw/2f; - final float twh_o = twh+lwh; - final float twh_i = twh-lwh; - final float thh = th/2f; - final float thh_o = thh+lwh; - final float thh_i = thh-lwh; - - final float ctrX = 0f, ctrY = 0f; - final float ctrZ = 0f; - - // outer (CCW!) - shape.moveTo(ctrX-twh_o, ctrY-thh_o, ctrZ); - shape.lineTo(ctrX+twh_o, ctrY-thh_o, ctrZ); - shape.lineTo(ctrX+twh_o, ctrY+thh_o, ctrZ); - shape.lineTo(ctrX-twh_o, ctrY+thh_o, ctrZ); - shape.closePath(); - - // inner (CCW!) - shape.moveTo(ctrX-twh_i, ctrY-thh_i, ctrZ); - shape.lineTo(ctrX+twh_i, ctrY-thh_i, ctrZ); - shape.lineTo(ctrX+twh_i, ctrY+thh_i, ctrZ); - shape.lineTo(ctrX-twh_i, ctrY+thh_i, ctrZ); - shape.closePath(); - - shape.setIsQuadraticNurbs(); - shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, null, rgbaColor); - - box.resize(shape.getBounds()); - } - - @Override - public String getSubString() { - return super.getSubString()+", dim "+getWidth() + " x " + getHeight(); - } -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/RoundButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/RoundButton.java deleted file mode 100644 index 93ba4f0dc..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/RoundButton.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright 2010-2023 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.graph.ui.gl.shapes; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.GraphShape; - -/** - * An abstract GraphUI round Button {@link GraphShape} - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * This button is rendered with a round oval shape. - * To render it rectangular, {@link #setCorner(float)} to zero. - * </p> - */ -public abstract class RoundButton extends GraphShape { - - /** {@value} */ - public static final float DEFAULT_CORNER = 1f; - protected float width; - protected float height; - protected float corner = DEFAULT_CORNER; - - protected RoundButton(final int renderModes, final float width, final float height) { - super(renderModes); - this.width = width; - this.height = height; - } - - public final float getWidth() { return width; } - - public final float getHeight() { return height; } - - public final float getCorner() { return corner; } - - public void setSize(final float width, final float height) { - this.width = width; - this.height = height; - markShapeDirty(); - } - - protected void createSharpOutline(final OutlineShape shape, final float zOffset) { - final float tw = getWidth(); - final float th = getHeight(); - - final float minX = 0; - final float minY = 0; - final float minZ = zOffset; - - shape.addVertex(minX, minY, minZ, true); - shape.addVertex(minX+tw, minY, minZ, true); - shape.addVertex(minX+tw, minY + th, minZ, true); - shape.addVertex(minX, minY + th, minZ, true); - shape.closeLastOutline(true); - } - - protected void createCurvedOutline(final OutlineShape shape, final float zOffset) { - final float tw = getWidth(); - final float th = getHeight(); - final float dC = 0.5f*corner*Math.min(tw, th); - - final float minX = 0; - final float minY = 0; - final float minZ = zOffset; - - shape.addVertex(minX, minY + dC, minZ, true); - shape.addVertex(minX, minY, minZ, false); - - shape.addVertex(minX + dC, minY, minZ, true); - - shape.addVertex(minX + tw - dC, minY, minZ, true); - shape.addVertex(minX + tw, minY, minZ, false); - shape.addVertex(minX + tw, minY + dC, minZ, true); - shape.addVertex(minX + tw, minY + th- dC, minZ, true); - shape.addVertex(minX + tw, minY + th, minZ, false); - shape.addVertex(minX + tw - dC, minY + th, minZ, true); - shape.addVertex(minX + dC, minY + th, minZ, true); - shape.addVertex(minX, minY + th, minZ, false); - shape.addVertex(minX, minY + th - dC, minZ, true); - - shape.closeLastOutline(true); - } - - /** Set corner size, default is {@link #DEFAULT_CORNER} */ - public void setCorner(final float corner) { - if(corner > 1.0f){ - this.corner = 1.0f; - } - else if(corner < 0.01f){ - this.corner = 0.0f; - } - else{ - this.corner = corner; - } - markShapeDirty(); - } - - @Override - public String getSubString() { - return super.getSubString()+", dim "+getWidth() + " x " + getHeight() + ", corner " + corner; - } -} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/TexSeqButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/TexSeqButton.java deleted file mode 100644 index 5ee164580..000000000 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/TexSeqButton.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright 2014-2023 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.graph.ui.gl.shapes; - -import com.jogamp.opengl.GLProfile; -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.curve.opengl.GLRegion; -import com.jogamp.graph.ui.gl.GraphShape; -import com.jogamp.opengl.util.texture.TextureSequence; - -/** - * An abstract GraphUI {@link TextureSequence} {@link RoundButton} {@link GraphShape}. - * <p> - * GraphUI is GPU based and resolution independent. - * </p> - * <p> - * This button is rendered with a round oval shape. - * To render it rectangular, {@link #setCorner(float)} to zero. - * </p> - */ -public abstract class TexSeqButton extends RoundButton { - protected final TextureSequence texSeq; - - public TexSeqButton(final int renderModes, final float width, - final float height, final TextureSequence texSeq) { - super(renderModes | Region.COLORTEXTURE_RENDERING_BIT, width, height); - this.texSeq = texSeq; - } - - @Override - protected GLRegion createGLRegion(final GLProfile glp) { - return GLRegion.create(glp, getRenderModes(), texSeq); - } - - public final TextureSequence getTextureSequence() { return this.texSeq; } - - @Override - protected void addShapeToRegion() { - final OutlineShape shape = new OutlineShape(vertexFactory); - if(corner == 0.0f) { - createSharpOutline(shape, 0f); - } else { - createCurvedOutline(shape, 0f); - } - shape.setIsQuadraticNurbs(); - shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, null, rgbaColor); - box.resize(shape.getBounds()); - - setRotationPivot( box.getCenter() ); - - if( DEBUG_DRAW ) { - System.err.println("XXX.UIShape.TextureSeqButton: Added Shape: "+shape+", "+box); - } - } -} |