diff options
Diffstat (limited to 'src/demos/com')
72 files changed, 13997 insertions, 6 deletions
diff --git a/src/demos/com/jogamp/opengl/demos/Launcher0.java b/src/demos/com/jogamp/opengl/demos/Launcher0.java index 9f2e0d64e..d9d66d434 100644 --- a/src/demos/com/jogamp/opengl/demos/Launcher0.java +++ b/src/demos/com/jogamp/opengl/demos/Launcher0.java @@ -56,6 +56,7 @@ import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLPipelineFactory; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.demos.es2.RedSquareES2; +import com.jogamp.opengl.demos.util.MiscUtils; /** * <p> diff --git a/src/demos/com/jogamp/opengl/demos/android/LauncherUtil.java b/src/demos/com/jogamp/opengl/demos/android/LauncherUtil.java new file mode 100644 index 000000000..f512e467e --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/LauncherUtil.java @@ -0,0 +1,430 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +/** + * Helper class to parse Uri's and programmatically add package names and properties to create an Uri or Intend. + * <p> + * The order of the Uri segments (any arguments) is preserved. + * </p> + */ +public class LauncherUtil { + + /** Default launch mode. */ + public static final String LAUNCH_ACTIVITY_NORMAL = "org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL"; + + /** Transparent launch mode. Note: This seems to be required to achieve translucency, since setTheme(..) doesn't work. */ + public static final String LAUNCH_ACTIVITY_TRANSPARENT = "org.jogamp.launcher.action.LAUNCH_ACTIVITY_TRANSPARENT"; + + /** FIXME: TODO */ + public static final String LAUNCH_MAIN = "org.jogamp.launcher.action.LAUNCH_MAIN"; + + /** FIXME: TODO */ + public static final String LAUNCH_JUNIT = "org.jogamp.launcher.action.LAUNCH_JUNIT"; + + /** The protocol <code>launch</code> */ + public static final String SCHEME = "launch"; + + /** The host <code>jogamp.org</code> */ + public static final String HOST = "jogamp.org"; + + static final String SYS_PKG = "sys"; + + static final String USR_PKG = "pkg"; + + static final String ARG = "arg"; + + public static abstract class BaseActivityLauncher extends Activity { + final OrderedProperties props = new OrderedProperties(); + final ArrayList<String> args = new ArrayList<String>(); + /** + * Returns the default {@link LauncherUtil#LAUNCH_ACTIVITY_NORMAL} action. + * <p> + * Should be overridden for other action, eg. {@link LauncherUtil#LAUNCH_ACTIVITY_TRANSPARENT}. + * </p> + */ + public String getAction() { return LAUNCH_ACTIVITY_NORMAL; } + + /** + * Returns the properties, which are being propagated to the target activity. + * <p> + * Maybe be used to set custom properties. + * </p> + */ + public final OrderedProperties getProperties() { return props; } + + /** + * Returns the commandline arguments, which are being propagated to the target activity. + * <p> + * Maybe be used to set custom commandline arguments. + * </p> + */ + public final ArrayList<String> getArguments() { return args; } + + /** Custom initialization hook which can be overriden to setup data, e.g. fill the properties retrieved by {@link #getProperties()}. */ + public void init() { } + + /** Returns true if this launcher activity shall end after starting the downstream activity. Defaults to <code>true</code>, override to change behavior. */ + public boolean finishAfterDelegate() { return true; } + + /** Must return the downstream Activity class name */ + public abstract String getActivityName(); + + /** Must return a list of required user packages, at least one containing the activity. */ + public abstract List<String> getUsrPackages(); + + /** Return a list of required system packages w/ native libraries, may return null or a zero sized list. */ + public abstract List<String> getSysPackages(); + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + init(); + + final DataSet data = new DataSet(); + data.setActivityName(getActivityName()); + data.addAllSysPackages(getSysPackages()); + data.addAllUsrPackages(getUsrPackages()); + data.addAllProperties(props); + data.addAllArguments(args); + + final Intent intent = LauncherUtil.getIntent(getAction(), data); + Log.d(getClass().getSimpleName(), "Launching Activity: "+intent); + startActivity (intent); + + if(finishAfterDelegate()) { + finish(); // done + } + } + } + + public static class OrderedProperties { + HashMap<String, String> map = new HashMap<String, String>(); + ArrayList<String> keyList = new ArrayList<String>(); + + public final void setProperty(final String key, final String value) { + if(key.equals(SYS_PKG)) { + throw new IllegalArgumentException("Illegal property key, '"+SYS_PKG+"' is reserved"); + } + if(key.equals(USR_PKG)) { + throw new IllegalArgumentException("Illegal property key, '"+USR_PKG+"' is reserved"); + } + if(key.equals(ARG)) { + throw new IllegalArgumentException("Illegal property key, '"+ARG+"' is reserved"); + } + final String oval = map.put(key, value); + if(null != oval) { + map.put(key, oval); // restore + throw new IllegalArgumentException("Property overwriting not allowed: "+key+": "+oval+" -> "+value); + } + keyList.add(key); // new key + } + + public final void addAll(final OrderedProperties props) { + final Iterator<String> argKeys = props.keyList.iterator(); + while(argKeys.hasNext()) { + final String key = argKeys.next(); + setProperty(key, props.map.get(key)); + } + } + + public final void setSystemProperties() { + final Iterator<String> argKeys = keyList.iterator(); + while(argKeys.hasNext()) { + final String key = argKeys.next(); + System.setProperty(key, map.get(key)); + } + } + public final void clearSystemProperties() { + final Iterator<String> argKeys = keyList.iterator(); + while(argKeys.hasNext()) { + System.clearProperty(argKeys.next()); + } + } + + public final String getProperty(final String key) { return map.get(key); } + public final Map<String, String> getProperties() { return map; } + + /** Returns the list of property keys in the order, as they were added. */ + public final List<String> getPropertyKeys() { return keyList; } + } + + /** + * Data set to transfer from and to launch URI consisting out of: + * <ul> + * <li>system packages w/ native libraries used on Android, which may use a cached ClassLoader, see {@link DataSet#getSysPackages()}.</li> + * <li>user packages w/o native libraries used on Android, which do not use a cached ClassLoader, see {@link DataSet#getUsrPackages()}.</li> + * <li>activity name, used to launch an Android activity, see {@link DataSet#getActivityName()}.</li> + * <li>properties, which will be added to the system properties, see {@link DataSet#getProperties()}.</li> + * <li>arguments, used to launch a class main-entry, see {@link DataSet#getArguments()}.</li> + * </ul> + * {@link DataSet#getUri()} returns a URI representation of all components. + */ + public static class DataSet { + static final char SLASH = '/'; + static final char QMARK = '?'; + static final char AMPER = '&'; + static final char ASSIG = '='; + static final String COLSLASH2 = "://"; + static final String EMPTY = ""; + + String activityName = null; + ArrayList<String> sysPackages = new ArrayList<String>(); + ArrayList<String> usrPackages = new ArrayList<String>(); + OrderedProperties properties = new OrderedProperties(); + ArrayList<String> arguments = new ArrayList<String>(); + + public final void setActivityName(final String name) { activityName = name; } + public final String getActivityName() { return activityName; } + + public final void addSysPackage(final String p) { + sysPackages.add(p); + } + public final void addAllSysPackages(final List<String> plist) { + sysPackages.addAll(plist); + } + public final List<String> getSysPackages() { return sysPackages; } + + public final void addUsrPackage(final String p) { + usrPackages.add(p); + } + public final void addAllUsrPackages(final List<String> plist) { + usrPackages.addAll(plist); + } + public final List<String> getUsrPackages() { return usrPackages; } + + public final void setProperty(final String key, final String value) { + properties.setProperty(key, value); + } + public final void addAllProperties(final OrderedProperties props) { + properties.addAll(props); + } + public final void setSystemProperties() { + properties.setSystemProperties(); + } + public final void clearSystemProperties() { + properties.clearSystemProperties(); + } + public final String getProperty(final String key) { return properties.getProperty(key); } + public final OrderedProperties getProperties() { return properties; } + public final List<String> getPropertyKeys() { return properties.getPropertyKeys(); } + + public final void addArgument(final String arg) { arguments.add(arg); } + public final void addAllArguments(final List<String> args) { + arguments.addAll(args); + } + public final ArrayList<String> getArguments() { return arguments; } + + public final Uri getUri() { + final StringBuilder sb = new StringBuilder(); + sb.append(SCHEME).append(COLSLASH2).append(HOST).append(SLASH).append(getActivityName()); + boolean needsQMark = true; + boolean needsSep = false; + if(sysPackages.size()>0) { + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + for(int i=0; i<sysPackages.size(); i++) { + if(needsSep) { + sb.append(AMPER); + } + sb.append(SYS_PKG).append(ASSIG).append(sysPackages.get(i)); + needsSep = true; + } + } + if(usrPackages.size()>0) { + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + for(int i=0; i<usrPackages.size(); i++) { + if(needsSep) { + sb.append(AMPER); + } + sb.append(USR_PKG).append(ASSIG).append(usrPackages.get(i)); + needsSep = true; + } + } + final Iterator<String> propKeys = properties.keyList.iterator(); + while(propKeys.hasNext()) { + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + if(needsSep) { + sb.append(AMPER); + } + final String key = propKeys.next(); + sb.append(key).append(ASSIG).append(properties.map.get(key)); + needsSep = true; + } + final Iterator<String> args = arguments.iterator(); + while(args.hasNext()) { + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + if(needsSep) { + sb.append(AMPER); + } + sb.append(ARG).append(ASSIG).append(args.next()); + needsSep = true; + } + return Uri.parse(sb.toString()); + } + + public static final DataSet create(final Uri uri) { + if(!uri.getScheme().equals(SCHEME)) { + return null; + } + if(!uri.getHost().equals(HOST)) { + return null; + } + final DataSet data = new DataSet(); + { + String an = uri.getPath(); + if(SLASH == an.charAt(0)) { + an = an.substring(1); + } + if(SLASH == an.charAt(an.length()-1)) { + an = an.substring(0, an.length()-1); + } + data.setActivityName(an); + } + + final String q = uri.getQuery(); + final int q_l = null != q ? q.length() : -1; + int q_e = -1; + while(q_e < q_l) { + final int q_b = q_e + 1; // next term + q_e = q.indexOf(AMPER, q_b); + if(0 == q_e) { + // single separator + continue; + } + if(0 > q_e) { + // end + q_e = q_l; + } + // n-part + final String part = q.substring(q_b, q_e); + final int assignment = part.indexOf(ASSIG); + if(0 < assignment) { + // assignment + final String k = part.substring(0, assignment); + final String v = part.substring(assignment+1); + if(k.equals(SYS_PKG)) { + if(v.length()==0) { + throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri); + } + data.addSysPackage(v); + } else if(k.equals(USR_PKG)) { + if(v.length()==0) { + throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri); + } + data.addUsrPackage(v); + } else if(k.equals(ARG)) { + if(v.length()==0) { + throw new IllegalArgumentException("Empty argument name: part <"+part+">, query <"+q+"> of "+uri); + } + data.addArgument(v); + } else { + data.setProperty(k, v); + } + } else { + // property key only + if( part.equals(USR_PKG) || part.equals(ARG) ) { + throw new IllegalArgumentException("Reserved key <"+part+"> in query <"+q+"> of "+uri); + } + data.setProperty(part, EMPTY); + } + } + data.validate(); + return data; + } + + public final void validate() { + if(null == activityName) { + throw new RuntimeException("Activity is not NULL"); + } + } + } + + public final static Intent getIntent(final String action, final DataSet data) { + data.validate(); + return new Intent(action, data.getUri()); + } + + public static void main(String[] args) { + if(args.length==0) { + args = new String[] { + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+SYS_PKG+"=jogamp.pack1&"+SYS_PKG+"=javax.pack2&"+USR_PKG+"=com.jogamp.pack3&"+USR_PKG+"=com.jogamp.pack4&jogamp.common.debug=true&com.jogamp.test=false", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+SYS_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+USR_PKG+"=com.jogamp.pack2", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+USR_PKG+"=javax.pack2&"+USR_PKG+"=com.jogamp.pack3&jogamp.common.debug=true&com.jogamp.test=false&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3" + }; + } + int errors = 0; + for(int i=0; i<args.length; i++) { + final String uri_s = args[i]; + final Uri uri0 = Uri.parse(uri_s); + final DataSet data = DataSet.create(uri0); + if(null == data) { + errors++; + System.err.println("Error: NULL JogAmpLauncherUtil: <"+uri_s+"> -> "+uri0+" -> NULL"); + } else { + final Uri uri1 = data.getUri(); + if(!uri0.equals(uri1)) { + errors++; + System.err.println("Error: Not equal: <"+uri_s+"> -> "+uri0+" -> "+uri1); + } else { + System.err.println("OK: "+uri1); + } + } + } + System.err.println("LauncherUtil Self Test: Errors: "+errors); + } + +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0a.java b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0a.java new file mode 100644 index 000000000..cdbaa7872 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0a.java @@ -0,0 +1,166 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.net.URLConnection; +import java.util.Arrays; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.av.MovieCube; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.common.net.Uri; +import com.jogamp.common.util.IOUtil; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; +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; + +import android.os.Bundle; +import android.util.Log; + +public class MovieCubeActivity0a extends NewtBaseActivity { + static String TAG = "MovieCubeActivity0a"; + + MouseAdapter showKeyboardMouseListener = new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + if( e.getPointerCount() == 4 && e.getPressure(0, true) > 0.7f ) { + ((com.jogamp.newt.Window) e.getSource()).setKeyboardVisible(true); + } + } + }; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final String[] streamLocs = new String[] { + System.getProperty("jnlp.media0_url0"), + System.getProperty("jnlp.media0_url1"), + System.getProperty("jnlp.media0_url2") }; + final Uri streamLoc = getUri(streamLocs, 0, false); + if(null == streamLoc) { throw new RuntimeException("no media reachable: "+Arrays.asList(streamLocs)); } + + // also initializes JOGL + final GLCapabilities capsMain = new GLCapabilities(GLProfile.getGL2ES2()); + capsMain.setBackgroundOpaque(false); + + // screen for layout params .. + final com.jogamp.newt.Display dpy = NewtFactory.createDisplay(null); + final com.jogamp.newt.Screen scrn = NewtFactory.createScreen(dpy, 0); + scrn.addReference(); + + try { + final Animator anim = new Animator(); + + // Main + final GLWindow glWindowMain = GLWindow.create(scrn, capsMain); + glWindowMain.setFullscreen(true); + setContentView(getWindow(), glWindowMain); + anim.add(glWindowMain); + glWindowMain.setVisible(true); + glWindowMain.addMouseListener(showKeyboardMouseListener); + + final MovieCube demoMain = new MovieCube(MovieCube.zoom_def, 0f, 0f, false); + final GLMediaPlayer mPlayer = demoMain.getGLMediaPlayer(); + mPlayer.addEventListener(new GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { + } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieCubeActivity0 AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieCubeActivity0 State: "+mp); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + glWindowMain.addGLEventListener(demoMain); + anim.setUpdateFPSFrames(60*5, null); + anim.resetFPSCounter(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_PLAY & event_mask ) ) { + anim.resetFPSCounter(); + } + if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) { + final StreamException se = mPlayer.getStreamException(); + if( null != se ) { + se.printStackTrace(); + } + getActivity().finish(); + } + } + }); + demoMain.initStream(streamLoc, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 0); + } catch (final IOException e) { + e.printStackTrace(); + } + + scrn.removeReference(); + + Log.d(TAG, "onCreate - X"); + } + + static Uri getUri(final String path[], final int off, final boolean checkAvail) { + Uri uri = null; + for(int i=off; null==uri && i<path.length; i++) { + if(null != path[i] && path[i].length()>0) { + if( checkAvail ) { + final URLConnection uc = IOUtil.getResource(path[i], null); + if( null != uc ) { + try { + uri = Uri.valueOf(uc.getURL()); + } catch (final URISyntaxException e) { + uri = null; + } + if( uc instanceof HttpURLConnection ) { + ((HttpURLConnection)uc).disconnect(); + } + } + } else { + try { + uri = Uri.cast(path[i]); + } catch (final URISyntaxException e) { + uri = null; + } + } + Log.d(TAG, "Stream: <"+path[i]+">: "+(null!=uri)); + } + } + return uri; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0b.java b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0b.java new file mode 100644 index 000000000..b04487b5f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0b.java @@ -0,0 +1,168 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.net.URLConnection; +import java.util.Arrays; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.av.MovieCube; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.common.net.Uri; +import com.jogamp.common.util.IOUtil; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; +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; + +import android.os.Bundle; +import android.util.Log; + +public class MovieCubeActivity0b extends NewtBaseActivity { + static String TAG = "MovieCubeActivity0a"; + + MouseAdapter showKeyboardMouseListener = new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + if( e.getPointerCount() == 4 && e.getPressure(0, true) > 0.7f ) { + ((com.jogamp.newt.Window) e.getSource()).setKeyboardVisible(true); + } + } + }; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final String[] streamLocs = new String[] { + System.getProperty("jnlp.media0_url0"), + System.getProperty("jnlp.media0_url1"), + System.getProperty("jnlp.media0_url2") }; + final Uri streamLoc = getUri(streamLocs, 0, false); + if(null == streamLoc) { throw new RuntimeException("no media reachable: "+Arrays.asList(streamLocs)); } + + // also initializes JOGL + final GLCapabilities capsMain = new GLCapabilities(GLProfile.getGL2ES2()); + capsMain.setNumSamples(4); + capsMain.setSampleBuffers(true); + capsMain.setBackgroundOpaque(false); + + // screen for layout params .. + final com.jogamp.newt.Display dpy = NewtFactory.createDisplay(null); + final com.jogamp.newt.Screen scrn = NewtFactory.createScreen(dpy, 0); + scrn.addReference(); + + try { + final Animator anim = new Animator(); + + // Main + final GLWindow glWindowMain = GLWindow.create(scrn, capsMain); + glWindowMain.setFullscreen(true); + setContentView(getWindow(), glWindowMain); + anim.add(glWindowMain); + glWindowMain.setVisible(true); + glWindowMain.addMouseListener(showKeyboardMouseListener); + + final MovieCube demoMain = new MovieCube(MovieCube.zoom_def, 0f, 0f, true); + final GLMediaPlayer mPlayer = demoMain.getGLMediaPlayer(); + mPlayer.addEventListener(new GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { + } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieCubeActivity0 AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieCubeActivity0 State: "+mp); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + glWindowMain.addGLEventListener(demoMain); + anim.setUpdateFPSFrames(60*5, null); + anim.resetFPSCounter(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_PLAY & event_mask ) ) { + anim.resetFPSCounter(); + } + if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) { + final StreamException se = mPlayer.getStreamException(); + if( null != se ) { + se.printStackTrace(); + } + getActivity().finish(); + } + } + }); + demoMain.initStream(streamLoc, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 0); + } catch (final IOException e) { + e.printStackTrace(); + } + + scrn.removeReference(); + + Log.d(TAG, "onCreate - X"); + } + + static Uri getUri(final String path[], final int off, final boolean checkAvail) { + Uri uri = null; + for(int i=off; null==uri && i<path.length; i++) { + if(null != path[i] && path[i].length()>0) { + if( checkAvail ) { + final URLConnection uc = IOUtil.getResource(path[i], null); + if( null != uc ) { + try { + uri = Uri.valueOf(uc.getURL()); + } catch (final URISyntaxException e) { + uri = null; + } + if( uc instanceof HttpURLConnection ) { + ((HttpURLConnection)uc).disconnect(); + } + } + } else { + try { + uri = Uri.cast(path[i]); + } catch (final URISyntaxException e) { + uri = null; + } + } + Log.d(TAG, "Stream: <"+path[i]+">: "+(null!=uri)); + } + } + return uri; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0a.java b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0a.java new file mode 100644 index 000000000..4c9409b02 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0a.java @@ -0,0 +1,87 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieCubeActivityLauncher0a extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieCubeActivity0a"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.media0_url0", "http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + props.setProperty("jnlp.media1_url1", "http://archive.org/download/ElephantsDream/ed_1024_512kb.mp4"); + props.setProperty("jnlp.media0_url2", "file:///mnt/sdcard/Movies/BigBuckBunny_320x180.mp4"); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("jogamp.debug.Lock", "true"); + // props.setProperty("jogamp.debug.Lock.TraceLock", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + // props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0b.java b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0b.java new file mode 100644 index 000000000..548c0bc51 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0b.java @@ -0,0 +1,87 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieCubeActivityLauncher0b extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieCubeActivity0b"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.media0_url0", "http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + props.setProperty("jnlp.media1_url1", "http://archive.org/download/ElephantsDream/ed_1024_512kb.mp4"); + props.setProperty("jnlp.media0_url2", "file:///mnt/sdcard/Movies/BigBuckBunny_320x180.mp4"); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("jogamp.debug.Lock", "true"); + // props.setProperty("jogamp.debug.Lock.TraceLock", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + // props.setProperty("jogl.debug.GLContext", "true"); + // props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1a.java b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1a.java new file mode 100644 index 000000000..d4133df18 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1a.java @@ -0,0 +1,87 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieCubeActivityLauncher1a extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieCubeActivity0a"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.media0_url0", "camera:/0"); + props.setProperty("jnlp.media0_url1", ""); + props.setProperty("jnlp.media1_url2", ""); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("jogamp.debug.Lock", "true"); + // props.setProperty("jogamp.debug.Lock.TraceLock", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + // props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1b.java b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1b.java new file mode 100644 index 000000000..21749ef74 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1b.java @@ -0,0 +1,87 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieCubeActivityLauncher1b extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieCubeActivity0b"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.media0_url0", "camera:/1"); + props.setProperty("jnlp.media0_url1", ""); + props.setProperty("jnlp.media1_url2", ""); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("jogamp.debug.Lock", "true"); + // props.setProperty("jogamp.debug.Lock.TraceLock", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + // props.setProperty("jogl.debug.GLContext", "true"); + // props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity0.java b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity0.java new file mode 100644 index 000000000..07d0b9914 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity0.java @@ -0,0 +1,159 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.net.URLConnection; +import java.util.Arrays; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.av.MovieSimple; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.common.net.Uri; +import com.jogamp.common.util.IOUtil; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; +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; + +import android.os.Bundle; +import android.util.Log; + +public class MovieSimpleActivity0 extends NewtBaseActivity { + static String TAG = "MovieSimpleActivity0"; + + MouseAdapter toFrontMouseListener = new MouseAdapter() { + public void mouseClicked(final MouseEvent e) { + final Object src = e.getSource(); + if(src instanceof Window) { + ((Window)src).requestFocus(false); + } + } }; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final String[] streamLocs = new String[] { + System.getProperty("jnlp.media0_url0"), + System.getProperty("jnlp.media0_url1"), + System.getProperty("jnlp.media0_url2") }; + final Uri streamLoc = getUri(streamLocs, 0, false); + if(null == streamLoc) { throw new RuntimeException("no media reachable: "+Arrays.asList(streamLocs)); } + + // also initializes JOGL + final GLCapabilities capsMain = new GLCapabilities(GLProfile.getGL2ES2()); + capsMain.setNumSamples(4); + capsMain.setSampleBuffers(true); + capsMain.setBackgroundOpaque(false); + + // screen for layout params .. + final com.jogamp.newt.Display dpy = NewtFactory.createDisplay(null); + final com.jogamp.newt.Screen scrn = NewtFactory.createScreen(dpy, 0); + scrn.addReference(); + + final Animator anim = new Animator(); + + // Main + final GLWindow glWindowMain = GLWindow.create(scrn, capsMain); + glWindowMain.setFullscreen(true); + setContentView(getWindow(), glWindowMain); + anim.add(glWindowMain); + glWindowMain.setVisible(true); + + final MovieSimple demoMain = new MovieSimple(null); + demoMain.setScaleOrig(true); + final GLMediaPlayer mPlayer = demoMain.getGLMediaPlayer(); + mPlayer.addEventListener( new GLMediaPlayer.GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieSimpleActivity0 AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieSimpleActivity0 State: "+mp); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + glWindowMain.addGLEventListener(demoMain); + anim.setUpdateFPSFrames(60*5, System.err); + anim.resetFPSCounter(); + } + if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) { + final StreamException se = mPlayer.getStreamException(); + if( null != se ) { + se.printStackTrace(); + } + getActivity().finish(); + } + } + }); + demoMain.initStream(streamLoc, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 0); + + scrn.removeReference(); + + Log.d(TAG, "onCreate - X"); + } + + static Uri getUri(final String path[], final int off, final boolean checkAvail) { + Uri uri = null; + for(int i=off; null==uri && i<path.length; i++) { + if(null != path[i] && path[i].length()>0) { + if( checkAvail ) { + final URLConnection uc = IOUtil.getResource(path[i], null); + if( null != uc ) { + try { + uri = Uri.valueOf(uc.getURL()); + } catch (final URISyntaxException e) { + uri = null; + } + if( uc instanceof HttpURLConnection ) { + ((HttpURLConnection)uc).disconnect(); + } + } + } else { + try { + uri = Uri.cast(path[i]); + } catch (final URISyntaxException e) { + uri = null; + } + } + Log.d(TAG, "Stream: <"+path[i]+">: "+(null!=uri)); + } + } + return uri; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity1.java b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity1.java new file mode 100644 index 000000000..d7a2aeae1 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity1.java @@ -0,0 +1,262 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.net.URLConnection; +import java.util.Arrays; + +import com.jogamp.nativewindow.util.Rectangle; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.demos.av.MovieSimple; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.common.net.Uri; +import com.jogamp.common.util.IOUtil; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; +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; + +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; + +public class MovieSimpleActivity1 extends NewtBaseActivity { + static String TAG = "MovieSimpleActivity1"; + + MouseAdapter toFrontMouseListener = new MouseAdapter() { + public void mouseClicked(final MouseEvent e) { + final Object src = e.getSource(); + if(src instanceof Window) { + ((Window)src).requestFocus(false); + } + } }; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final boolean mPlayerNoZoom = Boolean.valueOf(System.getProperty("jnlp.mplayer.nozoom")); + final boolean mPlayerHUD = Boolean.valueOf(System.getProperty("jnlp.mplayer.hud")); + final boolean mPlayerSharedHUD = mPlayerHUD && Boolean.valueOf(System.getProperty("jnlp.mplayer.hud.shared")); + Log.d(TAG, "onCreate - 0 - mPlayerNoScale "+mPlayerNoZoom+", mPlayerHUD "+mPlayerHUD+", mPlayerSharedHUD "+mPlayerSharedHUD); + + final String[] streamLocs = new String[] { + System.getProperty("jnlp.media0_url0"), + System.getProperty("jnlp.media0_url1"), + System.getProperty("jnlp.media0_url2") }; + final Uri streamLoc0 = getUri(streamLocs, 2, false); + if(null == streamLoc0) { throw new RuntimeException("no media reachable: "+Arrays.asList(streamLocs)); } + + final Uri streamLoc1; + { + Uri _streamLoc1 = null; + if(mPlayerHUD && !mPlayerSharedHUD) { + final String[] urls1 = new String[] { System.getProperty("jnlp.media1_url0") }; + _streamLoc1 = getUri(urls1, 1, false); + } + if(null == _streamLoc1) { _streamLoc1 = streamLoc0; } + streamLoc1 = _streamLoc1; + } + + setTransparencyTheme(); + setFullscreenFeature(getWindow(), true); + + final android.view.ViewGroup viewGroup = new android.widget.FrameLayout(getActivity().getApplicationContext()); + getWindow().setContentView(viewGroup); + + // also initializes JOGL + final GLCapabilities capsMain = new GLCapabilities(GLProfile.getGL2ES2()); + capsMain.setNumSamples(4); + capsMain.setSampleBuffers(true); + capsMain.setBackgroundOpaque(!mPlayerHUD); + + // screen for layout params .. + final com.jogamp.newt.Display dpy = NewtFactory.createDisplay(null); + final com.jogamp.newt.Screen scrn = NewtFactory.createScreen(dpy, 0); + scrn.addReference(); + + final Animator anim = new Animator(); + + // Main + final GLWindow glWindowMain = GLWindow.create(scrn, capsMain); + { + final int padding = mPlayerHUD ? 32 : 0; + final android.view.View androidView = ((jogamp.newt.driver.android.WindowDriver)glWindowMain.getDelegatedWindow()).getAndroidView(); + glWindowMain.setSurfaceSize(scrn.getWidth()-padding, scrn.getHeight()-padding); + glWindowMain.setUndecorated(true); + // setContentView(getWindow(), glWindowMain); + viewGroup.addView(androidView, new android.widget.FrameLayout.LayoutParams(glWindowMain.getSurfaceWidth(), glWindowMain.getSurfaceHeight(), Gravity.BOTTOM|Gravity.RIGHT)); + registerNEWTWindow(glWindowMain); + } + anim.add(glWindowMain); + glWindowMain.setVisible(true); + + final MovieSimple demoMain = new MovieSimple(null); + final GLMediaPlayer mPlayerMain = demoMain.getGLMediaPlayer(); + if(mPlayerHUD) { + demoMain.setEffects(MovieSimple.EFFECT_GRADIENT_BOTTOM2TOP); + demoMain.setTransparency(0.9f); + } + demoMain.setScaleOrig(mPlayerNoZoom); + mPlayerMain.addEventListener( new GLMediaPlayer.GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieSimpleActivity1 AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieSimpleActivity1 State: "+mp); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + glWindowMain.addGLEventListener(demoMain); + anim.setUpdateFPSFrames(60*5, System.err); + anim.resetFPSCounter(); + } + if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) { + final StreamException se = mPlayerMain.getStreamException(); + if( null != se ) { + se.printStackTrace(); + } + getActivity().finish(); + } + } + }); + demoMain.initStream(streamLoc0, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 0); + + if(mPlayerHUD) { + final GLMediaPlayer mPlayerShared = mPlayerSharedHUD ? mPlayerMain : null; + final GLCapabilities capsHUD = new GLCapabilities(GLProfile.getGL2ES2()); + capsHUD.setNumSamples(4); + capsHUD.setSampleBuffers(true); + capsHUD.setBackgroundOpaque(false); + final GLWindow glWindowHUD = GLWindow.create(scrn, capsHUD); + glWindowMain.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + final GLMediaPlayer mPlayerSub; + final MovieSimple demoHUD; + final Rectangle windowBounds = (Rectangle) scrn.getViewportInWindowUnits().cloneMutable(); + if(null != mPlayerShared) { + if(0 < mPlayerShared.getWidth() && mPlayerShared.getWidth()<scrn.getWidth()/2 && + 0 < mPlayerShared.getHeight() && mPlayerShared.getHeight()<scrn.getHeight()/2) { + final int[] wh = glWindowHUD.convertToWindowUnits(new int[]{mPlayerShared.getWidth(), mPlayerShared.getHeight()}); + windowBounds.setWidth( wh[0] ); + windowBounds.setHeight( wh[1] ); + } + glWindowHUD.setSharedAutoDrawable(glWindowMain); + demoHUD = new MovieSimple(mPlayerShared); + mPlayerSub = mPlayerShared; + } else { + demoHUD = new MovieSimple(null); + mPlayerSub = demoHUD.getGLMediaPlayer(); + } + mPlayerSub.addEventListener( new GLMediaPlayer.GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + glWindowHUD.addGLEventListener(demoHUD); + } + if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) { + final StreamException se = mPlayerMain.getStreamException(); + if( null != se ) { + se.printStackTrace(); + } + getActivity().finish(); + } + } + }); + demoHUD.initStream(streamLoc1, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 0); + + glWindowHUD.setPosition(windowBounds.getX(), windowBounds.getY()); + glWindowHUD.setSize(windowBounds.getWidth(), windowBounds.getHeight()); + System.err.println("HUD: "+mPlayerHUD); + System.err.println("HUD: "+windowBounds); + glWindowHUD.addMouseListener(toFrontMouseListener); + + viewGroup.post(new Runnable() { + public void run() { + final android.view.View androidView = ((jogamp.newt.driver.android.WindowDriver)glWindowHUD.getDelegatedWindow()).getAndroidView(); + // addContentView(getWindow(), glWindowHUD, new android.view.ViewGroup.LayoutParams(glWindowHUD.getWidth(), glWindowHUD.getHeight())); + viewGroup.addView(androidView, new android.widget.FrameLayout.LayoutParams(glWindowHUD.getSurfaceWidth(), glWindowHUD.getSurfaceHeight(), Gravity.TOP|Gravity.LEFT)); + registerNEWTWindow(glWindowHUD); + anim.add(glWindowHUD); + glWindowHUD.setVisible(true); + } } ); + return true; + } } ); + } + + scrn.removeReference(); + + Log.d(TAG, "onCreate - X"); + } + + static Uri getUri(final String path[], final int off, final boolean checkAvail) { + Uri uri = null; + for(int i=off; null==uri && i<path.length; i++) { + if(null != path[i] && path[i].length()>0) { + if( checkAvail ) { + final URLConnection uc = IOUtil.getResource(path[i], null); + if( null != uc ) { + try { + uri = Uri.valueOf(uc.getURL()); + } catch (final URISyntaxException e) { + uri = null; + } + if( uc instanceof HttpURLConnection ) { + ((HttpURLConnection)uc).disconnect(); + } + } + } else { + try { + uri = Uri.cast(path[i]); + } catch (final URISyntaxException e) { + uri = null; + } + } + Log.d(TAG, "Stream: <"+path[i]+">: "+(null!=uri)); + } + } + return uri; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00b.java b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00b.java new file mode 100644 index 000000000..bfcf3dd06 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00b.java @@ -0,0 +1,84 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieSimpleActivityLauncher00b extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieSimpleActivity0"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.media0_url0", "http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + props.setProperty("jnlp.media0_url1", "http://video.webmfiles.org/big-buck-bunny_trailer.webm"); + props.setProperty("jnlp.media0_url2", "file:///mnt/sdcard/Movies/BigBuckBunny_320x180.mp4"); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00c.java b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00c.java new file mode 100644 index 000000000..947e848c5 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00c.java @@ -0,0 +1,84 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieSimpleActivityLauncher00c extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieSimpleActivity0"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.media0_url0", "camera:/0"); + props.setProperty("jnlp.media0_url1", ""); + props.setProperty("jnlp.media0_url2", ""); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01a.java b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01a.java new file mode 100644 index 000000000..bf9114f4f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01a.java @@ -0,0 +1,87 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieSimpleActivityLauncher01a extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieSimpleActivity1"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.mplayer.nozoom", "true"); + props.setProperty("jnlp.mplayer.hud", "true"); + props.setProperty("jnlp.mplayer.hud.shared", "true"); + props.setProperty("jnlp.media0_url0", "http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + props.setProperty("jnlp.media1_url1", "http://archive.org/download/ElephantsDream/ed_1024_512kb.mp4"); + props.setProperty("jnlp.media0_url2", "file:///mnt/sdcard/Movies/BigBuckBunny_320x180.mp4"); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + // props.setProperty("jogl.debug.GLContext", "true"); + // props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01b.java b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01b.java new file mode 100644 index 000000000..35330b86b --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01b.java @@ -0,0 +1,87 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieSimpleActivityLauncher01b extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieSimpleActivity1"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.mplayer.nozoom", "false"); + props.setProperty("jnlp.mplayer.hud", "true"); + props.setProperty("jnlp.mplayer.hud.shared", "true"); + props.setProperty("jnlp.media0_url0", "http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + props.setProperty("jnlp.media1_url1", "http://archive.org/download/ElephantsDream/ed_1024_512kb.mp4"); + props.setProperty("jnlp.media0_url2", "file:///mnt/sdcard/Movies/BigBuckBunny_320x180.mp4"); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + // props.setProperty("jogl.debug.GLContext", "true"); + // props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher02.java b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher02.java new file mode 100644 index 000000000..d7c064a28 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher02.java @@ -0,0 +1,87 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class MovieSimpleActivityLauncher02 extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.MovieSimpleActivity1"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + props.setProperty("jnlp.mplayer.nozoom", "false"); + props.setProperty("jnlp.mplayer.hud", "true"); + props.setProperty("jnlp.mplayer.hud.shared", "false"); + props.setProperty("jnlp.media0_url0", "http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + props.setProperty("jnlp.media1_url1", "http://archive.org/download/ElephantsDream/ed_1024_512kb.mp4"); + props.setProperty("jnlp.media0_url2", "file:///mnt/sdcard/Movies/BigBuckBunny_320x180.mp4"); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("nativewindow.debug", "all"); + // props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + // props.setProperty("jogl.debug.GLContext", "true"); + // props.setProperty("jogl.debug.GLMediaPlayer", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + // props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2Activity.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2Activity.java new file mode 100644 index 000000000..8ab927487 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2Activity.java @@ -0,0 +1,134 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.util.ArrayList; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.es2.GearsES2; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.common.util.InterruptSource; +import com.jogamp.newt.event.MonitorEvent; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MonitorModeListener; +import com.jogamp.newt.opengl.GLWindow; + +import com.jogamp.opengl.util.Animator; + +import android.os.Bundle; +import android.util.Log; + +public class NEWTGearsES2Activity extends NewtBaseActivity { + static String TAG = "NEWTGearsES2Activity"; + + static final String forceRGBA5650 = "demo.force.rgba5650"; + static final String forceECT = "demo.force.ect"; + static final String forceKillProcessTest = "demo.force.killProcessTest"; + + @Override + public void onCreate(final Bundle savedInstanceState) { + Log.d(TAG, "onCreate - 0"); + super.onCreate(savedInstanceState); + + // create GLWindow (-> incl. underlying NEWT Display, Screen & Window) + final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2)); + if( null != System.getProperty(forceRGBA5650) ) { + Log.d(TAG, "forceRGBA5650"); + caps.setRedBits(5); caps.setGreenBits(6); caps.setBlueBits(5); + } + + Log.d(TAG, "req caps: "+caps); + final GLWindow glWindow = GLWindow.create(caps); + glWindow.setFullscreen(true); + setContentView(getWindow(), glWindow); + + final GearsES2 demo = new GearsES2(-1); + // demo.enableAndroidTrace(true); + glWindow.addGLEventListener(demo); + glWindow.getScreen().addMonitorModeListener(new MonitorModeListener() { + @Override + public void monitorModeChangeNotify(final MonitorEvent me) { } + @Override + public void monitorModeChanged(final MonitorEvent me, final boolean success) { + System.err.println("MonitorMode Changed (success "+success+"): "+me); + } + }); + if( null != System.getProperty(forceKillProcessTest) ) { + Log.d(TAG, "forceKillProcessTest"); + glWindow.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + if( e.getPointerCount() == 3 ) { + Log.d(TAG, "MemoryHog"); + new InterruptSource.Thread(null, new Runnable() { + @Override + public void run() { + final ArrayList<Buffer> buffers = new ArrayList<Buffer>(); + while(true) { + final int halfMB = 512 * 1024; + final float osizeMB = buffers.size() * 0.5f; + final float nsizeMB = osizeMB + 0.5f; + System.err.println("MemoryHog: ****** +4k: "+osizeMB+" MB +"+nsizeMB+" MB - Try"); + buffers.add(ByteBuffer.allocateDirect(halfMB)); // 0.5 MB each + System.err.println("MemoryHog: ****** +4k: "+osizeMB+" MB +"+nsizeMB+" MB - Done"); + try { + Thread.sleep(500); + } catch (final Exception e) { e.printStackTrace(); }; + } + } }, "MemoryHog").start(); + } else if( e.getPointerCount() == 4 ) { + Log.d(TAG, "ForceKill"); + android.os.Process.killProcess( android.os.Process.myPid() ); + } + } + }); + } + final Animator animator = new Animator(glWindow); + // animator.setRunAsFastAsPossible(true); + // glWindow.setSkipContextReleaseThread(animator.getThread()); + + if( null != System.getProperty(forceECT) ) { + Log.d(TAG, "forceECT"); + animator.setExclusiveContext(true); + } + + glWindow.setVisible(true); + + animator.setUpdateFPSFrames(60, System.err); + animator.resetFPSCounter(); + glWindow.resetFPSCounter(); + + Log.d(TAG, "onCreate - X"); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ActivityLauncher.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ActivityLauncher.java new file mode 100644 index 000000000..a945baeab --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ActivityLauncher.java @@ -0,0 +1,84 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class NEWTGearsES2ActivityLauncher extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.NEWTGearsES2Activity"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // properties.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("nativewindow.debug", "all"); + props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // properties.setProperty("jogl.debug.GLProfile", "true"); + props.setProperty("jogl.debug.EGLDisplayUtil", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + props.setProperty("newt.debug.Screen", "true"); + props.setProperty("newt.debug.Window", "true"); + props.setProperty("newt.debug.Window.MouseEvent", "true"); + props.setProperty("newt.debug.Window.KeyEvent", "true"); + // props.setProperty("newt.debug.Android.MouseEvent", "true"); + + // props.setProperty("demo.force.killProcessTest", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ECTActivityLauncher.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ECTActivityLauncher.java new file mode 100644 index 000000000..b627c6638 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ECTActivityLauncher.java @@ -0,0 +1,80 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class NEWTGearsES2ECTActivityLauncher extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.NEWTGearsES2Activity"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // properties.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("nativewindow.debug", "all"); + props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // properties.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + props.setProperty("newt.debug.Window", "true"); + props.setProperty("newt.debug.Window.MouseEvent", "true"); + props.setProperty("newt.debug.Window.KeyEvent", "true"); + + props.setProperty("demo.force.ect", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2RGB565ActivityLauncher.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2RGB565ActivityLauncher.java new file mode 100644 index 000000000..5ab877b35 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2RGB565ActivityLauncher.java @@ -0,0 +1,80 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class NEWTGearsES2RGB565ActivityLauncher extends LauncherUtil.BaseActivityLauncher { + + static String demo = "com.jogamp.opengl.test.android.NEWTGearsES2Activity"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // properties.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("nativewindow.debug", "all"); + props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // properties.setProperty("jogl.debug.GLProfile", "true"); + // props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + props.setProperty("newt.debug.Window", "true"); + props.setProperty("newt.debug.Window.MouseEvent", "true"); + props.setProperty("newt.debug.Window.KeyEvent", "true"); + + props.setProperty("demo.force.rgba5650", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivity.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivity.java new file mode 100644 index 000000000..8d945aad0 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivity.java @@ -0,0 +1,88 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.es2.GearsES2; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; +import com.jogamp.newt.event.MonitorEvent; +import com.jogamp.newt.event.MonitorModeListener; +import com.jogamp.newt.opengl.GLWindow; + +import com.jogamp.opengl.util.Animator; + +import android.os.Bundle; +import android.util.Log; + +public class NEWTGearsES2TransActivity extends NewtBaseActivity { + static String TAG = "NEWTGearsES2TransActivity"; + + @Override + public void onCreate(final Bundle savedInstanceState) { + Log.d(TAG, "onCreate - 0"); + super.onCreate(savedInstanceState); + + // create GLWindow (-> incl. underlying NEWT Display, Screen & Window) + final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2)); + caps.setBackgroundOpaque(false); + + Log.d(TAG, "req caps: "+caps); + final Screen screen = NewtFactory.createScreen(NewtFactory.createDisplay(null), 0); + screen.addReference(); + final GLWindow glWindow = GLWindow.create(screen, caps); + glWindow.setSurfaceSize(2*screen.getWidth()/3, 2*screen.getHeight()/3); + glWindow.setUndecorated(true); + setContentView(getWindow(), glWindow); + + glWindow.addGLEventListener(new GearsES2(-1)); + glWindow.getScreen().addMonitorModeListener(new MonitorModeListener() { + @Override + public void monitorModeChangeNotify(final MonitorEvent me) { } + @Override + public void monitorModeChanged(final MonitorEvent me, final boolean success) { + System.err.println("MonitorMode Changed (success "+success+"): "+me); + } + }); + final Animator animator = new Animator(glWindow); + // glWindow.setSkipContextReleaseThread(animator.getThread()); + + glWindow.setVisible(true); + + animator.setUpdateFPSFrames(60, System.err); + animator.resetFPSCounter(); + glWindow.resetFPSCounter(); + + screen.removeReference(); + Log.d(TAG, "onCreate - X"); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivityLauncher.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivityLauncher.java new file mode 100644 index 000000000..7a44a495b --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivityLauncher.java @@ -0,0 +1,58 @@ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class NEWTGearsES2TransActivityLauncher extends LauncherUtil.BaseActivityLauncher { + static String demo = "com.jogamp.opengl.test.android.NEWTGearsES2TransActivity"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + // props.setProperty("jnlp.android.translucent", "true"); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // properties.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // properties.setProperty("jogamp.debug.IOUtil", "true"); + // properties.setProperty("nativewindow.debug", "all"); + props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // properties.setProperty("jogl.debug", "all"); + // properties.setProperty("jogl.debug.GLProfile", "true"); + props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // properties.setProperty("jogl.debug.GLSLState", "true"); + // properties.setProperty("jogl.debug.DebugGL", "true"); + // properties.setProperty("jogl.debug.TraceGL", "true"); + // properties.setProperty("newt.debug", "all"); + props.setProperty("newt.debug.Window", "true"); + // properties.setProperty("newt.debug.Window.MouseEvent", "true"); + // properties.setProperty("newt.debug.Window.KeyEvent", "true"); + props.setProperty("jogamp.debug.IOUtil", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } + + @Override + public String getAction() { + return LauncherUtil.LAUNCH_ACTIVITY_TRANSPARENT; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivity.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivity.java new file mode 100644 index 000000000..ea512375f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivity.java @@ -0,0 +1,80 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.graph.ui.GPUUISceneGLListener0A; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.newt.event.MonitorEvent; +import com.jogamp.newt.event.MonitorModeListener; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + +import android.os.Bundle; +import android.util.Log; + +public class NEWTGraphUI1pActivity extends NewtBaseActivity { + static String TAG = "NEWTGraphUIActivity"; + + @Override + public void onCreate(final Bundle savedInstanceState) { + Log.d(TAG, "onCreate - 0"); + super.onCreate(savedInstanceState); + + // create GLWindow (-> incl. underlying NEWT Display, Screen & Window) + final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2)); + caps.setAlphaBits(4); + caps.setNumSamples(4); + caps.setSampleBuffers(true); + Log.d(TAG, "req caps: "+caps); + final GLWindow glWindow = GLWindow.create(caps); + glWindow.setFullscreen(true); + setContentView(getWindow(), glWindow); + + glWindow.addGLEventListener(new GPUUISceneGLListener0A(0)); + glWindow.getScreen().addMonitorModeListener(new MonitorModeListener() { + @Override + public void monitorModeChangeNotify(final MonitorEvent me) { } + @Override + public void monitorModeChanged(final MonitorEvent me, final boolean success) { + System.err.println("MonitorMode Changed (success "+success+"): "+me); + } + }); + glWindow.setVisible(true); + final Animator animator = new Animator(glWindow); + + animator.setUpdateFPSFrames(60, System.err); + animator.resetFPSCounter(); + glWindow.resetFPSCounter(); + + Log.d(TAG, "onCreate - X"); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivityLauncher.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivityLauncher.java new file mode 100644 index 000000000..796cff268 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivityLauncher.java @@ -0,0 +1,52 @@ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class NEWTGraphUI1pActivityLauncher extends LauncherUtil.BaseActivityLauncher { + static String demo = "com.jogamp.opengl.test.android.NEWTGraphUI1pActivity"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // props.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // props.setProperty("jogamp.debug.IOUtil", "true"); + // props.setProperty("nativewindow.debug", "all"); + props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // props.setProperty("jogl.debug", "all"); + // props.setProperty("jogl.debug.GLProfile", "true"); + props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.GLSLState", "true"); + // props.setProperty("jogl.debug.DebugGL", "true"); + // props.setProperty("jogl.debug.TraceGL", "true"); + // props.setProperty("newt.debug", "all"); + props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window.MouseEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivity.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivity.java new file mode 100644 index 000000000..ede8a5d31 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivity.java @@ -0,0 +1,79 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.graph.ui.GPUUISceneGLListener0A; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.graph.curve.Region; +import com.jogamp.newt.event.MonitorEvent; +import com.jogamp.newt.event.MonitorModeListener; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + +import android.os.Bundle; +import android.util.Log; + +public class NEWTGraphUI2pActivity extends NewtBaseActivity { + static String TAG = "NEWTGraphUIActivity"; + + @Override + public void onCreate(final Bundle savedInstanceState) { + Log.d(TAG, "onCreate - 0"); + super.onCreate(savedInstanceState); + + // create GLWindow (-> incl. underlying NEWT Display, Screen & Window) + final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2)); + caps.setAlphaBits(4); + Log.d(TAG, "req caps: "+caps); + final GLWindow glWindow = GLWindow.create(caps); + glWindow.setFullscreen(true); + setContentView(getWindow(), glWindow); + + glWindow.addGLEventListener(new GPUUISceneGLListener0A(Region.VBAA_RENDERING_BIT)); + glWindow.getScreen().addMonitorModeListener(new MonitorModeListener() { + @Override + public void monitorModeChangeNotify(final MonitorEvent me) { } + @Override + public void monitorModeChanged(final MonitorEvent me, final boolean success) { + System.err.println("MonitorMode Changed (success "+success+"): "+me); + } + }); + glWindow.setVisible(true); + final Animator animator = new Animator(glWindow); + + animator.setUpdateFPSFrames(60, System.err); + animator.resetFPSCounter(); + glWindow.resetFPSCounter(); + + Log.d(TAG, "onCreate - X"); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivityLauncher.java b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivityLauncher.java new file mode 100644 index 000000000..3d6b7991d --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivityLauncher.java @@ -0,0 +1,52 @@ +package com.jogamp.opengl.demos.android; + +import java.util.Arrays; +import java.util.List; + +import com.jogamp.opengl.demos.android.LauncherUtil.BaseActivityLauncher; +import com.jogamp.opengl.demos.android.LauncherUtil.OrderedProperties; + +public class NEWTGraphUI2pActivityLauncher extends LauncherUtil.BaseActivityLauncher { + static String demo = "com.jogamp.opengl.test.android.NEWTGraphUI2pActivity"; + static String[] sys_pkgs = new String[] { "com.jogamp.common", "com.jogamp.opengl" }; + static String[] usr_pkgs = new String[] { "com.jogamp.opengl.test" }; + + @Override + public void init() { + final OrderedProperties props = getProperties(); + // props.setProperty("jogamp.debug.JNILibLoader", "true"); + // props.setProperty("jogamp.debug.NativeLibrary", "true"); + // properties.setProperty("jogamp.debug.NativeLibrary.Lookup", "true"); + // properties.setProperty("jogamp.debug.IOUtil", "true"); + // properties.setProperty("nativewindow.debug", "all"); + props.setProperty("nativewindow.debug.GraphicsConfiguration", "true"); + // properties.setProperty("jogl.debug", "all"); + // properties.setProperty("jogl.debug.GLProfile", "true"); + props.setProperty("jogl.debug.GLDrawable", "true"); + props.setProperty("jogl.debug.GLContext", "true"); + props.setProperty("jogl.debug.GLSLCode", "true"); + props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // properties.setProperty("jogl.debug.GLSLState", "true"); + // properties.setProperty("jogl.debug.DebugGL", "true"); + // properties.setProperty("jogl.debug.TraceGL", "true"); + // properties.setProperty("newt.debug", "all"); + props.setProperty("newt.debug.Window", "true"); + // properties.setProperty("newt.debug.Window.MouseEvent", "true"); + // properties.setProperty("newt.debug.Window.KeyEvent", "true"); + } + + @Override + public String getActivityName() { + return demo; + } + + @Override + public List<String> getSysPackages() { + return Arrays.asList(sys_pkgs); + } + + @Override + public List<String> getUsrPackages() { + return Arrays.asList(usr_pkgs); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2Activity.java b/src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2Activity.java new file mode 100644 index 000000000..1485fd3dd --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2Activity.java @@ -0,0 +1,99 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.android; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.es2.RedSquareES2; + +import jogamp.newt.driver.android.NewtBaseActivity; + +import com.jogamp.newt.event.MonitorEvent; +import com.jogamp.newt.event.MonitorModeListener; +import com.jogamp.newt.opengl.GLWindow; + +import com.jogamp.opengl.util.Animator; + +import android.os.Bundle; +import android.util.Log; + +public class NEWTRedSquareES2Activity extends NewtBaseActivity { + static String TAG = "NEWTGearsES2Activity"; + + @Override + public void onCreate(final Bundle savedInstanceState) { + Log.d(TAG, "onCreate - 0"); + super.onCreate(savedInstanceState); + + // create GLWindow (-> incl. underlying NEWT Display, Screen & Window) + final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2)); + Log.d(TAG, "req caps: "+caps); + final GLWindow glWindow = GLWindow.create(caps); + // glWindow.setSize(200, 200); + // glWindow.setUndecorated(true); + glWindow.setFullscreen(true); + setContentView(getWindow(), glWindow); + + final RedSquareES2 demo = new RedSquareES2(-1); + // demo.enableAndroidTrace(true); + glWindow.addGLEventListener(demo); + glWindow.getScreen().addMonitorModeListener(new MonitorModeListener() { + @Override + public void monitorModeChangeNotify(final MonitorEvent me) { } + @Override + public void monitorModeChanged(final MonitorEvent me, final boolean success) { + System.err.println("MonitorMode Changed (success "+success+"): "+me); + } + }); + final Animator animator = new Animator(glWindow); + // animator.setRunAsFastAsPossible(true); + // glWindow.setSkipContextReleaseThread(animator.getThread()); + glWindow.setVisible(true); + + animator.setUpdateFPSFrames(60, System.err); + animator.resetFPSCounter(); + glWindow.resetFPSCounter(); + + Log.d(TAG, "onCreate - X"); + } + + @Override + public void onResume() { + // android.os.Debug.startMethodTracing("GearsES2.trace"); + // android.os.Debug.startAllocCounting(); + super.onResume(); + } + + @Override + public void onPause() { + // android.os.Debug.stopAllocCounting(); + // android.os.Debug.stopMethodTracing(); + super.onPause(); + } + +} diff --git a/src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2ActivityLauncher.java b/src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2ActivityLauncher.java new file mode 100644 index 000000000..061953d5e --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2ActivityLauncher.java @@ -0,0 +1,21 @@ +package com.jogamp.opengl.demos.android; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +public class NEWTRedSquareES2ActivityLauncher extends Activity { + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Uri uri = Uri.parse("launch://jogamp.org/com.jogamp.opengl.test.android.NEWTRedSquareES2Activity?sys=com.jogamp.common&sys=com.jogamp.opengl&pkg=com.jogamp.opengl.test"); + final Intent intent = new Intent("org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL", uri); + Log.d(getClass().getSimpleName(), "Launching Activity: "+intent); + startActivity (intent); + + finish(); // done + } +} diff --git a/src/demos/com/jogamp/opengl/demos/av/CrossFadePlayer.java b/src/demos/com/jogamp/opengl/demos/av/CrossFadePlayer.java new file mode 100644 index 000000000..a4d5e73de --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/av/CrossFadePlayer.java @@ -0,0 +1,212 @@ +/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.demos.av;
+
+import com.jogamp.common.net.Uri;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.opengl.util.av.AudioSink;
+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.av.GLMediaPlayerFactory;
+import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame;
+
+import java.io.File;
+
+/**
+ * Parallel media player that demonstrate CrossFade of audio volume during playback.
+ * This also demonstrate audio only playback of the GLMediaPlayer.
+ */
+public class CrossFadePlayer
+{
+ static GLMediaPlayer[] player;
+ static volatile boolean stop = false;
+
+ public static void main(final String[] args)
+ {
+
+ if(args.length==0) {
+ System.out.println("No files! \n" +
+ "pass as many media files you want\n" +
+ "to the CrossFadePlayer arguments \n" +
+ "and i will try CrossFade-play them all in parallel!");
+ }
+
+ final GLMediaEventListener mediaEventListener = new GLMediaEventListener()
+ {
+ @Override
+ public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { }
+
+ @Override
+ public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when)
+ {
+ System.out.println("\n***\nEvent mask changed: " + event_mask);
+ System.out.println("Timestamp: "+ when);
+ System.out.println("State of player: " + mp.getState().toString() +"\n");
+
+ if ((event_mask & GLMediaEventListener.EVENT_CHANGE_INIT) !=0) {
+ System.out.println("Duration: " + mp.getDuration() + "ms");
+ System.out.println("Volume: " + mp.getAudioVolume());
+ System.out.println("player.initGL()...");
+ new InterruptSource.Thread() {
+ public void run() {
+ try {
+ mp.initGL(null);
+ if ( GLMediaPlayer.State.Paused == mp.getState() ) { // init OK
+ mp.play();
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ } else if ((event_mask & GLMediaEventListener.EVENT_CHANGE_PAUSE) !=0) {
+ System.out.println("player.paused()...");
+ } else if ((event_mask & GLMediaEventListener.EVENT_CHANGE_PLAY) !=0) {
+ System.out.println("playing...");
+ System.out.println(mp.toString());
+ System.out.println(mp.getAudioSink().toString());
+ } else if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) {
+ final StreamException se = mp.getStreamException();
+ if( null != se ) {
+ System.err.println("Player State: EOS + Exception");
+ stop = true;
+ } else {
+ System.err.println("Player State: EOS");
+ new InterruptSource.Thread() {
+ public void run() {
+ System.out.println("mp.setPlaySpeed(1f) returned: " + mp.setPlaySpeed(1f));
+ mp.seek(0);
+ mp.play();
+ }
+ }.start();
+ }
+ }
+ if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) {
+ final StreamException se = mp.getStreamException();
+ if( null != se ) {
+ se.printStackTrace();
+ }
+ new InterruptSource.Thread() {
+ public void run() {
+ System.out.println("terminating...");
+ stop = true;
+ }
+ }.start();
+ }
+
+ }
+ };
+
+ // Initialize media players
+ player = new GLMediaPlayer[args.length];
+ int i=0;
+ for( final String arg: args ) {
+ player[i] = GLMediaPlayerFactory.createDefault();
+ if(player[i]!=null){
+ System.out.println("Created CrossFade player: "+ i + " " + player[i].getClass().getName());
+ player[i].addEventListener(mediaEventListener);
+ try {
+ final String filename = arg;
+ if(filename.equals("")){
+ System.out.println("No file selected: arg " + i +" = "+ filename);
+ player[i]=null;
+ } else {
+ final File file = new File(filename);
+ if(!file.exists()){
+ System.out.println("File do not exist");
+ } else {
+ final Uri uri = Uri.valueOf(file);
+ System.out.println("State of player "+ i +": " + player[i].getState().toString());
+ System.out.println("...initializing stream "+ i +"...");
+ player[i].initStream(uri, GLMediaPlayer.STREAM_ID_NONE, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.TEXTURE_COUNT_DEFAULT);
+
+ }
+ }
+ } catch (final Exception e1) {
+ e1.printStackTrace();
+ }
+ } else {
+ System.out.println("Failed to create player "+ i +"!");
+ }
+ i++;
+ }
+
+
+ // Main thread CrossFade until playback is done
+ final long startTime = com.jogamp.common.os.Platform.currentTimeMillis();
+ final double piPlayers = Math.PI*2.0f/args.length;
+ StreamException se = null;
+ while( null == se && stop == false ) {
+ try {
+ Thread.sleep(100);
+ } catch (final InterruptedException e) { }
+
+ // Find out the longest duration...
+ float maxDuration = 1000.0f ;
+ for(final GLMediaPlayer p: player) {
+ if(p!=null){
+ if( p.getDuration() > maxDuration) {
+ maxDuration = p.getDuration();
+ }
+ }
+ }
+
+ // tune the volume on players to crossfade!
+ final float progress = (com.jogamp.common.os.Platform.currentTimeMillis()-startTime)/maxDuration;
+
+ i = 0;
+ for(final GLMediaPlayer p: player){
+ if(p!=null){
+ final AudioSink sink = p.getAudioSink();
+ if(sink != null){
+ final float volume = (float) (0.5f+(0.5f*(Math.cos(40.0f*progress+(piPlayers*i)))));
+ final float playbacktime = com.jogamp.common.os.Platform.currentTimeMillis()-startTime;
+ // System.out.println("player: "+ i +" volume = " + volume +" progress = "+ progress +" time = "+ playbacktime + " / duration = " + maxDuration);
+ sink.setVolume(volume);
+ }
+
+ se = p.getStreamException();
+ if( null != se) {
+ se.printStackTrace();
+ throw new RuntimeException(se);
+ }
+ }
+
+ i++;
+ }
+ }
+
+ for(final GLMediaPlayer p: player) {
+ if(p!=null)
+ p.destroy(null);
+ }
+ System.out.println("...main exit...");
+ }
+}
diff --git a/src/demos/com/jogamp/opengl/demos/av/MovieCube.java b/src/demos/com/jogamp/opengl/demos/av/MovieCube.java new file mode 100644 index 000000000..caf2f9381 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/av/MovieCube.java @@ -0,0 +1,655 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.av; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.common.net.Uri; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +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.FontScale; +import com.jogamp.junit.util.JunitTracer; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.es2.TextureSequenceCubeES2; +import com.jogamp.opengl.demos.graph.TextRendererGLELBase; +import com.jogamp.opengl.demos.util.MiscUtils; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLReadBufferUtil; +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.av.GLMediaPlayerFactory; +import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; + +/** + * Simple cube movie player w/ aspect ration true projection on a cube. + */ +public class MovieCube implements GLEventListener { + public static final float zoom_def = -2.77f; + private static boolean waitForKey = false; + private final float zoom0, rotx, roty; + private TextureSequenceCubeES2 cube=null; + private GLMediaPlayer mPlayer=null; + private int swapInterval = 1; + private boolean swapIntervalSet = true; + private long lastPerfPos = 0; + private volatile boolean resetGLState = false; + private volatile GLAutoDrawable autoDrawable = null; + + /** Blender's Big Buck Bunny: 24f 416p H.264, AAC 48000 Hz, 2 ch, mpeg stream. */ + public static final Uri defURI; + static { + Uri _defURI = null; + try { + // Blender's Big Buck Bunny Trailer: 24f 640p VP8, Vorbis 44100Hz mono, WebM/Matroska Stream. + // _defURI = new URI("http://video.webmfiles.org/big-buck-bunny_trailer.webm"); + _defURI = Uri.cast("http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + } catch (final URISyntaxException e) { + e.printStackTrace(); + } + defURI = _defURI; + } + + /** + * Default constructor which also issues {@link #initStream(URI, int, int, int)} w/ default values + * and polls until the {@link GLMediaPlayer} is {@link GLMediaPlayer.State#Initialized}. + * If {@link GLMediaEventListener#EVENT_CHANGE_EOS} is reached, the stream is started over again. + * <p> + * This default constructor is merely useful for some <i>drop-in</i> test, e.g. using an applet. + * </p> + */ + public MovieCube() throws IOException, URISyntaxException { + this(zoom_def, 0f, 0f, true); + + mPlayer.addEventListener(new GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieCube AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieCube State: "+mp); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_SIZE & event_mask ) ) { + resetGLState(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { + new InterruptSource.Thread() { + @Override + public void run() { + // loop for-ever .. + mPlayer.seek(0); + mPlayer.play(); + } }.start(); + } + } + }); + initStream(defURI, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.TEXTURE_COUNT_DEFAULT); + StreamException se = null; + while( null == se && GLMediaPlayer.State.Initialized != mPlayer.getState() ) { + try { + Thread.sleep(16); + } catch (final InterruptedException e) { } + se = mPlayer.getStreamException(); + } + if( null != se ) { + se.printStackTrace(); + throw new RuntimeException(se); + } + } + + /** + * Custom constructor, user needs to issue {@link #initStream(URI, int, int, int)} afterwards. + */ + public MovieCube(final float zoom0, final float rotx, final float roty, final boolean showText) throws IOException { + this.zoom0 = zoom0; + this.rotx = rotx; + this.roty = roty; + this.showText = showText; + screenshot = new GLReadBufferUtil(false, false); + mPlayer = GLMediaPlayerFactory.createDefault(); + } + + public void initStream(final Uri streamLoc, final int vid, final int aid, final int textureCount) { + mPlayer.initStream(streamLoc, vid, aid, textureCount); + System.out.println("pC.1b "+mPlayer); + } + + public void setSwapInterval(final int v) { this.swapInterval = v; } + + public GLMediaPlayer getGLMediaPlayer() { return mPlayer; } + + public void resetGLState() { + resetGLState = true; + } + + final int[] textSampleCount = { 4 }; + + private final class InfoTextRendererGLELBase extends TextRendererGLELBase { + private static final float z_diff = 0.001f; + private final Font font = getFont(0, 0, 0); + private final float fontSize1 = 12; + private final float fontSize2 = 10; + private final GLRegion regionFPS; + private float pixelSize1, pixelSize2, underlineSize; + + InfoTextRendererGLELBase(final GLProfile glp, final int rmode, final boolean lowPerfDevice) { + // FIXME: Graph TextRenderer does not AA well w/o MSAA and FBO + super(rmode, MovieCube.this.textSampleCount); + this.setRendererCallbacks(RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + if( lowPerfDevice ) { + regionFPS = null; + } else { + regionFPS = GLRegion.create(glp, renderModes, null); + System.err.println("RegionFPS "+Region.getRenderModeString(renderModes)+", sampleCount "+textSampleCount[0]+", class "+regionFPS.getClass().getName()); + } + staticRGBAColor[0] = 0.1f; + staticRGBAColor[1] = 0.1f; + staticRGBAColor[2] = 0.1f; + staticRGBAColor[3] = 1.0f; + } + + @Override + public void init(final GLAutoDrawable drawable) { + // non-exclusive mode! + this.setSharedPMVMatrix(cube.pmvMatrix); + super.init(drawable); + + autoDrawable = drawable; + + pixelSize1 = FontScale.toPixels(fontSize1, dpiH); + pixelSize2 = FontScale.toPixels(fontSize2, dpiH); + pixelScale = 1.0f / ( pixelSize1 * 20f ); + // underlineSize: 'underline' amount of pixel below 0/0 (Note: lineGap is negative) + final Font.Metrics metrics = font.getMetrics(); + final float lineGap = pixelSize1 * metrics.getLineGap(); + final float descent = pixelSize1 * metrics.getDescent(); + underlineSize = lineGap - descent; + System.err.println("XXX: dpiH "+dpiH+", fontSize "+fontSize1+", pixelSize "+pixelSize1+", pixelScale "+pixelScale+", fLG "+lineGap+", fDesc "+descent+", underlineSize "+underlineSize); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + autoDrawable = null; + screenshot.dispose(drawable.getGL()); + if( null != regionFPS ) { + regionFPS.destroy(drawable.getGL().getGL2ES2()); + } + super.dispose(drawable); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GLAnimatorControl anim = drawable.getAnimator(); + final float lfps = null != anim ? anim.getLastFPS() : 0f; + final float tfps = null != anim ? anim.getTotalFPS() : 0f; + final boolean hasVideo = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID(); + final float pts = ( hasVideo ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS() ) / 1000f; + + // Note: MODELVIEW is from [ -1 .. 1 ] + + // dy: position right above video rectangle (bottom text line) + final float aspect = (float)mPlayer.getWidth() / (float)mPlayer.getHeight(); + final float aspect_h = 1f/aspect; + final float dy = 1f-aspect_h; + + // yoff1: position right above video rectangle (bottom text line) + // less than underlineSize, so 'underline' pixels are above video. + final float yoff1 = dy-(pixelScale*underlineSize); + + // yoff2: position right below video rectangle (bottom text line) + final float yoff2 = 2f-dy; + + /** + System.err.println("XXX: a "+aspect+", aspect_h "+aspect_h+", dy "+dy+ + "; underlineSize "+underlineSize+" "+(pixelScale*underlineSize)+ + "; yoff "+yoff1+", yoff2 "+yoff2); */ + + final GL gl = drawable.getGL(); + final String ptsPrec = null != regionFPS ? "3.1" : "3.0"; + final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f, v-sync %d", + pts, mPlayer.getDuration() / 1000f, + mPlayer.getState().toString().toLowerCase(), mPlayer.getPlaySpeed(), mPlayer.getAudioVolume(), + aspect, mPlayer.getFramerate(), lfps, tfps, swapInterval); + final String text2 = String.format("audio: id %d, kbps %d, codec %s", + mPlayer.getAID(), mPlayer.getAudioBitrate()/1000, mPlayer.getAudioCodec()); + final String text3 = String.format("video: id %d, kbps %d, codec %s", + mPlayer.getVID(), mPlayer.getVideoBitrate()/1000, mPlayer.getVideoCodec()); + final String text4 = mPlayer.getUri().path.decode(); + if( displayOSD && null != renderer ) { + gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); + if( null != regionFPS ) { + renderString(drawable, font, pixelSize1, text1, 1 /* col */, -1 /* row */, -1+z_diff, yoff1, 1f+z_diff, regionFPS.clear(gl.getGL2ES2())); // no-cache + } else { + renderString(drawable, font, pixelSize1, text1, 1 /* col */, -1 /* row */, -1+z_diff, yoff1, 1f+z_diff, true); + } + renderString(drawable, font, pixelSize2, text2, 1 /* col */, 0 /* row */, -1+z_diff, yoff2, 1f+z_diff, true); + renderString(drawable, font, pixelSize2, text3, 1 /* col */, 1 /* row */, -1+z_diff, yoff2, 1f+z_diff, true); + renderString(drawable, font, pixelSize2, text4, 1 /* col */, 2 /* row */, -1+z_diff, yoff2, 1f+z_diff, true); + } + } }; + private InfoTextRendererGLELBase textRendererGLEL = null; + final boolean showText; + private boolean displayOSD = true; + + public void printScreen(final GLAutoDrawable drawable) throws GLException, IOException { + final String filename = String.format("MovieCube-snap%02d-%03dx%03d.png", screenshot_num++, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + if(screenshot.readPixels(drawable.getGL(), false)) { + screenshot.write(new File(filename.toString())); + } + } + private final GLReadBufferUtil screenshot; + private int screenshot_num = 0; + + public void printScreenOnGLThread(final GLAutoDrawable drawable) { + drawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + try { + printScreen(drawable); + } catch (final GLException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } + return true; + } + }); + } + + private final KeyListener keyAction = new KeyAdapter() { + @Override + public void keyReleased(final KeyEvent e) { + if( e.isAutoRepeat() ) { + return; + } + System.err.println("MC "+e); + final int pts0 = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID() ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS(); + int pts1 = 0; + switch(e.getKeySymbol()) { + case KeyEvent.VK_V: { + switch(swapInterval) { + case 0: swapInterval = -1; break; + case -1: swapInterval = 1; break; + case 1: swapInterval = 0; break; + default: swapInterval = 1; break; + } + swapIntervalSet = true; + break; + } + case KeyEvent.VK_O: displayOSD = !displayOSD; break; + case KeyEvent.VK_RIGHT: pts1 = pts0 + 1000; break; + case KeyEvent.VK_UP: pts1 = pts0 + 10000; break; + case KeyEvent.VK_PAGE_UP: pts1 = pts0 + 30000; break; + case KeyEvent.VK_LEFT: pts1 = pts0 - 1000; break; + case KeyEvent.VK_DOWN: pts1 = pts0 - 10000; break; + case KeyEvent.VK_PAGE_DOWN: pts1 = pts0 - 30000; break; + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_HOME: + case KeyEvent.VK_BACK_SPACE: { + mPlayer.seek(0); + break; + } + case KeyEvent.VK_SPACE: { + if(GLMediaPlayer.State.Paused == mPlayer.getState()) { + mPlayer.play(); + } else { + mPlayer.pause(false); + } + break; + } + case KeyEvent.VK_MULTIPLY: + mPlayer.setPlaySpeed(1.0f); + break; + case KeyEvent.VK_SUBTRACT: { + float playSpeed = mPlayer.getPlaySpeed(); + if( e.isShiftDown() ) { + playSpeed /= 2.0f; + } else { + playSpeed -= 0.1f; + } + mPlayer.setPlaySpeed(playSpeed); + } break; + case KeyEvent.VK_ADD: { + float playSpeed = mPlayer.getPlaySpeed(); + if( e.isShiftDown() ) { + playSpeed *= 2.0f; + } else { + playSpeed += 0.1f; + } + mPlayer.setPlaySpeed(playSpeed); + } break; + case KeyEvent.VK_M: { + float audioVolume = mPlayer.getAudioVolume(); + if( audioVolume > 0.5f ) { + audioVolume = 0f; + } else { + audioVolume = 1f; + } + mPlayer.setAudioVolume(audioVolume); + } break; + case KeyEvent.VK_S: + if(null != autoDrawable) { + printScreenOnGLThread(autoDrawable); + } + break; + } + + if( 0 != pts1 ) { + mPlayer.seek(pts1); + } + } + }; + + @Override + public void init(final GLAutoDrawable drawable) { + if(null == mPlayer) { + throw new InternalError("mPlayer null"); + } + if( GLMediaPlayer.State.Uninitialized == mPlayer.getState() ) { + throw new IllegalStateException("mPlayer in uninitialized state: "+mPlayer); + } + if( GLMediaPlayer.STREAM_ID_NONE == mPlayer.getVID() ) { + // throw new IllegalStateException("mPlayer has no VID/stream selected: "+mPlayer); + } + resetGLState = false; + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + System.err.println(JoglVersion.getGLInfo(gl, null)); + + cube = new TextureSequenceCubeES2(mPlayer, false, zoom0, rotx, roty); + + if(waitForKey) { + JunitTracer.waitForKey("Init>"); + } + + if( GLMediaPlayer.State.Initialized == mPlayer.getState() ) { + try { + mPlayer.initGL(gl); + } catch (final Exception e) { + e.printStackTrace(); + if(null != mPlayer) { + mPlayer.destroy(gl); + mPlayer = null; + } + throw new GLException(e); + } + } + cube.init(drawable); + mPlayer.play(); + System.out.println("play.0 "+mPlayer); + + boolean added; + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.addKeyListener(keyAction); + added = true; + } else { added = false; } + System.err.println("MC.init: kl-added "+added+", "+drawable.getClass().getName()); + + if( showText ) { + final int rmode = drawable.getChosenGLCapabilities().getSampleBuffers() ? 0 : Region.VBAA_RENDERING_BIT; + final boolean lowPerfDevice = gl.isGLES(); + textRendererGLEL = new InfoTextRendererGLELBase(gl.getGLProfile(), rmode, lowPerfDevice); + drawable.addGLEventListener(textRendererGLEL); + } + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + if(null == mPlayer) { return; } + cube.reshape(drawable, x, y, width, height); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + System.err.println(Thread.currentThread()+" MovieCube.dispose ... "); + if( null != textRendererGLEL ) { + drawable.disposeGLEventListener(textRendererGLEL, true); + textRendererGLEL = null; + } + disposeImpl(drawable, true); + } + + private void disposeImpl(final GLAutoDrawable drawable, final boolean disposePlayer) { + if(null == mPlayer) { return; } + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.removeKeyListener(keyAction); + } + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if( disposePlayer ) { + mPlayer.destroy(gl); + mPlayer=null; + } + cube.dispose(drawable); + cube=null; + } + + + @Override + public void display(final GLAutoDrawable drawable) { + if( swapIntervalSet ) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + final int _swapInterval = swapInterval; + gl.setSwapInterval(_swapInterval); // in case switching the drawable (impl. may bound attribute there) + drawable.getAnimator().resetFPSCounter(); + swapInterval = gl.getSwapInterval(); + System.err.println("Swap Interval: "+_swapInterval+" -> "+swapInterval); + swapIntervalSet = false; + } + if(null == mPlayer) { return; } + + if( resetGLState ) { + resetGLState = false; + System.err.println("XXX resetGLState"); + disposeImpl(drawable, false); + init(drawable); + reshape(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + } + + final long currentPos = System.currentTimeMillis(); + if( currentPos - lastPerfPos > 2000 ) { + System.err.println( mPlayer.getPerfString() ); + lastPerfPos = currentPos; + } + cube.display(drawable); + } + + public static void main(final String[] args) throws IOException, InterruptedException, URISyntaxException { + int swapInterval = 1; + int width = 800; + int height = 600; + int textureCount = GLMediaPlayer.TEXTURE_COUNT_DEFAULT; // default - threaded + + boolean forceES2 = false; + boolean forceES3 = false; + boolean forceGL3 = false; + boolean forceGLDef = false; + int vid = GLMediaPlayer.STREAM_ID_AUTO; + int aid = GLMediaPlayer.STREAM_ID_AUTO; + final boolean origSize; + + String url_s=null, file_s=null; + { + boolean _origSize = false; + for(int i=0; i<args.length; i++) { + if(args[i].equals("-vid")) { + i++; + vid = MiscUtils.atoi(args[i], vid); + } else if(args[i].equals("-aid")) { + i++; + aid = MiscUtils.atoi(args[i], aid); + } else if(args[i].equals("-width")) { + i++; + width = MiscUtils.atoi(args[i], width); + } else if(args[i].equals("-height")) { + i++; + height = MiscUtils.atoi(args[i], height); + } else if(args[i].equals("-osize")) { + _origSize = true; + } else if(args[i].equals("-textureCount")) { + i++; + textureCount = MiscUtils.atoi(args[i], textureCount); + } else if(args[i].equals("-url")) { + i++; + url_s = args[i]; + } else if(args[i].equals("-file")) { + i++; + file_s = args[i]; + } else if(args[i].equals("-es2")) { + forceES2 = true; + } else if(args[i].equals("-es3")) { + forceES3 = true; + } else if(args[i].equals("-gl3")) { + forceGL3 = true; + } else if(args[i].equals("-gldef")) { + forceGLDef = true; + } else if(args[i].equals("-vsync")) { + i++; + swapInterval = MiscUtils.atoi(args[i], swapInterval); + } else if(args[i].equals("-wait")) { + waitForKey = true; + } + } + origSize = _origSize; + } + final Uri streamLoc; + if( null != url_s ) { + streamLoc = Uri.cast( url_s ); + } else if( null != file_s ) { + streamLoc = Uri.valueOf(new File(file_s)); + } else { + streamLoc = defURI; + } + System.err.println("url_s "+url_s); + System.err.println("file_s "+file_s); + System.err.println("stream "+streamLoc); + System.err.println("vid "+vid+", aid "+aid); + System.err.println("textureCount "+textureCount); + System.err.println("forceES2 "+forceES2); + System.err.println("forceES3 "+forceES3); + System.err.println("forceGL3 "+forceGL3); + System.err.println("forceGLDef "+forceGLDef); + System.err.println("swapInterval "+swapInterval); + + final MovieCube mc = new MovieCube(zoom_def, 0f, 0f, true); + mc.setSwapInterval(swapInterval); + + final GLProfile glp; + if(forceGLDef) { + glp = GLProfile.getDefault(); + } else if(forceGL3) { + glp = GLProfile.get(GLProfile.GL3); + } else if(forceES3) { + glp = GLProfile.get(GLProfile.GLES3); + } else if(forceES2) { + glp = GLProfile.get(GLProfile.GLES2); + } else { + glp = GLProfile.getGL2ES2(); + } + System.err.println("GLProfile: "+glp); + final GLCapabilities caps = new GLCapabilities(glp); + // caps.setAlphaBits(4); // NOTE_ALPHA_BLENDING: We go w/o alpha and blending! + final GLWindow window = GLWindow.create(caps); + final Animator anim = new Animator(window); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyed(final WindowEvent e) { + anim.stop(); + } + }); + window.setSize(width, height); + window.setVisible(true); + System.err.println("Chosen: "+window.getChosenGLCapabilities()); + anim.start(); + + mc.mPlayer.addEventListener(new GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { + } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieCube AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieCube State: "+mp); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_SIZE & event_mask ) ) { + if( origSize ) { + window.setSurfaceSize(mp.getWidth(), mp.getHeight()); + } + // window.disposeGLEventListener(ms, false /* remove */ ); + mc.resetGLState(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + window.addGLEventListener(mc); + anim.setUpdateFPSFrames(60, null); + anim.resetFPSCounter(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_PLAY & event_mask ) ) { + anim.resetFPSCounter(); + } + if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) { + final StreamException se = mc.mPlayer.getStreamException(); + if( null != se ) { + se.printStackTrace(); + } + new InterruptSource.Thread() { + @Override + public void run() { + window.destroy(); + } }.start(); + } + } + }); + mc.initStream(streamLoc, vid, aid, textureCount); + } +} + diff --git a/src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java b/src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java new file mode 100644 index 000000000..62e3975dd --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java @@ -0,0 +1,887 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.av; + +import java.net.URISyntaxException; +import java.nio.FloatBuffer; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLES2; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLUniformData; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.common.net.Uri; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +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.FontScale; +import com.jogamp.junit.util.JunitTracer; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.GLExtensions; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.graph.TextRendererGLELBase; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.Quaternion; +import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.util.CustomGLEventListener; +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.av.GLMediaPlayer; +import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener; +import com.jogamp.opengl.util.av.GLMediaPlayerFactory; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; +import com.jogamp.opengl.util.stereo.EyeParameter; +import com.jogamp.opengl.util.stereo.ViewerPose; +import com.jogamp.opengl.util.stereo.StereoClientRenderer; +import com.jogamp.opengl.util.stereo.StereoGLEventListener; +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureCoords; +import com.jogamp.opengl.util.texture.TextureSequence; +import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; + +/** + * Side-By-Side (SBS) 3D Movie Player for {@link StereoClientRenderer} + * <p> + * The movie is assumed to be symmetrical SBS, + * the left-eye receives the left-part of the texture + * and the right-eye the right-part. + * </p> + */ +public class MovieSBSStereo implements StereoGLEventListener { + public static final String WINDOW_KEY = "window"; + public static final String STEREO_RENDERER_KEY = "stereo"; + public static final String PLAYER = "player"; + + private static boolean waitForKey = false; + private int surfWidth, surfHeight; + private int prevMouseX; // , prevMouseY; + private int rotate = 0; + private float zoom0; + private float zoom1; + private float zoom; + private long startTime; + private final float alpha = 1.0f; + + private GLMediaPlayer mPlayer; + private boolean mPlayerScaleOrig; + private float[] verts = null; + private GLArrayDataServer interleavedVBOLeft; + private GLArrayDataServer interleavedVBORight; + private volatile boolean resetGLState = false; + private StereoClientRenderer stereoClientRenderer; + + private ShaderState st; + private PMVMatrix pmvMatrix; + private GLUniformData pmvMatrixUniform; + private static final String shaderBasename = "texsequence_xxx"; + private static final String myTextureLookupName = "myTexture2D"; + + /** Blender's Big Buck Bunny: 24f 416p H.264, AAC 48000 Hz, 2 ch, mpeg stream. */ + public static final Uri defURI; + static { + Uri _defURI = null; + try { + // Blender's Big Buck Bunny Trailer: 24f 640p VP8, Vorbis 44100Hz mono, WebM/Matroska Stream. + // _defURI = new URI("http://video.webmfiles.org/big-buck-bunny_trailer.webm"); + _defURI = Uri.cast("http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + } catch (final URISyntaxException e) { + e.printStackTrace(); + } + defURI = _defURI; + } + + final int[] textSampleCount = { 4 }; + + private final class InfoTextRendererGLELBase extends TextRendererGLELBase { + private final Font font = getFont(0, 0, 0); + private final float fontSize = 1f; // 0.01f; + private final GLRegion regionFPS; + + InfoTextRendererGLELBase(final GLProfile glp, final int rmode, final boolean lowPerfDevice) { + // FIXME: Graph TextRenderer does not AA well w/o MSAA and FBO + super(rmode, textSampleCount); + this.setRendererCallbacks(RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + if( lowPerfDevice ) { + regionFPS = null; + } else { + regionFPS = GLRegion.create(glp, renderModes, null); + System.err.println("RegionFPS "+Region.getRenderModeString(renderModes)+", sampleCount "+textSampleCount[0]+", class "+regionFPS.getClass().getName()); + } + staticRGBAColor[0] = 0.9f; + staticRGBAColor[1] = 0.9f; + staticRGBAColor[2] = 0.9f; + staticRGBAColor[3] = 1.0f; + } + + @Override + public void init(final GLAutoDrawable drawable) { + super.init(drawable); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + if( null != regionFPS ) { + regionFPS.destroy(drawable.getGL().getGL2ES2()); + } + super.dispose(drawable); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GLAnimatorControl anim = drawable.getAnimator(); + final float lfps = null != anim ? anim.getLastFPS() : 0f; + final float tfps = null != anim ? anim.getTotalFPS() : 0f; + final boolean hasVideo = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID(); + final float pts = ( hasVideo ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS() ) / 1000f; + + // Note: MODELVIEW is from [ 0 .. height ] + + final int height = 0; // drawable.getSurfaceHeight(); + + final float aspect = (float)mPlayer.getWidth() / (float)mPlayer.getHeight(); + + final String ptsPrec = null != regionFPS ? "3.1" : "3.0"; + final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f", + pts, mPlayer.getDuration() / 1000f, + mPlayer.getState().toString().toLowerCase(), mPlayer.getPlaySpeed(), mPlayer.getAudioVolume(), + aspect, mPlayer.getFramerate(), lfps, tfps); + final String text2 = String.format("audio: id %d, kbps %d, codec %s", + mPlayer.getAID(), mPlayer.getAudioBitrate()/1000, mPlayer.getAudioCodec()); + final String text3 = String.format("video: id %d, kbps %d, codec %s", + mPlayer.getVID(), mPlayer.getVideoBitrate()/1000, mPlayer.getVideoCodec()); + final String text4 = mPlayer.getUri().path.decode(); + if( displayOSD && null != renderer ) { + // We share ClearColor w/ MovieSimple's init ! + final float pixelSize = FontScale.toPixels(fontSize, dpiH); + if( null != regionFPS ) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + renderString(drawable, font, pixelSize, text1, 1 /* col */, 1 /* row */, 0, 0, -1, regionFPS.clear(gl)); // no-cache + } else { + renderString(drawable, font, pixelSize, text1, 1 /* col */, 1 /* row */, 0, 0, -1, true); + } + renderString(drawable, font, pixelSize, text2, 1 /* col */, -4 /* row */, 0, height, -1, true); + renderString(drawable, font, pixelSize, text3, 1 /* col */, -3 /* row */, 0, height, 0, true); + renderString(drawable, font, pixelSize, text4, 1 /* col */, -2 /* row */, 0, height, 1, true); + } + } }; + private final boolean enableTextRendererGLEL = false; + private InfoTextRendererGLELBase textRendererGLEL = null; + private boolean displayOSD = false; + + private final MouseListener mouseAction = new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + if(e.getY()<=surfHeight/2 && null!=mPlayer && 1 == e.getClickCount()) { + if(GLMediaPlayer.State.Playing == mPlayer.getState()) { + mPlayer.pause(false); + } else { + mPlayer.play(); + } + } + } + @Override + public void mouseReleased(final MouseEvent e) { + if(e.getY()<=surfHeight/2) { + rotate = -1; + zoom = zoom0; + System.err.println("zoom: "+zoom); + } + } + @Override + public void mouseMoved(final MouseEvent e) { + prevMouseX = e.getX(); + // prevMouseY = e.getY(); + } + @Override + public void mouseDragged(final MouseEvent e) { + final int x = e.getX(); + final int y = e.getY(); + + if(y>surfHeight/2) { + final float dp = (float)(x-prevMouseX)/(float)surfWidth; + final int pts0 = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID() ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS(); + mPlayer.seek(pts0 + (int) (mPlayer.getDuration() * dp)); + } else { + mPlayer.play(); + rotate = 1; + zoom = zoom1; + } + + prevMouseX = x; + // prevMouseY = y; + } + @Override + public void mouseWheelMoved(final MouseEvent e) { + if( !e.isShiftDown() ) { + zoom += e.getRotation()[1]/10f; // vertical: wheel + System.err.println("zoom: "+zoom); + } + } }; + + private final KeyListener keyAction = new KeyAdapter() { + @Override + public void keyReleased(final KeyEvent e) { + if( e.isAutoRepeat() ) { + return; + } + System.err.println("MC "+e); + final int pts0 = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID() ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS(); + int pts1 = 0; + switch(e.getKeySymbol()) { + case KeyEvent.VK_O: displayOSD = !displayOSD; break; + case KeyEvent.VK_RIGHT: pts1 = pts0 + 1000; break; + case KeyEvent.VK_UP: pts1 = pts0 + 10000; break; + case KeyEvent.VK_PAGE_UP: pts1 = pts0 + 30000; break; + case KeyEvent.VK_LEFT: pts1 = pts0 - 1000; break; + case KeyEvent.VK_DOWN: pts1 = pts0 - 10000; break; + case KeyEvent.VK_PAGE_DOWN: pts1 = pts0 - 30000; break; + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_HOME: + case KeyEvent.VK_BACK_SPACE: { + mPlayer.seek(0); + break; + } + case KeyEvent.VK_SPACE: { + if(GLMediaPlayer.State.Paused == mPlayer.getState()) { + mPlayer.play(); + } else { + mPlayer.pause(false); + } + break; + } + case KeyEvent.VK_MULTIPLY: + mPlayer.setPlaySpeed(1.0f); + break; + case KeyEvent.VK_SUBTRACT: { + float playSpeed = mPlayer.getPlaySpeed(); + if( e.isShiftDown() ) { + playSpeed /= 2.0f; + } else { + playSpeed -= 0.1f; + } + mPlayer.setPlaySpeed(playSpeed); + } break; + case KeyEvent.VK_ADD: { + float playSpeed = mPlayer.getPlaySpeed(); + if( e.isShiftDown() ) { + playSpeed *= 2.0f; + } else { + playSpeed += 0.1f; + } + mPlayer.setPlaySpeed(playSpeed); + } break; + case KeyEvent.VK_M: { + float audioVolume = mPlayer.getAudioVolume(); + if( audioVolume > 0.5f ) { + audioVolume = 0f; + } else { + audioVolume = 1f; + } + mPlayer.setAudioVolume(audioVolume); + } break; + } + + if( 0 != pts1 ) { + mPlayer.seek(pts1); + } + } }; + + /** user needs to issue {@link #initStream(URI, int, int, int)} afterwards. */ + public MovieSBSStereo() throws IllegalStateException { + mPlayerScaleOrig = false; + mPlayer = GLMediaPlayerFactory.createDefault(); + mPlayer.attachObject(PLAYER, this); + System.out.println("pC.1a "+mPlayer); + } + + public void initStream(final Uri streamLoc, final int vid, final int aid, final int textureCount) { + mPlayer.initStream(streamLoc, vid, aid, textureCount); + System.out.println("pC.1b "+mPlayer); + } + + public GLMediaPlayer getGLMediaPlayer() { return mPlayer; } + + public void setScaleOrig(final boolean v) { + mPlayerScaleOrig = v; + } + + public void setStereoClientRenderer(final StereoClientRenderer scr) { + stereoClientRenderer = scr; + } + public StereoClientRenderer getStereoClientRenderer() { return stereoClientRenderer; } + + public void resetGLState() { + resetGLState = true; + } + + private void initShader(final GL2ES2 gl) { + // Create & Compile the shader objects + final ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, MovieSBSStereo.class, + "../shader", "../shader/bin", shaderBasename, true); + final ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, MovieSBSStereo.class, + "../shader", "../shader/bin", shaderBasename, true); + + boolean preludeGLSLVersion = true; + if( GLES2.GL_TEXTURE_EXTERNAL_OES == mPlayer.getTextureTarget() ) { + if( !gl.isExtensionAvailable(GLExtensions.OES_EGL_image_external) ) { + throw new GLException(GLExtensions.OES_EGL_image_external+" requested but not available"); + } + if( Platform.OSType.ANDROID == Platform.getOSType() && gl.isGLES3() ) { + // Bug on Nexus 10, ES3 - Android 4.3, where + // GL_OES_EGL_image_external extension directive leads to a failure _with_ '#version 300 es' ! + // P0003: Extension 'GL_OES_EGL_image_external' not supported + preludeGLSLVersion = false; + } + } + rsVp.defaultShaderCustomization(gl, preludeGLSLVersion, true); + + int rsFpPos = preludeGLSLVersion ? rsFp.addGLSLVersion(gl) : 0; + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, mPlayer.getRequiredExtensionsShaderStub()); + rsFp.addDefaultShaderPrecision(gl, rsFpPos); + + final String texLookupFuncName = mPlayer.getTextureLookupFunctionName(myTextureLookupName); + rsFp.replaceInShaderSource(myTextureLookupName, texLookupFuncName); + + // Inject TextureSequence shader details + final StringBuilder sFpIns = new StringBuilder(); + sFpIns.append("uniform ").append(mPlayer.getTextureSampler2DType()).append(" mgl_ActiveTexture;\n"); + sFpIns.append(mPlayer.getTextureLookupFragmentShaderImpl()); + rsFp.insertShaderSource(0, "TEXTURE-SEQUENCE-CODE-BEGIN", 0, sFpIns); + + // Create & Link the shader program + final ShaderProgram sp = new ShaderProgram(); + sp.add(rsVp); + sp.add(rsFp); + if(!sp.link(gl, System.err)) { + throw new GLException("Couldn't link program: "+sp); + } + + // Let's manage all our states using ShaderState. + st = new ShaderState(); + st.attachShaderProgram(gl, sp, false); + } + + @Override + public void init(final GLAutoDrawable drawable) { + if(null == mPlayer) { + throw new InternalError("mPlayer null"); + } + if( GLMediaPlayer.State.Uninitialized == mPlayer.getState() ) { + throw new IllegalStateException("mPlayer in uninitialized state: "+mPlayer); + } + final boolean hasVideo = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID(); + resetGLState = false; + + zoom0 = -2.1f; + zoom1 = -5f; + zoom = 0f; + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + System.err.println(JoglVersion.getGLInfo(gl, null)); + System.err.println("Alpha: "+alpha+", opaque "+drawable.getChosenGLCapabilities().isBackgroundOpaque()+ + ", "+drawable.getClass().getName()+", "+drawable); + + if(waitForKey) { + JunitTracer.waitForKey("Init>"); + } + final Texture tex; + try { + System.out.println("p0 "+mPlayer); + if(GLMediaPlayer.State.Initialized == mPlayer.getState() ) { + mPlayer.initGL(gl); + } + System.out.println("p1 "+mPlayer); + final TextureFrame frame = mPlayer.getLastTexture(); + if( null != frame ) { + if( !hasVideo ) { + throw new InternalError("XXX: "+mPlayer); + } + tex = frame.getTexture(); + if( null == tex ) { + throw new InternalError("XXX: "+mPlayer); + } + } else { + tex = null; + if( hasVideo ) { + throw new InternalError("XXX: "+mPlayer); + } + } + mPlayer.setTextureMinMagFilter( new int[] { GL.GL_NEAREST, GL.GL_NEAREST } ); + } catch (final Exception glex) { + glex.printStackTrace(); + if(null != mPlayer) { + mPlayer.destroy(gl); + mPlayer = null; + } + throw new GLException(glex); + } + + if( hasVideo ) { + initShader(gl); + + // Push the 1st uniform down the path + st.useProgram(gl, true); + + final int[] viewPort = new int[] { 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()}; + pmvMatrix = new PMVMatrix(); + reshapePMV(viewPort[2], viewPort[3]); + pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); + if(!st.uniform(gl, pmvMatrixUniform)) { + throw new GLException("Error setting PMVMatrix in shader: "+st); + } + if(!st.uniform(gl, new GLUniformData("mgl_ActiveTexture", mPlayer.getTextureUnit()))) { + throw new GLException("Error setting mgl_ActiveTexture in shader: "+st); + } + + final float dWidth = drawable.getSurfaceWidth(); + final float dHeight = drawable.getSurfaceHeight(); + final float mWidth = mPlayer.getWidth(); + final float mHeight = mPlayer.getHeight(); + final float mAspect = mWidth/mHeight; + System.err.println("XXX0: mov aspect: "+mAspect); + float xs, ys; + if(mPlayerScaleOrig && mWidth < dWidth && mHeight < dHeight) { + xs = mAspect * ( mWidth / dWidth ) ; ys = xs / mAspect ; + } else { + xs = mAspect; ys = 1f; // b>h + } + verts = new float[] { -1f*xs, -1f*ys, 0f, // LB + 1f*xs, 1f*ys, 0f // RT + }; + { + System.err.println("XXX0: pixel LB: "+verts[0]+", "+verts[1]+", "+verts[2]); + System.err.println("XXX0: pixel RT: "+verts[3]+", "+verts[4]+", "+verts[5]); + final float[] winLB = new float[3]; + final float[] winRT = new float[3]; + pmvMatrix.gluProject(verts[0], verts[1], verts[2], viewPort, 0, winLB, 0); + pmvMatrix.gluProject(verts[3], verts[4], verts[5], viewPort, 0, winRT, 0); + System.err.println("XXX0: win LB: "+winLB[0]+", "+winLB[1]+", "+winLB[2]); + System.err.println("XXX0: win RT: "+winRT[0]+", "+winRT[1]+", "+winRT[2]); + } + + interleavedVBOLeft = GLArrayDataServer.createGLSLInterleaved(3+4+2, GL.GL_FLOAT, false, 3*4, GL.GL_STATIC_DRAW); + { + interleavedVBOLeft.addGLSLSubArray("mgl_Vertex", 3, GL.GL_ARRAY_BUFFER); + interleavedVBOLeft.addGLSLSubArray("mgl_Color", 4, GL.GL_ARRAY_BUFFER); + interleavedVBOLeft.addGLSLSubArray("mgl_MultiTexCoord", 2, GL.GL_ARRAY_BUFFER); + } + interleavedVBORight = GLArrayDataServer.createGLSLInterleaved(3+4+2, GL.GL_FLOAT, false, 3*4, GL.GL_STATIC_DRAW); + { + interleavedVBORight.addGLSLSubArray("mgl_Vertex", 3, GL.GL_ARRAY_BUFFER); + interleavedVBORight.addGLSLSubArray("mgl_Color", 4, GL.GL_ARRAY_BUFFER); + interleavedVBORight.addGLSLSubArray("mgl_MultiTexCoord", 2, GL.GL_ARRAY_BUFFER); + } + updateInterleavedVBO(gl, interleavedVBOLeft, tex, 0); + updateInterleavedVBO(gl, interleavedVBORight, tex, 1); + + st.ownAttribute(interleavedVBOLeft, true); + st.ownAttribute(interleavedVBORight, true); + gl.glClearColor(0.3f, 0.3f, 0.3f, 0.3f); + + gl.glEnable(GL.GL_DEPTH_TEST); + + st.useProgram(gl, false); + + // Let's show the completed shader state .. + System.out.println("iVBOLeft : "+interleavedVBOLeft); + System.out.println("iVBORight: "+interleavedVBORight); + System.out.println(st); + } + + mPlayer.play(); + System.out.println("play.0 "+mPlayer); + startTime = System.currentTimeMillis(); + + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.addMouseListener(mouseAction); + window.addKeyListener(keyAction); + surfWidth = window.getSurfaceWidth(); + surfHeight = window.getSurfaceHeight(); + } + final int rmode = drawable.getChosenGLCapabilities().getSampleBuffers() ? 0 : Region.VBAA_RENDERING_BIT; + final boolean lowPerfDevice = gl.isGLES(); + if( enableTextRendererGLEL ) { + textRendererGLEL = new InfoTextRendererGLELBase(gl.getGLProfile(), rmode, lowPerfDevice); + textRendererGLEL.init(drawable); + } else { + textRendererGLEL = null; + } + } + + protected void updateInterleavedVBO(final GL gl, final GLArrayDataServer iVBO, final Texture tex, final int eyeNum) { + final boolean wasEnabled = iVBO.enabled(); + iVBO.seal(gl, false); + iVBO.rewind(); + { + final FloatBuffer ib = (FloatBuffer)iVBO.getBuffer(); + final TextureCoords tc = tex.getImageTexCoords(); + final float texHalfWidth = tc.right()/2f; + System.err.println("XXX0: "+tc+", texHalfWidth "+texHalfWidth); + System.err.println("XXX0: tex aspect: "+tex.getAspectRatio()); + System.err.println("XXX0: tex y-flip: "+tex.getMustFlipVertically()); + + // left-bottom + ib.put(verts[0]); ib.put(verts[1]); ib.put(verts[2]); + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + if( 0 == eyeNum ) { + ib.put( tc.left() ); ib.put( tc.bottom() ); + } else { + ib.put( tc.left() + texHalfWidth ); ib.put( tc.bottom() ); + } + + // right-bottom + ib.put(verts[3]); ib.put(verts[1]); ib.put(verts[2]); + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + if( 0 == eyeNum ) { + ib.put( texHalfWidth ); ib.put( tc.bottom() ); + } else { + ib.put( tc.right() ); ib.put( tc.bottom() ); + } + + // left-top + ib.put(verts[0]); ib.put(verts[4]); ib.put(verts[2]); + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + if( 0 == eyeNum ) { + ib.put( tc.left() ); ib.put( tc.top() ); + } else { + ib.put( tc.left() + texHalfWidth ); ib.put( tc.top() ); + } + + // right-top + ib.put(verts[3]); ib.put(verts[4]); ib.put(verts[2]); + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + if( 0 == eyeNum ) { + ib.put( texHalfWidth ); ib.put( tc.top() ); + } else { + ib.put( tc.right() ); ib.put( tc.top() ); + } + } + iVBO.seal(gl, true); + if( !wasEnabled ) { + iVBO.enableBuffer(gl, false); + } + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + surfWidth = width; + surfHeight = height; + + if(null == mPlayer) { return; } + + if(null != st) { + reshapePMV(width, height); + st.useProgram(gl, true); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + } + + System.out.println("pR "+mPlayer); + if( null != textRendererGLEL ) { + textRendererGLEL.reshape(drawable, 0, 0, width, height); + } + } + + private final float zNear = 0.1f; + private final float zFar = 10000f; + + private void reshapePMV(final int width, final int height) { + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.gluPerspective(45.0f, (float)width / (float)height, zNear, zFar); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, zoom0); + } + + private final float[] mat4Tmp1 = new float[16]; + private final float[] mat4Tmp2 = new float[16]; + private final float[] vec3Tmp1 = new float[3]; + private final float[] vec3Tmp2 = new float[3]; + private final float[] vec3Tmp3 = new float[3]; + + GLArrayDataServer interleavedVBOCurrent = null; + + private static final float[] vec3ScalePos = new float[] { 4f, 4f, 4f }; + + @Override + public void reshapeForEye(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height, + final EyeParameter eyeParam, final ViewerPose viewerPose) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + interleavedVBOCurrent = 0 == eyeParam.number ? interleavedVBOLeft : interleavedVBORight; + + surfWidth = drawable.getSurfaceWidth(); + surfHeight = drawable.getSurfaceHeight(); + + if(null == mPlayer) { return; } + if(null == st) { return; } + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + final float[] mat4Projection = FloatUtil.makePerspective(mat4Tmp1, 0, true, eyeParam.fovhv, zNear, zFar); + pmvMatrix.glLoadMatrixf(mat4Projection, 0); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + final Quaternion rollPitchYaw = new Quaternion(); + final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0); + VectorUtil.scaleVec3(shiftedEyePos, shiftedEyePos, vec3ScalePos); // amplify viewerPose position + VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset); + + rollPitchYaw.mult(viewerPose.orientation); + final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0); + final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0); + final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward); + + final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp1, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp2); + final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Tmp2, true, eyeParam.distNoseToPupilX, eyeParam.distMiddleToPupilY, eyeParam.eyeReliefZ); + final float[] mat4Modelview = FloatUtil.multMatrix(mViewAdjust, mLookAt); + pmvMatrix.glLoadMatrixf(mat4Modelview, 0); + pmvMatrix.glTranslatef(0, 0, zoom0); + st.useProgram(gl, true); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + if( null != textRendererGLEL ) { + textRendererGLEL.reshape(drawable, 0, 0, width, height); + } + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + if( null != textRendererGLEL ) { + textRendererGLEL.dispose(drawable); + textRendererGLEL = null; + } + disposeImpl(drawable, true); + } + + private void disposeImpl(final GLAutoDrawable drawable, final boolean disposePlayer) { + if(null == mPlayer) { return; } + + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.removeMouseListener(mouseAction); + window.removeKeyListener(keyAction); + } + + System.out.println("pD.1 "+mPlayer+", disposePlayer "+disposePlayer); + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if( disposePlayer ) { + mPlayer.destroy(gl); + System.out.println("pD.X "+mPlayer); + mPlayer=null; + } + pmvMatrixUniform = null; + if(null != pmvMatrix) { + pmvMatrix=null; + } + if(null != st) { + st.destroy(gl); + st=null; + } + } + + long lastPerfPos = 0; + + @Override + public void display(final GLAutoDrawable drawable) { + display(drawable, 0); + } + + @Override + public void display(final GLAutoDrawable drawable, final int flags) { + // TODO Auto-generated method stub + final boolean repeatedFrame = 0 != ( CustomGLEventListener.DISPLAY_REPEAT & flags ); + final boolean dontClear = 0 != ( CustomGLEventListener.DISPLAY_DONTCLEAR & flags ); + final GLArrayDataServer iVBO = null != interleavedVBOCurrent ? interleavedVBOCurrent : interleavedVBOLeft; + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(null == mPlayer) { return; } + + if( resetGLState ) { + resetGLState = false; + System.err.println("XXX resetGLState"); + disposeImpl(drawable, false); + init(drawable); + reshape(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + } + + final long currentPos = System.currentTimeMillis(); + if( currentPos - lastPerfPos > 2000 ) { + System.err.println( mPlayer.getPerfString() ); + lastPerfPos = currentPos; + } + + if( !dontClear ) { + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + } + + if(null == st) { + return; + } + + st.useProgram(gl, true); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glPushMatrix(); + pmvMatrix.glTranslatef(0, 0, zoom); + if( rotate > 0) { + final float ang = ((System.currentTimeMillis() - startTime) * 360.0f) / 8000.0f; + pmvMatrix.glRotatef(ang, 0, 0, 1); + } else { + rotate = 0; + } + st.uniform(gl, pmvMatrixUniform); + iVBO.enableBuffer(gl, true); + Texture tex = null; + if(null!=mPlayer) { + final TextureSequence.TextureFrame texFrame; + if( repeatedFrame ) { + texFrame=mPlayer.getLastTexture(); + } else { + texFrame=mPlayer.getNextTexture(gl); + } + if(null != texFrame) { + tex = texFrame.getTexture(); + gl.glActiveTexture(GL.GL_TEXTURE0+mPlayer.getTextureUnit()); + tex.enable(gl); + tex.bind(gl); + } + } + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + if(null != tex) { + tex.disable(gl); + } + iVBO.enableBuffer(gl, false); + st.useProgram(gl, false); + pmvMatrix.glPopMatrix(); + + if( null != textRendererGLEL ) { + textRendererGLEL.display(drawable); + } + } + + static class StereoGLMediaEventListener implements GLMediaEventListener { + void destroyWindow(final Window window) { + new InterruptSource.Thread() { + @Override + public void run() { + window.destroy(); + } }.start(); + } + + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { + } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieSimple AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieSimple State: "+mp); + final GLWindow window = (GLWindow) mp.getAttachedObject(WINDOW_KEY); + final MovieSBSStereo ms = (MovieSBSStereo)mp.getAttachedObject(PLAYER); + final StereoClientRenderer stereoClientRenderer = (StereoClientRenderer) mp.getAttachedObject(STEREO_RENDERER_KEY); + + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_SIZE & event_mask ) ) { + System.err.println("MovieSimple State: CHANGE_SIZE"); + // window.disposeGLEventListener(ms, false /* remove */ ); + ms.resetGLState(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + System.err.println("MovieSimple State: INIT"); + // Use GLEventListener in all cases [A+V, V, A] + stereoClientRenderer.addGLEventListener(ms); + final GLAnimatorControl anim = window.getAnimator(); + anim.setUpdateFPSFrames(60, null); + anim.resetFPSCounter(); + ms.setStereoClientRenderer(stereoClientRenderer); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_PLAY & event_mask ) ) { + window.getAnimator().resetFPSCounter(); + } + + boolean destroy = false; + Throwable err = null; + + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { + err = ms.mPlayer.getStreamException(); + if( null != err ) { + System.err.println("MovieSimple State: EOS + Exception"); + destroy = true; + } else { + System.err.println("MovieSimple State: EOS"); + new InterruptSource.Thread() { + @Override + public void run() { + mp.setPlaySpeed(1f); + mp.seek(0); + mp.play(); + } + }.start(); + } + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_ERR & event_mask ) ) { + err = ms.mPlayer.getStreamException(); + if( null != err ) { + System.err.println("MovieSimple State: ERR + Exception"); + } else { + System.err.println("MovieSimple State: ERR"); + } + destroy = true; + } + if( destroy ) { + if( null != err ) { + err.printStackTrace(); + } + destroyWindow(window); + } + } + }; + public final static StereoGLMediaEventListener stereoGLMediaEventListener = new StereoGLMediaEventListener(); +} diff --git a/src/demos/com/jogamp/opengl/demos/av/MovieSimple.java b/src/demos/com/jogamp/opengl/demos/av/MovieSimple.java new file mode 100644 index 000000000..42c7b94a5 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/av/MovieSimple.java @@ -0,0 +1,1123 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.av; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.FloatBuffer; + +import com.jogamp.common.net.Uri; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +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.FontScale; +import com.jogamp.junit.util.JunitTracer; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLES2; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLExtensions; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.GLUniformData; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.graph.TextRendererGLELBase; +import com.jogamp.opengl.demos.util.MiscUtils; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.GLReadBufferUtil; +import com.jogamp.opengl.util.PMVMatrix; +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.av.GLMediaPlayerFactory; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureCoords; +import com.jogamp.opengl.util.texture.TextureSequence; +import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; + +/** + * Simple planar movie player w/ orthogonal 1:1 projection. + */ +public class MovieSimple implements GLEventListener { + public static final int EFFECT_NORMAL = 0; + public static final int EFFECT_GRADIENT_BOTTOM2TOP = 1<<1; + public static final int EFFECT_TRANSPARENT = 1<<3; + + public static final String WINDOW_KEY = "window"; + public static final String PLAYER = "player"; + + private static boolean waitForKey = false; + private int surfWidth, surfHeight; + private int prevMouseX; // , prevMouseY; + private int rotate = 0; + private boolean orthoProjection = true; + private float nearPlaneNormalized; + private float zoom0; + private float zoom1; + private float zoom; + private long startTime; + private int effects = EFFECT_NORMAL; + private float alpha = 1.0f; + private int swapInterval = 1; + private boolean swapIntervalSet = true; + + private GLMediaPlayer mPlayer; + private final boolean mPlayerShared; + private boolean mPlayerScaleOrig; + private float[] verts = null; + private GLArrayDataServer interleavedVBO; + private volatile boolean resetGLState = false; + + private volatile GLAutoDrawable autoDrawable = null; + + private ShaderState st; + private PMVMatrix pmvMatrix; + private GLUniformData pmvMatrixUniform; + private static final String shaderBasename = "texsequence_xxx"; + private static final String myTextureLookupName = "myTexture2D"; + + /** Blender's Big Buck Bunny: 24f 416p H.264, AAC 48000 Hz, 2 ch, mpeg stream. */ + public static final Uri defURI; + static { + Uri _defURI = null; + try { + // Blender's Big Buck Bunny Trailer: 24f 640p VP8, Vorbis 44100Hz mono, WebM/Matroska Stream. + // _defURI = new URI("http://video.webmfiles.org/big-buck-bunny_trailer.webm"); + _defURI = Uri.cast("http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"); + } catch (final URISyntaxException e) { + e.printStackTrace(); + } + defURI = _defURI; + } + + final int[] textSampleCount = { 4 }; + + private final class InfoTextRendererGLELBase extends TextRendererGLELBase { + private final Font font = getFont(0, 0, 0); + private final float fontSize = 10f; + private final GLRegion regionFPS; + + InfoTextRendererGLELBase(final GLProfile glp, final int rmode, final boolean lowPerfDevice) { + // FIXME: Graph TextRenderer does not AA well w/o MSAA and FBO + super(rmode, textSampleCount); + this.setRendererCallbacks(RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + if( lowPerfDevice ) { + regionFPS = null; + } else { + regionFPS = GLRegion.create(glp, renderModes, null); + System.err.println("RegionFPS "+Region.getRenderModeString(renderModes)+", sampleCount "+textSampleCount[0]+", class "+regionFPS.getClass().getName()); + } + staticRGBAColor[0] = 0.9f; + staticRGBAColor[1] = 0.9f; + staticRGBAColor[2] = 0.9f; + staticRGBAColor[3] = 1.0f; + } + + @Override + public void init(final GLAutoDrawable drawable) { + super.init(drawable); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + if( null != regionFPS ) { + regionFPS.destroy(drawable.getGL().getGL2ES2()); + } + super.dispose(drawable); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GLAnimatorControl anim = drawable.getAnimator(); + final float lfps = null != anim ? anim.getLastFPS() : 0f; + final float tfps = null != anim ? anim.getTotalFPS() : 0f; + final boolean hasVideo = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID(); + final float pts = ( hasVideo ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS() ) / 1000f; + + // Note: MODELVIEW is from [ 0 .. height ] + + final int height = drawable.getSurfaceHeight(); + + final float aspect = (float)mPlayer.getWidth() / (float)mPlayer.getHeight(); + + final String ptsPrec = null != regionFPS ? "3.1" : "3.0"; + final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f, v-sync %b", + pts, mPlayer.getDuration() / 1000f, + mPlayer.getState().toString().toLowerCase(), mPlayer.getPlaySpeed(), mPlayer.getAudioVolume(), + aspect, mPlayer.getFramerate(), lfps, tfps, swapIntervalSet); + final String text2 = String.format("audio: id %d, kbps %d, codec %s", + mPlayer.getAID(), mPlayer.getAudioBitrate()/1000, mPlayer.getAudioCodec()); + final String text3 = String.format("video: id %d, kbps %d, codec %s", + mPlayer.getVID(), mPlayer.getVideoBitrate()/1000, mPlayer.getVideoCodec()); + final String text4 = mPlayer.getUri().path.decode(); + if( displayOSD && null != renderer ) { + // We share ClearColor w/ MovieSimple's init ! + final float pixelSize = FontScale.toPixels(fontSize, dpiH); + if( null != regionFPS ) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + renderString(drawable, font, pixelSize, text1, 1 /* col */, 1 /* row */, 0, 0, -1, regionFPS.clear(gl)); // no-cache + } else { + renderString(drawable, font, pixelSize, text1, 1 /* col */, 1 /* row */, 0, 0, -1, true); + } + renderString(drawable, font, pixelSize, text2, 1 /* col */, -4 /* row */, 0, height, -1, true); + renderString(drawable, font, pixelSize, text3, 1 /* col */, -3 /* row */, 0, height, -1, true); + renderString(drawable, font, pixelSize, text4, 1 /* col */, -2 /* row */, 0, height, -1, true); + } + } }; + private InfoTextRendererGLELBase textRendererGLEL = null; + private boolean displayOSD = true; + + public void printScreen(final GLAutoDrawable drawable) throws GLException, IOException { + final String filename = String.format("MovieSimple-snap%02d-%03dx%03d.png", screenshot_num++, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + if(screenshot.readPixels(drawable.getGL(), false)) { + screenshot.write(new File(filename.toString())); + } + } + private final GLReadBufferUtil screenshot; + private int screenshot_num = 0; + + public void printScreenOnGLThread(final GLAutoDrawable drawable) { + drawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + try { + printScreen(drawable); + } catch (final GLException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } + return true; + } + }); + } + + private final MouseListener mouseAction = new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + if(e.getY()<=surfHeight/2 && null!=mPlayer && 1 == e.getClickCount()) { + if(GLMediaPlayer.State.Playing == mPlayer.getState()) { + mPlayer.pause(false); + } else { + mPlayer.play(); + } + } + } + @Override + public void mouseReleased(final MouseEvent e) { + if(e.getY()<=surfHeight/2) { + rotate = -1; + zoom = zoom0; + System.err.println("zoom: "+zoom); + } + } + @Override + public void mouseMoved(final MouseEvent e) { + prevMouseX = e.getX(); + // prevMouseY = e.getY(); + } + @Override + public void mouseDragged(final MouseEvent e) { + final int x = e.getX(); + final int y = e.getY(); + + if(y>surfHeight/2) { + final float dp = (float)(x-prevMouseX)/(float)surfWidth; + final int pts0 = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID() ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS(); + mPlayer.seek(pts0 + (int) (mPlayer.getDuration() * dp)); + } else { + mPlayer.play(); + rotate = 1; + zoom = zoom1; + } + + prevMouseX = x; + // prevMouseY = y; + } + @Override + public void mouseWheelMoved(final MouseEvent e) { + if( !e.isShiftDown() ) { + zoom += e.getRotation()[1]/10f; // vertical: wheel + System.err.println("zoom: "+zoom); + } + } }; + + private final KeyListener keyAction = new KeyAdapter() { + @Override + public void keyReleased(final KeyEvent e) { + if( e.isAutoRepeat() ) { + return; + } + System.err.println("MC "+e); + final int pts0 = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID() ? mPlayer.getVideoPTS() : mPlayer.getAudioPTS(); + int pts1 = 0; + switch(e.getKeySymbol()) { + case KeyEvent.VK_V: { + switch(swapInterval) { + case 0: swapInterval = -1; break; + case -1: swapInterval = 1; break; + case 1: swapInterval = 0; break; + default: swapInterval = 1; break; + } + swapIntervalSet = true; + break; + } + case KeyEvent.VK_O: displayOSD = !displayOSD; break; + case KeyEvent.VK_RIGHT: pts1 = pts0 + 1000; break; + case KeyEvent.VK_UP: pts1 = pts0 + 10000; break; + case KeyEvent.VK_PAGE_UP: pts1 = pts0 + 30000; break; + case KeyEvent.VK_LEFT: pts1 = pts0 - 1000; break; + case KeyEvent.VK_DOWN: pts1 = pts0 - 10000; break; + case KeyEvent.VK_PAGE_DOWN: pts1 = pts0 - 30000; break; + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_HOME: + case KeyEvent.VK_BACK_SPACE: { + mPlayer.seek(0); + break; + } + case KeyEvent.VK_SPACE: { + if(GLMediaPlayer.State.Paused == mPlayer.getState()) { + mPlayer.play(); + } else { + mPlayer.pause(false); + } + break; + } + case KeyEvent.VK_MULTIPLY: + mPlayer.setPlaySpeed(1.0f); + break; + case KeyEvent.VK_SUBTRACT: { + float playSpeed = mPlayer.getPlaySpeed(); + if( e.isShiftDown() ) { + playSpeed /= 2.0f; + } else { + playSpeed -= 0.1f; + } + mPlayer.setPlaySpeed(playSpeed); + } break; + case KeyEvent.VK_ADD: { + float playSpeed = mPlayer.getPlaySpeed(); + if( e.isShiftDown() ) { + playSpeed *= 2.0f; + } else { + playSpeed += 0.1f; + } + mPlayer.setPlaySpeed(playSpeed); + } break; + case KeyEvent.VK_M: { + float audioVolume = mPlayer.getAudioVolume(); + if( audioVolume > 0.5f ) { + audioVolume = 0f; + } else { + audioVolume = 1f; + } + mPlayer.setAudioVolume(audioVolume); + } break; + case KeyEvent.VK_S: + if(null != autoDrawable) { + printScreenOnGLThread(autoDrawable); + } + break; + } + + if( 0 != pts1 ) { + mPlayer.seek(pts1); + } + } }; + + /** + * Default constructor which also issues {@link #initStream(URI, int, int, int)} w/ default values + * and polls until the {@link GLMediaPlayer} is {@link GLMediaPlayer.State#Initialized}. + * If {@link GLMediaEventListener#EVENT_CHANGE_EOS} is reached, the stream is started over again. + * <p> + * This default constructor is merely useful for some <i>drop-in</i> test, e.g. using an applet. + * </p> + */ + public MovieSimple() { + this(null); + + mPlayer.addEventListener(new GLMediaEventListener() { + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieCube AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieCube State: "+mp); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_SIZE & event_mask ) ) { + resetGLState(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { + new InterruptSource.Thread() { + @Override + public void run() { + // loop for-ever .. + mPlayer.seek(0); + mPlayer.play(); + } }.start(); + } + } + }); + initStream(defURI, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 3 /* textureCount */); + StreamException se = null; + while( null == se && GLMediaPlayer.State.Initialized != mPlayer.getState() ) { + try { + Thread.sleep(16); + } catch (final InterruptedException e) { } + se = mPlayer.getStreamException(); + } + if( null != se ) { + se.printStackTrace(); + throw new RuntimeException(se); + } + } + + /** Custom constructor, user needs to issue {@link #initStream(URI, int, int, int)} afterwards. */ + public MovieSimple(final GLMediaPlayer sharedMediaPlayer) throws IllegalStateException { + screenshot = new GLReadBufferUtil(false, false); + mPlayer = sharedMediaPlayer; + mPlayerScaleOrig = false; + mPlayerShared = null != mPlayer; + if( !mPlayerShared ) { + mPlayer = GLMediaPlayerFactory.createDefault(); + mPlayer.attachObject(PLAYER, this); + } + System.out.println("pC.1a shared "+mPlayerShared+", "+mPlayer); + } + + public void initStream(final Uri streamLoc, final int vid, final int aid, final int textureCount) { + mPlayer.initStream(streamLoc, vid, aid, textureCount); + System.out.println("pC.1b "+mPlayer); + } + + public void setSwapInterval(final int v) { this.swapInterval = v; } + + public GLMediaPlayer getGLMediaPlayer() { return mPlayer; } + + public void setScaleOrig(final boolean v) { + mPlayerScaleOrig = v; + } + + /** defaults to true */ + public void setOrthoProjection(final boolean v) { orthoProjection=v; } + public boolean getOrthoProjection() { return orthoProjection; } + + public boolean hasEffect(final int e) { return 0 != ( effects & e ) ; } + public void setEffects(final int e) { effects = e; }; + public void setTransparency(final float alpha) { + this.effects |= EFFECT_TRANSPARENT; + this.alpha = alpha; + } + + public void resetGLState() { + resetGLState = true; + } + + private void initShader(final GL2ES2 gl) { + // Create & Compile the shader objects + final ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, MovieSimple.class, + "../shader", "../shader/bin", shaderBasename, true); + final ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, MovieSimple.class, + "../shader", "../shader/bin", shaderBasename, true); + + boolean preludeGLSLVersion = true; + if( GLES2.GL_TEXTURE_EXTERNAL_OES == mPlayer.getTextureTarget() ) { + if( !gl.isExtensionAvailable(GLExtensions.OES_EGL_image_external) ) { + throw new GLException(GLExtensions.OES_EGL_image_external+" requested but not available"); + } + if( Platform.OSType.ANDROID == Platform.getOSType() && gl.isGLES3() ) { + // Bug on Nexus 10, ES3 - Android 4.3, where + // GL_OES_EGL_image_external extension directive leads to a failure _with_ '#version 300 es' ! + // P0003: Extension 'GL_OES_EGL_image_external' not supported + preludeGLSLVersion = false; + } + } + rsVp.defaultShaderCustomization(gl, preludeGLSLVersion, true); + + int rsFpPos = preludeGLSLVersion ? rsFp.addGLSLVersion(gl) : 0; + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, mPlayer.getRequiredExtensionsShaderStub()); + rsFp.addDefaultShaderPrecision(gl, rsFpPos); + + final String texLookupFuncName = mPlayer.getTextureLookupFunctionName(myTextureLookupName); + rsFp.replaceInShaderSource(myTextureLookupName, texLookupFuncName); + + // Inject TextureSequence shader details + final StringBuilder sFpIns = new StringBuilder(); + sFpIns.append("uniform ").append(mPlayer.getTextureSampler2DType()).append(" mgl_ActiveTexture;\n"); + sFpIns.append(mPlayer.getTextureLookupFragmentShaderImpl()); + rsFp.insertShaderSource(0, "TEXTURE-SEQUENCE-CODE-BEGIN", 0, sFpIns); + + // Create & Link the shader program + final ShaderProgram sp = new ShaderProgram(); + sp.add(rsVp); + sp.add(rsFp); + if(!sp.link(gl, System.err)) { + throw new GLException("Couldn't link program: "+sp); + } + + // Let's manage all our states using ShaderState. + st = new ShaderState(); + st.attachShaderProgram(gl, sp, false); + } + + @Override + public void init(final GLAutoDrawable drawable) { + if(null == mPlayer) { + throw new InternalError("mPlayer null"); + } + if( GLMediaPlayer.State.Uninitialized == mPlayer.getState() ) { + throw new IllegalStateException("mPlayer in uninitialized state: "+mPlayer); + } + final boolean hasVideo = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID(); + resetGLState = false; + + zoom0 = orthoProjection ? 0f : -2.5f; + zoom1 = orthoProjection ? 0f : -5f; + zoom = zoom0; + + autoDrawable = drawable; + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + System.err.println(JoglVersion.getGLInfo(gl, null)); + System.err.println("Alpha: "+alpha+", opaque "+drawable.getChosenGLCapabilities().isBackgroundOpaque()+ + ", "+drawable.getClass().getName()+", "+drawable); + + if(waitForKey) { + JunitTracer.waitForKey("Init>"); + } + final Texture tex; + try { + System.out.println("p0 "+mPlayer+", shared "+mPlayerShared); + if(!mPlayerShared && GLMediaPlayer.State.Initialized == mPlayer.getState() ) { + mPlayer.initGL(gl); + } + System.out.println("p1 "+mPlayer+", shared "+mPlayerShared); + final TextureFrame frame = mPlayer.getLastTexture(); + if( null != frame ) { + if( !hasVideo ) { + throw new InternalError("XXX: "+mPlayer); + } + tex = frame.getTexture(); + if( null == tex ) { + throw new InternalError("XXX: "+mPlayer); + } + } else { + tex = null; + if( hasVideo ) { + throw new InternalError("XXX: "+mPlayer); + } + } + if(!mPlayerShared) { + mPlayer.setTextureMinMagFilter( new int[] { GL.GL_NEAREST, GL.GL_LINEAR } ); + } + } catch (final Exception glex) { + glex.printStackTrace(); + if(!mPlayerShared && null != mPlayer) { + mPlayer.destroy(gl); + mPlayer = null; + } + throw new GLException(glex); + } + + if( hasVideo ) { + initShader(gl); + + // Push the 1st uniform down the path + st.useProgram(gl, true); + + final int[] viewPort = new int[] { 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()}; + pmvMatrix = new PMVMatrix(); + reshapePMV(viewPort[2], viewPort[3]); + pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); + if(!st.uniform(gl, pmvMatrixUniform)) { + throw new GLException("Error setting PMVMatrix in shader: "+st); + } + if(!st.uniform(gl, new GLUniformData("mgl_ActiveTexture", mPlayer.getTextureUnit()))) { + throw new GLException("Error setting mgl_ActiveTexture in shader: "+st); + } + + final float dWidth = drawable.getSurfaceWidth(); + final float dHeight = drawable.getSurfaceHeight(); + final float mWidth = mPlayer.getWidth(); + final float mHeight = mPlayer.getHeight(); + final float mAspect = mWidth/mHeight; + System.err.println("XXX0: mov aspect: "+mAspect); + float xs, ys; + if(orthoProjection) { + if(mPlayerScaleOrig && mWidth < dWidth && mHeight < dHeight) { + xs = mWidth/2f; ys = xs / mAspect; + } else { + xs = dWidth/2f; ys = xs / mAspect; // w>h + } + } else { + if(mPlayerScaleOrig && mWidth < dWidth && mHeight < dHeight) { + xs = mAspect * ( mWidth / dWidth ) ; ys = xs / mAspect ; + } else { + xs = mAspect; ys = 1f; // b>h + } + } + verts = new float[] { -1f*xs, -1f*ys, 0f, // LB + 1f*xs, 1f*ys, 0f // RT + }; + { + System.err.println("XXX0: pixel LB: "+verts[0]+", "+verts[1]+", "+verts[2]); + System.err.println("XXX0: pixel RT: "+verts[3]+", "+verts[4]+", "+verts[5]); + final float[] winLB = new float[3]; + final float[] winRT = new float[3]; + pmvMatrix.gluProject(verts[0], verts[1], verts[2], viewPort, 0, winLB, 0); + pmvMatrix.gluProject(verts[3], verts[4], verts[5], viewPort, 0, winRT, 0); + System.err.println("XXX0: win LB: "+winLB[0]+", "+winLB[1]+", "+winLB[2]); + System.err.println("XXX0: win RT: "+winRT[0]+", "+winRT[1]+", "+winRT[2]); + } + + interleavedVBO = GLArrayDataServer.createGLSLInterleaved(3+4+2, GL.GL_FLOAT, false, 3*4, GL.GL_STATIC_DRAW); + { + interleavedVBO.addGLSLSubArray("mgl_Vertex", 3, GL.GL_ARRAY_BUFFER); + interleavedVBO.addGLSLSubArray("mgl_Color", 4, GL.GL_ARRAY_BUFFER); + interleavedVBO.addGLSLSubArray("mgl_MultiTexCoord", 2, GL.GL_ARRAY_BUFFER); + } + updateInterleavedVBO(gl, tex); + + st.ownAttribute(interleavedVBO, true); + gl.glClearColor(0.3f, 0.3f, 0.3f, 0.3f); + + gl.glEnable(GL.GL_DEPTH_TEST); + + st.useProgram(gl, false); + + // Let's show the completed shader state .. + System.out.println("iVBO: "+interleavedVBO); + System.out.println(st); + } + + if(!mPlayerShared) { + mPlayer.play(); + System.out.println("play.0 "+mPlayer); + } + startTime = System.currentTimeMillis(); + + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.addMouseListener(mouseAction); + window.addKeyListener(keyAction); + surfWidth = window.getSurfaceWidth(); + surfHeight = window.getSurfaceHeight(); + } + final int rmode = drawable.getChosenGLCapabilities().getSampleBuffers() ? 0 : Region.VBAA_RENDERING_BIT; + final boolean lowPerfDevice = gl.isGLES(); + textRendererGLEL = new InfoTextRendererGLELBase(gl.getGLProfile(), rmode, lowPerfDevice); + drawable.addGLEventListener(textRendererGLEL); + } + + protected void updateInterleavedVBO(final GL gl, final Texture tex) { + final float ss = 1f, ts = 1f; // scale tex-coord + final boolean wasEnabled = interleavedVBO.enabled(); + interleavedVBO.seal(gl, false); + interleavedVBO.rewind(); + { + final FloatBuffer ib = (FloatBuffer)interleavedVBO.getBuffer(); + final TextureCoords tc = tex.getImageTexCoords(); + System.err.println("XXX0: "+tc); + System.err.println("XXX0: tex aspect: "+tex.getAspectRatio()); + System.err.println("XXX0: tex y-flip: "+tex.getMustFlipVertically()); + + // left-bottom + ib.put(verts[0]); ib.put(verts[1]); ib.put(verts[2]); + if( hasEffect(EFFECT_GRADIENT_BOTTOM2TOP) ) { + ib.put( 0); ib.put( 0); ib.put( 0); ib.put(alpha); + } else { + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + } + ib.put( tc.left() *ss); ib.put( tc.bottom() *ts); + + // right-bottom + ib.put(verts[3]); ib.put(verts[1]); ib.put(verts[2]); + if( hasEffect(EFFECT_GRADIENT_BOTTOM2TOP) ) { + ib.put( 0); ib.put( 0); ib.put( 0); ib.put(alpha); + } else { + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + } + ib.put( tc.right() *ss); ib.put( tc.bottom() *ts); + + // left-top + ib.put(verts[0]); ib.put(verts[4]); ib.put(verts[2]); + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + ib.put( tc.left() *ss); ib.put( tc.top() *ts); + + // right-top + ib.put(verts[3]); ib.put(verts[4]); ib.put(verts[2]); + ib.put( 1); ib.put( 1); ib.put( 1); ib.put(alpha); + ib.put( tc.right() *ss); ib.put( tc.top() *ts); + } + interleavedVBO.seal(gl, true); + if( !wasEnabled ) { + interleavedVBO.enableBuffer(gl, false); + } + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(null == mPlayer) { return; } + surfWidth = width; + surfHeight = height; + + if(null != st) { + reshapePMV(width, height); + st.useProgram(gl, true); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + } + + System.out.println("pR "+mPlayer); + } + + private final float zNear = 1f; + private final float zFar = 10f; + + private void reshapePMV(final int width, final int height) { + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + if(orthoProjection) { + final float fw = width / 2f; + final float fh = height/ 2f; + pmvMatrix.glOrthof(-fw, fw, -fh, fh, -1.0f, 1.0f); + nearPlaneNormalized = 0f; + } else { + pmvMatrix.gluPerspective(45.0f, (float)width / (float)height, zNear, zFar); + nearPlaneNormalized = 1f/(10f-1f); + } + System.err.println("XXX0: Perspective nearPlaneNormalized: "+nearPlaneNormalized); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, zoom0); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + autoDrawable = null; + drawable.disposeGLEventListener(textRendererGLEL, true); + textRendererGLEL = null; + screenshot.dispose(drawable.getGL()); + disposeImpl(drawable, true); + } + + private void disposeImpl(final GLAutoDrawable drawable, final boolean disposePlayer) { + if(null == mPlayer) { return; } + + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.removeMouseListener(mouseAction); + window.removeKeyListener(keyAction); + } + + System.out.println("pD.1 "+mPlayer+", disposePlayer "+disposePlayer); + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if( disposePlayer ) { + if(!mPlayerShared) { + mPlayer.destroy(gl); + } + System.out.println("pD.X "+mPlayer); + mPlayer=null; + } + pmvMatrixUniform = null; + if(null != pmvMatrix) { + pmvMatrix=null; + } + if(null != st) { + st.destroy(gl); + st=null; + } + } + + long lastPerfPos = 0; + + @Override + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if( swapIntervalSet ) { + final int _swapInterval = swapInterval; + gl.setSwapInterval(_swapInterval); // in case switching the drawable (impl. may bound attribute there) + drawable.getAnimator().resetFPSCounter(); + swapInterval = gl.getSwapInterval(); + System.err.println("Swap Interval: "+_swapInterval+" -> "+swapInterval); + swapIntervalSet = false; + } + if(null == mPlayer) { return; } + + if( resetGLState ) { + resetGLState = false; + System.err.println("XXX resetGLState"); + disposeImpl(drawable, false); + init(drawable); + reshape(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + } + + final long currentPos = System.currentTimeMillis(); + if( currentPos - lastPerfPos > 2000 ) { + System.err.println( mPlayer.getPerfString() ); + lastPerfPos = currentPos; + } + + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + if(null == st) { + return; + } + + st.useProgram(gl, true); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, zoom); + if(rotate > 0) { + final float ang = ((System.currentTimeMillis() - startTime) * 360.0f) / 8000.0f; + pmvMatrix.glRotatef(ang, 0, 0, 1); + } else { + rotate = 0; + } + st.uniform(gl, pmvMatrixUniform); + interleavedVBO.enableBuffer(gl, true); + Texture tex = null; + if(null!=mPlayer) { + final TextureSequence.TextureFrame texFrame; + if( mPlayerShared ) { + texFrame=mPlayer.getLastTexture(); + } else { + texFrame=mPlayer.getNextTexture(gl); + } + if(null != texFrame) { + tex = texFrame.getTexture(); + gl.glActiveTexture(GL.GL_TEXTURE0+mPlayer.getTextureUnit()); + tex.enable(gl); + tex.bind(gl); + } + } + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + if(null != tex) { + tex.disable(gl); + } + interleavedVBO.enableBuffer(gl, false); + st.useProgram(gl, false); + } + + static class MyGLMediaEventListener implements GLMediaEventListener { + void destroyWindow(final Window window) { + new InterruptSource.Thread() { + @Override + public void run() { + window.destroy(); + } }.start(); + } + + @Override + public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { + } + + @Override + public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) { + System.err.println("MovieSimple AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when); + System.err.println("MovieSimple State: "+mp); + final GLWindow window = (GLWindow) mp.getAttachedObject(WINDOW_KEY); + final MovieSimple ms = (MovieSimple)mp.getAttachedObject(PLAYER); + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_SIZE & event_mask ) ) { + System.err.println("MovieSimple State: CHANGE_SIZE"); + if( origSize ) { + window.setSurfaceSize(mp.getWidth(), mp.getHeight()); + } + // window.disposeGLEventListener(ms, false /* remove */ ); + ms.resetGLState(); + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) { + System.err.println("MovieSimple State: INIT"); + // Use GLEventListener in all cases [A+V, V, A] + window.addGLEventListener(ms); + final GLAnimatorControl anim = window.getAnimator(); + anim.setUpdateFPSFrames(60, null); + anim.resetFPSCounter(); + /** + * Kick off player w/o GLEventListener, i.e. for audio only. + * + new InterruptSource.Thread() { + public void run() { + try { + mp.initGL(null); + if ( GLMediaPlayer.State.Paused == mp.getState() ) { // init OK + mp.play(); + } + System.out.println("play.1 "+mp); + } catch (Exception e) { + e.printStackTrace(); + destroyWindow(); + return; + } + } + }.start(); + */ + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_PLAY & event_mask ) ) { + window.getAnimator().resetFPSCounter(); + } + + boolean destroy = false; + Throwable err = null; + + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { + err = ms.mPlayer.getStreamException(); + if( null != err ) { + System.err.println("MovieSimple State: EOS + Exception"); + destroy = true; + } else { + System.err.println("MovieSimple State: EOS"); + if( loopEOS ) { + new InterruptSource.Thread() { + @Override + public void run() { + mp.setPlaySpeed(1f); + mp.seek(0); + mp.play(); + } + }.start(); + } else { + destroy = true; + } + } + } + if( 0 != ( GLMediaEventListener.EVENT_CHANGE_ERR & event_mask ) ) { + err = ms.mPlayer.getStreamException(); + if( null != err ) { + System.err.println("MovieSimple State: ERR + Exception"); + } else { + System.err.println("MovieSimple State: ERR"); + } + destroy = true; + } + if( destroy ) { + if( null != err ) { + err.printStackTrace(); + } + destroyWindow(window); + } + } + }; + public final static MyGLMediaEventListener myGLMediaEventListener = new MyGLMediaEventListener(); + + static boolean loopEOS = false; + static boolean origSize; + + public static void main(final String[] args) throws IOException, URISyntaxException { + int swapInterval = 1; + int width = 800; + int height = 600; + int textureCount = 3; // default - threaded + boolean ortho = true; + boolean zoom = false; + + boolean forceES2 = false; + boolean forceES3 = false; + boolean forceGL3 = false; + boolean forceGLDef = false; + int vid = GLMediaPlayer.STREAM_ID_AUTO; + int aid = GLMediaPlayer.STREAM_ID_AUTO; + + final int windowCount; + { + int _windowCount = 1; + for(int i=0; i<args.length; i++) { + if(args[i].equals("-windows")) { + i++; + _windowCount = MiscUtils.atoi(args[i], _windowCount); + } + } + windowCount = _windowCount; + } + final String[] urls_s = new String[windowCount]; + String file_s1=null, file_s2=null; + { + boolean _origSize = false; + for(int i=0; i<args.length; i++) { + if(args[i].equals("-vid")) { + i++; + vid = MiscUtils.atoi(args[i], vid); + } else if(args[i].equals("-aid")) { + i++; + aid = MiscUtils.atoi(args[i], aid); + } else if(args[i].equals("-width")) { + i++; + width = MiscUtils.atoi(args[i], width); + } else if(args[i].equals("-height")) { + i++; + height = MiscUtils.atoi(args[i], height); + } else if(args[i].equals("-osize")) { + _origSize = true; + } else if(args[i].equals("-textureCount")) { + i++; + textureCount = MiscUtils.atoi(args[i], textureCount); + } else if(args[i].equals("-es2")) { + forceES2 = true; + } else if(args[i].equals("-es3")) { + forceES3 = true; + } else if(args[i].equals("-gl3")) { + forceGL3 = true; + } else if(args[i].equals("-gldef")) { + forceGLDef = true; + } else if(args[i].equals("-vsync")) { + i++; + swapInterval = MiscUtils.atoi(args[i], swapInterval); + } else if(args[i].equals("-projection")) { + ortho=false; + } else if(args[i].equals("-zoom")) { + zoom=true; + } else if(args[i].equals("-loop")) { + loopEOS=true; + } else if(args[i].equals("-urlN")) { + i++; + final int n = MiscUtils.atoi(args[i], 0); + i++; + urls_s[n] = args[i]; + } else if(args[i].equals("-url")) { + i++; + urls_s[0] = args[i]; + } else if(args[i].equals("-file1")) { + i++; + file_s1 = args[i]; + } else if(args[i].equals("-file2")) { + i++; + file_s2 = args[i]; + } else if(args[i].equals("-wait")) { + waitForKey = true; + } + } + origSize = _origSize; + } + final Uri streamLoc0; + if( null != urls_s[0] ) { + streamLoc0 = Uri.cast( urls_s[0] ); + } else if( null != file_s1 ) { + final File movieFile = new File(file_s1); + streamLoc0 = Uri.valueOf(movieFile); + } else if( null != file_s2 ) { + streamLoc0 = Uri.valueOf(new File(file_s2)); + } else { + streamLoc0 = defURI; + } + System.err.println("url_s "+urls_s[0]); + System.err.println("file_s 1: "+file_s1+", 2: "+file_s2); + System.err.println("stream0 "+streamLoc0); + System.err.println("vid "+vid+", aid "+aid); + System.err.println("textureCount "+textureCount); + System.err.println("forceES2 "+forceES2); + System.err.println("forceES3 "+forceES3); + System.err.println("forceGL3 "+forceGL3); + System.err.println("forceGLDef "+forceGLDef); + System.err.println("swapInterval "+swapInterval); + + final GLProfile glp; + if(forceGLDef) { + glp = GLProfile.getDefault(); + } else if(forceGL3) { + glp = GLProfile.get(GLProfile.GL3); + } else if(forceES3) { + glp = GLProfile.get(GLProfile.GLES3); + } else if(forceES2) { + glp = GLProfile.get(GLProfile.GLES2); + } else { + glp = GLProfile.getGL2ES2(); + } + System.err.println("GLProfile: "+glp); + final GLCapabilities caps = new GLCapabilities(glp); + // caps.setAlphaBits(4); // NOTE_ALPHA_BLENDING: We go w/o alpha and blending! + + final MovieSimple[] mss = new MovieSimple[windowCount]; + final GLWindow[] windows = new GLWindow[windowCount]; + for(int i=0; i<windowCount; i++) { + final Animator anim = new Animator(); + anim.start(); + windows[i] = GLWindow.create(caps); + windows[i].addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyed(final WindowEvent e) { + anim.stop(); + } + }); + mss[i] = new MovieSimple(null); + mss[i].setSwapInterval(swapInterval); + mss[i].setScaleOrig(!zoom); + mss[i].setOrthoProjection(ortho); + mss[i].mPlayer.attachObject(WINDOW_KEY, windows[i]); + mss[i].mPlayer.addEventListener(myGLMediaEventListener); + + windows[i].setTitle("Player "+i); + windows[i].setSize(width, height); + windows[i].setVisible(true); + anim.add(windows[i]); + + final Uri streamLocN; + if( 0 == i ) { + streamLocN = streamLoc0; + } else { + if( null != urls_s[i] ) { + streamLocN = Uri.cast(urls_s[i]); + } else { + streamLocN = defURI; + } + } + System.err.println("Win #"+i+": stream "+streamLocN); + mss[i].initStream(streamLocN, vid, aid, textureCount); + } + } + +} diff --git a/src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java b/src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java new file mode 100644 index 000000000..88a49a09a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java @@ -0,0 +1,403 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.av; + +import java.io.File; +import java.net.URISyntaxException; +import java.util.Arrays; + +import com.jogamp.nativewindow.util.DimensionImmutable; +import com.jogamp.nativewindow.util.PointImmutable; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.demos.es2.GearsES2; +import com.jogamp.opengl.demos.util.MiscUtils; +import com.jogamp.opengl.demos.util.QuitAdapter; + +import jogamp.opengl.util.stereo.GenericStereoDevice; + +import com.jogamp.common.net.Uri; +import com.jogamp.newt.MonitorDevice; +import com.jogamp.newt.Screen; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.opengl.util.stereo.StereoDeviceUtil; +import com.jogamp.opengl.math.FovHVHalves; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.AnimatorBase; +import com.jogamp.opengl.util.av.GLMediaPlayer; +import com.jogamp.opengl.util.stereo.StereoDevice; +import com.jogamp.opengl.util.stereo.StereoDeviceRenderer; +import com.jogamp.opengl.util.stereo.StereoDeviceFactory; +import com.jogamp.opengl.util.stereo.StereoClientRenderer; +import com.jogamp.opengl.util.stereo.StereoGLEventListener; +import com.jogamp.opengl.util.stereo.StereoUtil; + +/** + * All distortions, no multisampling, bilinear filtering, manual-swap and using two FBOs (default, good) + * <pre> + * java StereoDemo01 -time 10000000 + * </pre> + * All distortions, 8x multisampling, bilinear filtering, manual-swap and using two FBOs (best - slowest) + * <pre> + * java StereoDemo01 -time 10000000 -samples 8 + * </pre> + * All distortions, 8x multisampling, bilinear filtering, manual-swap and using one a big single FBO (w/ all commandline params) + * <pre> + * java StereoDemo01 -time 10000000 -vignette true -chromatic true -timewarp false -samples 8 -biLinear true -autoSwap false -singleFBO true -mainScreen false + * </pre> + * No distortions, no multisampling, no filtering, auto-swap and using a big single FBO (worst and fastest) + * <pre> + * java StereoDemo01 -time 10000000 -vignette false -chromatic false -timewarp false -samples 0 -biLinear false -autoSwap true -singleFBO true + * </pre> + * Test on main screen: + * <pre> + * java StereoDemo01 -time 10000000 -mainScreen true + * </pre> + * Test a 3D SBS Movie: + * <pre> + * java StereoDemo01 -time 10000000 -filmFile Some_SBS_3D_Movie.mkv + * java StereoDemo01 -time 10000000 -filmURI http://whoknows.not/Some_SBS_3D_Movie.mkv + * </pre> + * <p> + * In case user likes to utilize the {@link StereoDeviceFactory.DeviceType#Generic Generic} software implementation, + * which is selected {@link StereoDeviceFactory.DeviceType#Default Default} if no other device is available + * or explicit via <code>-device Generic</code>, the user can chose between different <i>generic</i> stereo modes: + * <pre> + * mono : <code>-device Generic -deviceIndex 0</code> + * stereo-sbs : <code>-device Generic -deviceIndex 1</code> + * stereo-sbs-lense: <code>-device Generic -deviceIndex 2</code> + * </pre> + * </p> + * <p> + * Key 'R' enables/disables the VR's sensors, i.e. head rotation .. + * </p> + * + */ +public class StereoDemo01 { + static long duration = 10000; // ms + + static boolean useStereoScreen = true; + + static int numSamples = 0; + static boolean biLinear = true; + static boolean useSingleFBO = false; + static boolean useVignette = true; + static boolean useChromatic = true; + static boolean useTimewarp = true; + static boolean useAutoSwap = false; + static String useFilmFile = null; + static String useFilmURI = null; + static StereoDeviceFactory.DeviceType deviceType = StereoDeviceFactory.DeviceType.Default; + static int deviceIndex = 0; + + public static void main(final String args[]) throws InterruptedException, URISyntaxException { + boolean useRecommendedDistortionBits = true; + int posx = -1; + int posy = -1; + + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + duration = MiscUtils.atol(args[i], duration); + } else if(args[i].equals("-samples")) { + i++; + numSamples = MiscUtils.atoi(args[i], numSamples); + } else if(args[i].equals("-biLinear")) { + i++; + biLinear = MiscUtils.atob(args[i], biLinear); + } else if(args[i].equals("-singleFBO")) { + i++; + useSingleFBO = MiscUtils.atob(args[i], useSingleFBO); + } else if(args[i].equals("-vignette")) { + i++; + useVignette = MiscUtils.atob(args[i], useVignette); + useRecommendedDistortionBits = false; + } else if(args[i].equals("-chromatic")) { + i++; + useChromatic = MiscUtils.atob(args[i], useChromatic); + useRecommendedDistortionBits = false; + } else if(args[i].equals("-timewarp")) { + i++; + useTimewarp = MiscUtils.atob(args[i], useTimewarp); + useRecommendedDistortionBits = false; + } else if(args[i].equals("-vignette")) { + i++; + useVignette = MiscUtils.atob(args[i], useVignette); + useRecommendedDistortionBits = false; + } else if(args[i].equals("-mainScreen")) { + i++; + useStereoScreen = !MiscUtils.atob(args[i], useStereoScreen); + } else if(args[i].equals("-device")) { + i++; + deviceType = StereoDeviceFactory.DeviceType.valueOf(args[i]); + } else if(args[i].equals("-deviceIndex")) { + i++; + deviceIndex = MiscUtils.atoi(args[i], deviceIndex); + } else if(args[i].equals("-posx")) { + i++; + posx = MiscUtils.atoi(args[i], posx); + } else if(args[i].equals("-posy")) { + i++; + posy = MiscUtils.atoi(args[i], posy); + } else if(args[i].equals("-autoSwap")) { + i++; + useAutoSwap = MiscUtils.atob(args[i], useAutoSwap); + } else if(args[i].equals("-filmFile")) { + i++; + useFilmFile = args[i]; + } else if(args[i].equals("-filmURI")) { + i++; + useFilmURI = args[i]; + } + } + final StereoGLEventListener upstream; + final MovieSBSStereo movieSimple; + final Uri movieURI; + if( null != useFilmFile ) { + movieSimple = new MovieSBSStereo(); + movieURI = Uri.valueOf(new File(useFilmFile)); + upstream = movieSimple; + } else if( null != useFilmURI ) { + movieSimple = new MovieSBSStereo(); + movieURI = Uri.cast(useFilmURI); + upstream = movieSimple; + } else { + final GearsES2 demo = new GearsES2(0); + demo.setZ(2f, 10000f, 20f); // start closer to eye + demo.setVerbose(false); + upstream = demo; + movieSimple = null; + movieURI = null; + } + final StereoDemo01 demo01 = new StereoDemo01(); + demo01.doIt(deviceType, deviceIndex, posx, posy, + upstream, movieSimple, movieURI, biLinear, numSamples, useSingleFBO, + useRecommendedDistortionBits, useVignette, useChromatic, useTimewarp, + useAutoSwap, true /* useAnimator */, false /* exclusiveContext*/); + } + + public void doIt(final StereoDeviceFactory.DeviceType deviceType, final int deviceIndex, final int posx, final int posy, + final StereoGLEventListener upstream, final MovieSBSStereo movieSimple, final Uri movieURI, + final boolean biLinear, final int numSamples, final boolean useSingleFBO, + final boolean useRecommendedDistortionBits, final boolean useVignette, final boolean useChromatic, final boolean useTimewarp, + final boolean useAutoSwap, final boolean useAnimator, final boolean exclusiveContext) throws InterruptedException { + + System.err.println("glob duration "+duration); + System.err.println("glob useStereoScreen "+useStereoScreen); + System.err.println("deviceType "+deviceType); + System.err.println("deviceIndex "+deviceIndex); + System.err.println("biLinear "+biLinear); + System.err.println("numSamples "+numSamples); + System.err.println("useSingleFBO "+useSingleFBO); + System.err.println("useRecommendedDistortionBits "+useRecommendedDistortionBits); + System.err.println("useVignette "+useVignette); + System.err.println("useChromatic "+useChromatic); + System.err.println("useTimewarp "+useTimewarp); + System.err.println("useAutoSwap "+useAutoSwap); + + final StereoDeviceFactory stereoDeviceFactory = StereoDeviceFactory.createFactory(deviceType); + if( null == stereoDeviceFactory ) { + System.err.println("No StereoDeviceFactory available"); + return; + } + + final StereoDevice stereoDevice = stereoDeviceFactory.createDevice(deviceIndex, null, true /* verbose */); + if( null == stereoDevice ) { + System.err.println("No StereoDevice.Context available for index "+deviceIndex); + return; + } + + final boolean isGenericDevice = stereoDevice instanceof GenericStereoDevice; + + if( 0 <= posx && 0 <= posy && isGenericDevice ) { + ((GenericStereoDevice)stereoDevice).setSurfacePosition(posx, posy); + } + System.err.println("StereoDevice "+stereoDevice); + + // + // + // + final PointImmutable devicePos = stereoDevice.getPosition(); + final DimensionImmutable deviceRes = stereoDevice.getSurfaceSize(); + System.err.println("Device Res "+deviceRes+", reqRotation "+stereoDevice.getRequiredRotation()); + System.err.println("Device Pos "+devicePos); + + final MonitorDevice monitor = StereoDeviceUtil.getMonitorDevice(stereoDevice, true); + final Screen screen = monitor.getScreen(); + + // Start the sensor which provides the Rift’s pose and motion. + if( !stereoDevice.startSensors(stereoDevice.getSupportedSensorBits(), 0) ) { + System.err.println("Could not start sensors on device "+deviceIndex); + } + + final GLCapabilities caps = new GLCapabilities(GLProfile.getMaxProgrammable(true /* favorHardwareRasterizer */)); + final GLWindow window = GLWindow.create(screen, caps); + + if( useStereoScreen ) { + window.setPosition(devicePos.getX(), devicePos.getY()); + } + window.setSurfaceSize(deviceRes.getWidth(), deviceRes.getHeight()); + window.setAutoSwapBufferMode(useAutoSwap); + window.setUndecorated(true); + + final Animator animator = useAnimator ? new Animator() : null; + if( useAnimator ) { + animator.setModeBits(false, AnimatorBase.MODE_EXPECT_AWT_RENDERING_THREAD); + animator.setExclusiveContext(exclusiveContext); + } + + // + // Stereo Device Setup + // + // EyePos.y = ovrHmd_GetFloat(HMD, OVR_KEY_EYE_HEIGHT, EyePos.y); + final FovHVHalves[] defaultEyeFov = stereoDevice.getDefaultFOV(); + System.err.println("Default Fov[0]: "+defaultEyeFov[0]); + System.err.println("Default Fov[0]: "+defaultEyeFov[0].toStringInDegrees()); + if( defaultEyeFov.length > 1 ) { + System.err.println("Default Fov[1]: "+defaultEyeFov[1]); + System.err.println("Default Fov[1]: "+defaultEyeFov[1].toStringInDegrees()); + } + + final boolean usesLenses = 0 != ( StereoDeviceRenderer.DISTORTION_BARREL & stereoDevice.getMinimumDistortionBits() ); + final float[] eyePositionOffset = null != movieSimple && usesLenses ? new float[] { 0f, 0.3f, 0f } // better fixed movie position w/ lenses + : stereoDevice.getDefaultEyePositionOffset(); // default + System.err.println("Eye Position Offset: "+Arrays.toString(eyePositionOffset)); + + final int textureUnit = 0; + final int reqDistortionBits; + if( useRecommendedDistortionBits ) { + reqDistortionBits = stereoDevice.getRecommendedDistortionBits(); + } else { + reqDistortionBits = ( useVignette ? StereoDeviceRenderer.DISTORTION_VIGNETTE : 0 ) | + ( useChromatic ? StereoDeviceRenderer.DISTORTION_CHROMATIC : 0 ) | + ( useTimewarp ? StereoDeviceRenderer.DISTORTION_TIMEWARP : 0 ); + } + System.err.println("Requesting Distortion Bits: "+StereoUtil.distortionBitsToString(reqDistortionBits)); + + final float pixelsPerDisplayPixel = 1f; + final StereoDeviceRenderer stereoDeviceRenderer = + stereoDevice.createRenderer(reqDistortionBits, useSingleFBO ? 1 : 2, eyePositionOffset, + defaultEyeFov, pixelsPerDisplayPixel, textureUnit); + System.err.println("StereoDeviceRenderer: "+stereoDeviceRenderer); + + final int texFilter = biLinear ? GL.GL_LINEAR : GL.GL_NEAREST; + final StereoClientRenderer renderer = new StereoClientRenderer(stereoDeviceRenderer, true /* ownsDist */, texFilter, texFilter, numSamples); + if( null != movieSimple && null != movieURI) { + movieSimple.setScaleOrig(true); + final GLMediaPlayer mp = movieSimple.getGLMediaPlayer(); + mp.attachObject(MovieSimple.WINDOW_KEY, window); + mp.attachObject(MovieSBSStereo.STEREO_RENDERER_KEY, renderer); + mp.addEventListener(MovieSBSStereo.stereoGLMediaEventListener); + movieSimple.initStream(movieURI, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 3); + } else { + renderer.addGLEventListener(upstream); + } + window.addGLEventListener(renderer); + + final QuitAdapter quitAdapter = new QuitAdapter(); + window.addKeyListener(quitAdapter); + window.addWindowListener(quitAdapter); + + window.addKeyListener(new KeyAdapter() { + @Override + public void keyReleased(final KeyEvent e) { + if( e.isAutoRepeat() ) { + return; + } + switch(e.getKeySymbol()) { + case KeyEvent.VK_O: { + window.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + stereoDevice.resetLocationSensorOrigin(); + return true; + } }); + break; + } + case KeyEvent.VK_P: { + window.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + System.err.println(stereoDeviceRenderer.getLastViewerPose()); + return true; + } }); + break; + } + case KeyEvent.VK_R: { + if( stereoDevice.getSensorsStarted() ) { + stereoDevice.stopSensors(); + } else { + stereoDevice.startSensors(stereoDevice.getSupportedSensorBits(), 0); + } + break; + } + } + } } ); + + if( useAnimator ) { + animator.add(window); + animator.start(); + } + window.setVisible(true); + + // Correct window size to actual pixel size, + // which ration is unknown before window creation when using multiple displays! + System.err.println("Window.0.windowSize : "+window.getWidth()+" x "+window.getHeight()); + System.err.println("Window.0.surfaceSize: "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + window.setSurfaceSize(deviceRes.getWidth(), deviceRes.getHeight()); + if( useStereoScreen ) { + window.setPosition(devicePos.getX(), devicePos.getY()); + } + System.err.println("Window.1.windowSize : "+window.getWidth()+" x "+window.getHeight()); + System.err.println("Window.1.surfaceSize: "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + + if( useAnimator ) { + animator.setUpdateFPSFrames(60, System.err); + } + + final long t0 = System.currentTimeMillis(); + long t1 = t0; + while(!quitAdapter.shouldQuit() && t1-t0<duration) { + Thread.sleep(100); + t1 = System.currentTimeMillis(); + } + + if( useAnimator ) { + animator.stop(); + } + window.destroy(); + screen.removeReference(); // StereoDeviceUtil.getMonitorDevice(stereoDevice, true); + stereoDevice.dispose(); + stereoDeviceFactory.shutdown(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java b/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java index ffb4f95d0..23cd8978d 100644 --- a/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java +++ b/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java @@ -32,6 +32,7 @@ import com.jogamp.newt.event.PinchToZoomGesture; import com.jogamp.newt.event.GestureHandler.GestureEvent; import com.jogamp.opengl.GLRendererQuirks; import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.GearsObject; import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.Quaternion; import com.jogamp.opengl.math.VectorUtil; @@ -55,8 +56,6 @@ import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLUniformData; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; -import com.jogamp.opengl.demos.GearsObject; - /** * GearsES2.java <BR> * @author Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P> diff --git a/src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java b/src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java index 5c48a5df1..3aa6696df 100644 --- a/src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java +++ b/src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java @@ -27,13 +27,11 @@ import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLBufferStorage; import com.jogamp.opengl.GLException; import com.jogamp.opengl.GLUniformData; - +import com.jogamp.opengl.demos.GearsObject; import com.jogamp.opengl.util.GLArrayDataServer; import com.jogamp.opengl.util.PMVMatrix; import com.jogamp.opengl.util.glsl.ShaderState; -import com.jogamp.opengl.demos.GearsObject; - /** * GearsObjectES2.java <BR> * @author Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P> diff --git a/src/demos/com/jogamp/opengl/demos/es2/TextureSequenceCubeES2.java b/src/demos/com/jogamp/opengl/demos/es2/TextureSequenceCubeES2.java new file mode 100644 index 000000000..6a7115143 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/es2/TextureSequenceCubeES2.java @@ -0,0 +1,491 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.es2; + +import java.nio.FloatBuffer; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLES2; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLUniformData; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.common.os.Platform; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.opengl.GLExtensions; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureCoords; +import com.jogamp.opengl.util.texture.TextureSequence; +import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; + +public class TextureSequenceCubeES2 implements GLEventListener { + public TextureSequenceCubeES2 (final TextureSequence texSource, final boolean innerCube, final float zoom0, final float rotx, final float roty) { + this.texSeq = texSource; + this.innerCube = innerCube; + this.zoom = zoom0; + this.view_rotx = rotx; + this.view_roty = roty; + } + + private TextureSequence texSeq; + public ShaderState st; + public PMVMatrix pmvMatrix; + private GLUniformData pmvMatrixUniform; + // private TextureCoords[] textureCoords = null; + private float nearPlaneNormalized; + // private float zoom0=-5.0f, zoom=zoom0; + // private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f; + public float zoom=-2.3f; + private float view_rotx = 0.0f, view_roty = 0.0f; + private final float view_rotz = 0.0f; + int[] vboNames = new int[4]; + boolean innerCube; + + private final MouseListener mouseAction = new MouseAdapter() { + int lx = 0; + int ly = 0; + boolean first = false; + + public void mousePressed(final MouseEvent e) { + first = true; + } + public void mouseMoved(final MouseEvent e) { + first = false; + } + public void mouseDragged(final MouseEvent e) { + int width, height; + final Object source = e.getSource(); + Window window = null; + if(source instanceof Window) { + window = (Window) source; + width=window.getSurfaceWidth(); + height=window.getSurfaceHeight(); + } else if (source instanceof GLAutoDrawable) { + final GLAutoDrawable glad = (GLAutoDrawable) source; + width = glad.getSurfaceWidth(); + height = glad.getSurfaceHeight(); + } else if (GLProfile.isAWTAvailable() && source instanceof java.awt.Component) { + final java.awt.Component comp = (java.awt.Component) source; + width=comp.getWidth(); // FIXME HiDPI: May need to convert window units -> pixel units! + height=comp.getHeight(); + } else { + throw new RuntimeException("Event source neither Window nor Component: "+source); + } + if(e.getPointerCount()==2) { + // 2 pointers zoom .. + if(first) { + lx = Math.abs(e.getY(0)-e.getY(1)); + first=false; + return; + } + final int nv = Math.abs(e.getY(0)-e.getY(1)); + final int dy = nv - lx; + + { + final float o = zoom; + final float d = 40f*Math.signum(dy)/height; + zoom += d; + System.err.println("zoom.d: "+o+" + "+d+" -> "+zoom); + } + + lx = nv; + } else { + // 1 pointer rotate + if(first) { + lx = e.getX(); + ly = e.getY(); + first=false; + return; + } + final int nx = e.getX(); + final int ny = e.getY(); + view_roty += 360f * ( (float)( nx - lx ) / (float)width ); + view_rotx += 360f * ( (float)( ny - ly ) / (float)height ); + lx = nx; + ly = ny; + } + } + public void mouseWheelMoved(final MouseEvent e) { + // System.err.println("XXX "+e); + if( !e.isShiftDown() ) { + final float o = zoom; + final float d = e.getRotation()[1]/10f; // vertical: wheel + zoom += d; + System.err.println("zoom.w: "+o+" + "+d+" -> "+zoom); + } + } + }; + + static final String shaderBasename = "texsequence_xxx"; + static final String myTextureLookupName = "myTexture2D"; + + private void initShader(final GL2ES2 gl) { + // Create & Compile the shader objects + final ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(), + "shader", "shader/bin", shaderBasename, true); + final ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(), + "shader", "shader/bin", shaderBasename, true); + + boolean preludeGLSLVersion = true; + if( GLES2.GL_TEXTURE_EXTERNAL_OES == texSeq.getTextureTarget() ) { + if( !gl.isExtensionAvailable(GLExtensions.OES_EGL_image_external) ) { + throw new GLException(GLExtensions.OES_EGL_image_external+" requested but not available"); + } + if( Platform.OSType.ANDROID == Platform.getOSType() && gl.isGLES3() ) { + // Bug on Nexus 10, ES3 - Android 4.3, where + // GL_OES_EGL_image_external extension directive leads to a failure _with_ '#version 300 es' ! + // P0003: Extension 'GL_OES_EGL_image_external' not supported + preludeGLSLVersion = false; + } + } + rsVp.defaultShaderCustomization(gl, preludeGLSLVersion, true); + + int rsFpPos = preludeGLSLVersion ? rsFp.addGLSLVersion(gl) : 0; + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, texSeq.getRequiredExtensionsShaderStub()); + rsFp.addDefaultShaderPrecision(gl, rsFpPos); + + final String texLookupFuncName = texSeq.getTextureLookupFunctionName(myTextureLookupName); + rsFp.replaceInShaderSource(myTextureLookupName, texLookupFuncName); + + // Inject TextureSequence shader details + final StringBuilder sFpIns = new StringBuilder(); + sFpIns.append("uniform ").append(texSeq.getTextureSampler2DType()).append(" mgl_ActiveTexture;\n"); + sFpIns.append(texSeq.getTextureLookupFragmentShaderImpl()); + rsFp.insertShaderSource(0, "TEXTURE-SEQUENCE-CODE-BEGIN", 0, sFpIns); + + // Create & Link the shader program + final ShaderProgram sp = new ShaderProgram(); + sp.add(rsVp); + sp.add(rsFp); + if(!sp.link(gl, System.err)) { + throw new GLException("Couldn't link program: "+sp); + } + + // Let's manage all our states using ShaderState. + st = new ShaderState(); + st.attachShaderProgram(gl, sp, false); + } + + GLArrayDataServer interleavedVBO, cubeIndicesVBO; + + public void init(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + System.err.println(JoglVersion.getGLInfo(gl, null)); + final TextureFrame frame = texSeq.getLastTexture(); + if( null == frame ) { + return; + } + final Texture tex= frame.getTexture(); + + initShader(gl); + + // Push the 1st uniform down the path + st.useProgram(gl, true); + + pmvMatrix = new PMVMatrix(); + reshapePMV(drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + pmvMatrixUniform = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); // P, Mv + if(!st.uniform(gl, pmvMatrixUniform)) { + throw new GLException("Error setting PMVMatrix in shader: "+st); + } + if(!st.uniform(gl, new GLUniformData("mgl_ActiveTexture", texSeq.getTextureUnit()))) { + throw new GLException("Error setting mgl_ActiveTexture in shader: "+st); + } + + + // calculate centered tex coords w/ aspect ratio + final float[] fixedCubeTexCoords = new float[s_cubeTexCoords.length]; + { + final float aspect = tex.getAspectRatio(); + final TextureCoords tc = tex.getImageTexCoords(); + System.err.println("XXX0: aspect: "+aspect); + System.err.println("XXX0: y-flip: "+tex.getMustFlipVertically()); + System.err.println("XXX0: "+tc); + final float tc_x1 = Math.max(tc.left(), tc.right()); + final float tc_y1 = Math.max(tc.bottom(), tc.top()); + final float ss=1f, ts=aspect; // scale tex-coord + final float dy = ( 1f - aspect ) / 2f ; + for(int i=0; i<s_cubeTexCoords.length; i+=2) { + final float tx = s_cubeTexCoords[i+0]; + final float ty = s_cubeTexCoords[i+1]; + if(tx!=0) { + fixedCubeTexCoords[i+0] = tc_x1 * ss; + } + if(ty==0 && !tex.getMustFlipVertically() || ty!=0 && tex.getMustFlipVertically()) { + fixedCubeTexCoords[i+1] = 0f + dy; + } else { + fixedCubeTexCoords[i+1] = tc_y1 * ts + dy; + } + } + } + + interleavedVBO = GLArrayDataServer.createGLSLInterleaved(3+4+2, GL.GL_FLOAT, false, 3*6*4, GL.GL_STATIC_DRAW); + { + interleavedVBO.addGLSLSubArray("mgl_Vertex", 3, GL.GL_ARRAY_BUFFER); + interleavedVBO.addGLSLSubArray("mgl_Color", 4, GL.GL_ARRAY_BUFFER); + //interleavedVBO.addGLSLSubArray("mgl_Normal", 3, GL.GL_ARRAY_BUFFER); + interleavedVBO.addGLSLSubArray("mgl_MultiTexCoord", 2, GL.GL_ARRAY_BUFFER); + + final FloatBuffer ib = (FloatBuffer)interleavedVBO.getBuffer(); + + for(int i=0; i<6*4; i++) { + ib.put(s_cubeVertices, i*3, 3); + ib.put(s_cubeColors, i*4, 4); + //ib.put(s_cubeNormals, i*3, 3); + ib.put(fixedCubeTexCoords, i*2, 2); + } + } + interleavedVBO.seal(gl, true); + interleavedVBO.enableBuffer(gl, false); + st.ownAttribute(interleavedVBO, true); + + cubeIndicesVBO = GLArrayDataServer.createData(6, GL.GL_UNSIGNED_SHORT, 6, GL.GL_STATIC_DRAW, GL.GL_ELEMENT_ARRAY_BUFFER); + for(int i=0; i<6*6; i++) { + cubeIndicesVBO.puts(s_cubeIndices[i]); + } + cubeIndicesVBO.seal(gl, true); + cubeIndicesVBO.enableBuffer(gl, false); + st.ownAttribute(cubeIndicesVBO, true); + + + gl.glEnable(GL.GL_DEPTH_TEST); + + st.useProgram(gl, false); + + final Object upstreamWidget = drawable.getUpstreamWidget(); + if (upstreamWidget instanceof Window) { + final Window window = (Window) upstreamWidget; + window.addMouseListener(mouseAction); + } else if (GLProfile.isAWTAvailable() && upstreamWidget instanceof java.awt.Component) { + final java.awt.Component comp = (java.awt.Component) upstreamWidget; + new com.jogamp.newt.event.awt.AWTMouseAdapter(mouseAction, drawable).addTo(comp); + } + + // Let's show the completed shader state .. + System.out.println("iVBO: "+interleavedVBO); + System.out.println(st); + } + + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glViewport(0, 0, width, height); + + if(!innerCube) { + // lights on + } else { + // lights off + } + // gl.glEnable(GL.GL_CULL_FACE); + // gl.glDisable(GL.GL_DITHER); + + if(null != st) { + reshapePMV(width, height); + st.useProgram(gl, true); + st.uniform(gl, pmvMatrixUniform); + st.useProgram(gl, false); + } + } + + + private void reshapePMV(final int width, final int height) { + if(null != pmvMatrix) { + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + if(!innerCube) { + pmvMatrix.gluPerspective(45.0f, (float)width / (float)height, 1f, 10.0f); + nearPlaneNormalized = 1f/(100f-1f); + } else { + pmvMatrix.glOrthof(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 10.0f); + nearPlaneNormalized = 0f; + } + System.err.println("XXX0: Perspective nearPlaneNormalized: "+nearPlaneNormalized); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, zoom); + } + } + + + @Override + public void dispose(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + texSeq = null; + pmvMatrixUniform = null; + pmvMatrix=null; + if( null != st ) { + st.destroy(gl); + st=null; + } + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + if(innerCube) { + // Clear background to white + gl.glClearColor(1.0f, 1.0f, 1.0f, 0.4f); + } else { + // Clear background to blue + gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f); + } + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + if( null == st ) { + return; + } + + st.useProgram(gl, true); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, zoom); + pmvMatrix.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f); + pmvMatrix.glRotatef(view_roty, 0.0f, 1.0f, 0.0f); + pmvMatrix.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f); + st.uniform(gl, pmvMatrixUniform); + interleavedVBO.enableBuffer(gl, true); + Texture tex = null; + if(null!=texSeq) { + final TextureSequence.TextureFrame texFrame = texSeq.getNextTexture(gl); + if(null != texFrame) { + tex = texFrame.getTexture(); + gl.glActiveTexture(GL.GL_TEXTURE0+texSeq.getTextureUnit()); + tex.enable(gl); + tex.bind(gl); + } + } + cubeIndicesVBO.bindBuffer(gl, true); // keeps VBO binding + gl.glDrawElements(GL.GL_TRIANGLES, cubeIndicesVBO.getElemCount() * cubeIndicesVBO.getCompsPerElem(), GL.GL_UNSIGNED_SHORT, 0); + cubeIndicesVBO.bindBuffer(gl, false); + + if(null != tex) { + tex.disable(gl); + } + interleavedVBO.enableBuffer(gl, false); + st.useProgram(gl, false); + } + + static final float[] light_position = { -50.f, 50.f, 50.f, 0.f }; + static final float[] light_ambient = { 0.125f, 0.125f, 0.125f, 1.f }; + static final float[] light_diffuse = { 1.0f, 1.0f, 1.0f, 1.f }; + static final float[] material_spec = { 1.0f, 1.0f, 1.0f, 0.f }; + static final float[] zero_vec4 = { 0.0f, 0.0f, 0.0f, 0.f }; + + private static final float[] s_cubeVertices = /* f b t b r l */ + { + -1f, 1f, 1f, 1f, -1f, 1f, 1f, 1f, 1f, -1f, -1f, 1f, + + -1f, 1f, -1f, 1f, -1f, -1f, 1f, 1f, -1f, -1f, -1f, -1f, + + -1f, -1f, 1f, 1f, -1f, -1f, 1f, -1f, 1f, -1f, -1f, -1f, + + -1f, 1f, 1f, 1f, 1f, -1f, 1f, 1f, 1f, -1f, 1f, -1f, + + 1f, -1f, 1f, 1f, 1f, -1f, 1f, 1f, 1f, 1f, -1f, -1f, + + -1f, -1f, 1f, -1f, 1f, -1f, -1f, 1f, 1f, -1f, -1f, -1f + }; + + private static final float[] s_cubeTexCoords = + { // LT RB RT LB + 0f, 1f, 1f, 0f, 1f, 1f, 0f, 0f, + + 0f, 1f, 1f, 0f, 1f, 1f, 0f, 0f, + + 0f, 1f, 1f, 0f, 1f, 1f, 0f, 0f, + + 0f, 1f, 1f, 0f, 1f, 1f, 0f, 0f, + + 0f, 0f, 1f, 1f, 0f, 1f, 1f, 0f, + + 0f, 0f, 1f, 1f, 0f, 1f, 1f, 0f, + }; + + private static final float[] s_cubeColors = + { + 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, + + 40f/255f, 80f/255f, 160f/255f, 255f/255f, 40f/255f, 80f/255f, 160f/255f, 255f/255f, + 40f/255f, 80f/255f, 160f/255f, 255f/255f, 40f/255f, 80f/255f, 160f/255f, 255f/255f, + + 40f/255f, 80f/255f, 160f/255f, 255f/255f, 40f/255f, 80f/255f, 160f/255f, 255f/255f, + 40f/255f, 80f/255f, 160f/255f, 255f/255f, 40f/255f, 80f/255f, 160f/255f, 255f/255f, + + 128f/255f, 128f/255f, 128f/255f, 255f/255f, 128f/255f, 128f/255f, 128f/255f, 255f/255f, + 128f/255f, 128f/255f, 128f/255f, 255f/255f, 128f/255f, 128f/255f, 128f/255f, 255f/255f, + + 255f/255f, 110f/255f, 10f/255f, 255f/255f, 255f/255f, 110f/255f, 10f/255f, 255f/255f, + 255f/255f, 110f/255f, 10f/255f, 255f/255f, 255f/255f, 110f/255f, 10f/255f, 255f/255f, + + 255f/255f, 70f/255f, 60f/255f, 255f/255f, 255f/255f, 70f/255f, 60f/255f, 255f/255f, + 255f/255f, 70f/255f, 60f/255f, 255f/255f, 255f/255f, 70f/255f, 60f/255f, 255f/255f + }; + + /* + private static final float[] s_cubeNormals = + { + 0f, 0f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, + + 0f, 0f, -1f, 0f, 0f, -1f, 0f, 0f, -1f, 0f, 0f, -1f, + + 0f, -1f, 0f, 0f, -1f, 0f, 0f, -1f, 0f, 0f, -1f, 0f, + + 0f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, 0f, + + 1f, 0f, 0f, 1f, 0f, 0f, 1f, 0f, 0f, 1f, 0f, 0f, + + -1f, 0f, 0f, -1f, 0f, 0f, -1f, 0f, 0f, -1f, 0f, 0f + };*/ + private static final short[] s_cubeIndices = + { + 0, 3, 1, 2, 0, 1, /* front */ + 6, 5, 4, 5, 7, 4, /* back */ + 8, 11, 9, 10, 8, 9, /* top */ + 15, 12, 13, 12, 14, 13, /* bottom */ + 16, 19, 17, 18, 16, 17, /* right */ + 23, 20, 21, 20, 22, 21 /* left */ + }; +} + diff --git a/src/demos/com/jogamp/opengl/demos/graph/FontSetDemos.java b/src/demos/com/jogamp/opengl/demos/graph/FontSetDemos.java new file mode 100644 index 000000000..12c996945 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/FontSetDemos.java @@ -0,0 +1,35 @@ +package com.jogamp.opengl.demos.graph; + +import java.io.IOException; + +import com.jogamp.common.util.IOUtil; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontSet; + +public class FontSetDemos { + public static Font[] getSet01() throws IOException { + final Font[] fonts = new Font[11]; + int i = 0; + fonts[i++] = FontFactory.get(FontFactory.UBUNTU).getDefault(); // FontSet.FAMILY_REGULAR, FontSet.STYLE_NONE + fonts[i++] = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_NONE); + fonts[i++] = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_ITALIC); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMono.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMonoBold.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSans.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSansBold.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerif.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerifBold.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerifBoldItalic.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + fonts[i++] = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerifItalic.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + return fonts; + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener00.java b/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener00.java new file mode 100644 index 000000000..2515b8217 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener00.java @@ -0,0 +1,134 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.graph; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.opengl.util.PMVMatrix; + +/** Demonstrate the rendering of multiple outlines into one region/OutlineShape + * These Outlines are not necessary connected or contained. + * The output of this demo shows two identical shapes but the left one + * has some vertices with off-curve flag set to true, and the right allt he vertices + * are on the curve. Demos the Res. Independent Nurbs based Curve rendering + * + */ +public class GPURegionGLListener00 extends GPURendererListenerBase01 { + OutlineShape outlineShape = null; + + public GPURegionGLListener00 (final RenderState rs, final int renderModes, final int sampleCount, final boolean debug, final boolean trace) { + super(RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable), renderModes, debug, trace); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + setMatrix(-20, 00, -50, 0f, sampleCount); + } + + private void createTestOutline(final GLProfile glp){ + outlineShape = new OutlineShape(getRenderer().getRenderState().getVertexFactory()); + outlineShape.addVertex(0.0f,-10.0f, true); + outlineShape.addVertex(15.0f,-10.0f, true); + outlineShape.addVertex(10.0f,5.0f, false); + outlineShape.addVertex(15.0f,10.0f, true); + outlineShape.addVertex(6.0f,15.0f, false); + outlineShape.addVertex(5.0f,8.0f, false); + outlineShape.addVertex(0.0f,10.0f,true); + outlineShape.closeLastOutline(true); + outlineShape.addEmptyOutline(); + outlineShape.addVertex(5.0f,-5.0f,true); + outlineShape.addVertex(10.0f,-5.0f, false); + outlineShape.addVertex(10.0f,0.0f, true); + outlineShape.addVertex(5.0f,0.0f, false); + outlineShape.closeLastOutline(true); + + /** Same shape as above but without any off-curve vertices */ + final float offset = 30; + outlineShape.addEmptyOutline(); + outlineShape.addVertex(offset+0.0f,-10.0f, true); + outlineShape.addVertex(offset+17.0f,-10.0f, true); + outlineShape.addVertex(offset+11.0f,5.0f, true); + outlineShape.addVertex(offset+16.0f,10.0f, true); + outlineShape.addVertex(offset+7.0f,15.0f, true); + outlineShape.addVertex(offset+6.0f,8.0f, true); + outlineShape.addVertex(offset+0.0f,10.0f, true); + outlineShape.closeLastOutline(true); + outlineShape.addEmptyOutline(); + outlineShape.addVertex(offset+5.0f,0.0f, true); + outlineShape.addVertex(offset+5.0f,-5.0f, true); + outlineShape.addVertex(offset+10.0f,-5.0f, true); + outlineShape.addVertex(offset+10.0f,0.0f, true); + outlineShape.closeLastOutline(true); + + region = GLRegion.create(glp, getRenderModes(), null); + region.addOutlineShape(outlineShape, null, region.hasColorChannel() ? getRenderer().getRenderState().getColorStatic(new float[4]) : null); + } + + @Override + public void init(final GLAutoDrawable drawable) { + super.init(drawable); + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + final RenderState rs = getRenderer().getRenderState(); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_BLEND); + rs.setColorStatic(0.0f, 0.0f, 0.0f, 1.0f); + + createTestOutline(gl.getGLProfile()); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + final RegionRenderer regionRenderer = getRenderer(); + final PMVMatrix pmv = regionRenderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + pmv.glTranslatef(getXTran(), getYTran(), getZTran()); + pmv.glRotatef(getAngle(), 0, 1, 0); + if( weight != regionRenderer.getRenderState().getWeight() ) { + regionRenderer.getRenderState().setWeight(weight); + } + regionRenderer.enable(gl, true); + region.draw(gl, regionRenderer, getSampleCount()); + regionRenderer.enable(gl, false); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener01.java b/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener01.java new file mode 100644 index 000000000..c7fbe54c8 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener01.java @@ -0,0 +1,299 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.graph; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.geom.plane.Path2F; +import com.jogamp.graph.geom.plane.WindingRule; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.opengl.util.PMVMatrix; + +/** Demonstrate the rendering of multiple outlines into one region/OutlineShape + * These Outlines are not necessary connected or contained. + * The output of this demo shows two identical shapes but the left one + * has some vertices with off-curve flag set to true, and the right allt he vertices + * are on the curve. Demos the Res. Independent Nurbs based Curve rendering + * + */ +public class GPURegionGLListener01 extends GPURendererListenerBase01 { + final int shape_ctor_mode; + OutlineShape outlineShape = null; + + public GPURegionGLListener01 (final RenderState rs, final int renderModes, final int sampleCount, final boolean debug, final boolean trace) { + this(1, rs, renderModes, sampleCount, debug, trace); + } + + public GPURegionGLListener01 (final int shape_ctor_mode, final RenderState rs, final int renderModes, final int sampleCount, final boolean debug, final boolean trace) { + super(RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable), renderModes, debug, trace); + this.shape_ctor_mode = shape_ctor_mode; + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + setMatrix(-20, 00, -50, 0f, sampleCount); + } + + private void createTestOutline00(){ + outlineShape.addVertex(0.0f,-10.0f, true); + outlineShape.addVertex(15.0f,-10.0f, true); + outlineShape.addVertex(10.0f,5.0f, false); + outlineShape.addVertex(15.0f,10.0f, true); + outlineShape.addVertex(6.0f,15.0f, false); + outlineShape.addVertex(5.0f,8.0f, false); + outlineShape.addVertex(0.0f,10.0f,true); + outlineShape.closeLastOutline(true); + outlineShape.addEmptyOutline(); + outlineShape.addVertex(5.0f,-5.0f,true); + outlineShape.addVertex(10.0f,-5.0f, false); + outlineShape.addVertex(10.0f,0.0f, true); + outlineShape.addVertex(5.0f,0.0f, false); + outlineShape.closeLastOutline(true); + + /** Same shape as above but without any off-curve vertices */ + final float offset = 30; + outlineShape.addEmptyOutline(); + outlineShape.addVertex(offset+0.0f,-10.0f, true); + outlineShape.addVertex(offset+17.0f,-10.0f, true); + outlineShape.addVertex(offset+11.0f,5.0f, true); + outlineShape.addVertex(offset+16.0f,10.0f, true); + outlineShape.addVertex(offset+7.0f,15.0f, true); + outlineShape.addVertex(offset+6.0f,8.0f, true); + outlineShape.addVertex(offset+0.0f,10.0f, true); + outlineShape.closeLastOutline(true); + outlineShape.addEmptyOutline(); + outlineShape.addVertex(offset+5.0f,0.0f, true); + outlineShape.addVertex(offset+5.0f,-5.0f, true); + outlineShape.addVertex(offset+10.0f,-5.0f, true); + outlineShape.addVertex(offset+10.0f,0.0f, true); + outlineShape.closeLastOutline(true); + } + + private void createTestOutline01(){ + outlineShape.moveTo(0.0f,-10.0f, 0f); + outlineShape.lineTo(15.0f,-10.0f, 0f); + outlineShape.quadTo(10.0f,5.0f,0f, 15.0f,10.0f,0f); + outlineShape.cubicTo(6.0f,15.0f,0f, 5.0f,8.0f,0f, 0.0f,10.0f,0f); + outlineShape.closePath(); + outlineShape.moveTo(5.0f,-5.0f,0f); + outlineShape.quadTo(10.0f,-5.0f,0f, 10.0f,0.0f,0f); + outlineShape.quadTo(5.0f,0.0f,0f, 5.0f,-5.0f,0f); + outlineShape.closePath(); + + /** Same shape as above but without any off-curve vertices */ + final float offset = 30; + outlineShape.moveTo(offset+0.0f,-10.0f,0f); + outlineShape.lineTo(offset+17.0f,-10.0f,0f); + outlineShape.lineTo(offset+11.0f,5.0f,0f); + outlineShape.lineTo(offset+16.0f,10.0f,0f); + outlineShape.lineTo(offset+7.0f,15.0f,0f); + outlineShape.lineTo(offset+6.0f,8.0f,0f); + outlineShape.lineTo(offset+0.0f,10.0f,0f); + outlineShape.closePath(); + outlineShape.moveTo(offset+5.0f,0.0f,0f); + outlineShape.lineTo(offset+5.0f,-5.0f,0f); + outlineShape.lineTo(offset+10.0f,-5.0f,0f); + outlineShape.lineTo(offset+10.0f,0.0f,0f); + outlineShape.closePath(); + } + + private void createTestOutline02(){ + final Path2F path = new Path2F(WindingRule.NON_ZERO); + path.moveTo(0.0f,-10.0f); + path.lineTo(15.0f,-10.0f); + path.quadTo(10.0f,5.0f, 15.0f,10.0f); + path.cubicTo(6.0f,15.0f, 5.0f,8.0f, 0.0f,10.0f); + path.closePath(); + path.moveTo(5.0f,-5.0f); + path.quadTo(10.0f,-5.0f, 10.0f,0.0f); + path.quadTo(5.0f,0.0f, 5.0f,-5.0f); + path.closePath(); + + /** Same shape as above but without any off-curve vertices */ + final float offset = 30; + path.moveTo(offset+0.0f,-10.0f); + path.lineTo(offset+17.0f,-10.0f); + path.lineTo(offset+11.0f,5.0f); + path.lineTo(offset+16.0f,10.0f); + path.lineTo(offset+7.0f,15.0f); + path.lineTo(offset+6.0f,8.0f); + path.lineTo(offset+0.0f,10.0f); + path.closePath(); + path.moveTo(offset+5.0f,0.0f); + path.lineTo(offset+5.0f,-5.0f); + path.lineTo(offset+10.0f,-5.0f); + path.lineTo(offset+10.0f,0.0f); + path.closePath(); + + System.err.println("GPURegionGLListener01.createTestOutline02.X: path "+path); + path.printSegments(System.err); + outlineShape.addPath(path, false /* connect */); + } + + private void createTestOutline03(){ + { + final Path2F path = new Path2F(WindingRule.NON_ZERO); + path.moveTo(0.0f,-10.0f); + path.lineTo(15.0f,-10.0f); + path.quadTo(10.0f,5.0f, 15.0f,10.0f); + path.cubicTo(6.0f,15.0f, 5.0f,8.0f, 0.0f,10.0f); + path.closePath(); + System.err.println("GPURegionGLListener01.createTestOutline03.0: path "+path); + path.printSegments(System.err); + { + final Path2F path2 = new Path2F(WindingRule.NON_ZERO); + path2.moveTo(5.0f,-5.0f); + path2.quadTo(10.0f,-5.0f, 10.0f,0.0f); + path2.quadTo(5.0f,0.0f, 5.0f,-5.0f); + path2.closePath(); + System.err.println("GPURegionGLListener01.createTestOutline03.0: path2 "+path2); + path2.printSegments(System.err); + path.append(path2, false); + System.err.println("GPURegionGLListener01.createTestOutline03.1: path "+path); + path.printSegments(System.err); + } + outlineShape.addPath(path, false /* connect */); + } + { + /** Same shape as above but without any off-curve vertices */ + final float offset = 30; + final Path2F path = new Path2F(WindingRule.NON_ZERO); + path.moveTo(offset+0.0f,-10.0f); + path.lineTo(offset+17.0f,-10.0f); + path.lineTo(offset+11.0f,5.0f); + path.lineTo(offset+16.0f,10.0f); + path.lineTo(offset+7.0f,15.0f); + path.lineTo(offset+6.0f,8.0f); + path.lineTo(offset+0.0f,10.0f); + path.closePath(); + path.moveTo(offset+5.0f,0.0f); + path.lineTo(offset+5.0f,-5.0f); + path.lineTo(offset+10.0f,-5.0f); + path.lineTo(offset+10.0f,0.0f); + path.closePath(); + System.err.println("GPURegionGLListener01.createTestOutline03.3: path "+path); + path.printSegments(System.err); + outlineShape.addPath(path, false /* connect */); + } + + } + + private void createTestOutline04(){ + final Path2F path = new Path2F(WindingRule.NON_ZERO); + + path.moveTo(0.0f,10.0f); + path.cubicTo(5.0f,8.0f, 6.0f,15.0f, 15.0f,10.0f); + path.quadTo(10.0f,5.0f, 15.0f,-10.0f); + path.lineTo(0.0f,-10.0f); + path.closePath(); + path.moveTo(5.0f,-5.0f); + path.quadTo(5.0f,0.0f, 10.0f,0.0f); + path.quadTo(10.0f,-5.0f, 5.0f,-5.0f); + path.closePath(); + + /** Same shape as above but without any off-curve vertices */ + final float offset = 30; + path.moveTo(offset+0.0f,10.0f); + path.lineTo(offset+6.0f,8.0f); + path.lineTo(offset+7.0f,15.0f); + path.lineTo(offset+16.0f,10.0f); + path.lineTo(offset+11.0f,5.0f); + path.lineTo(offset+17.0f,-10.0f); + path.lineTo(offset+0.0f,-10.0f); + path.closePath(); + path.moveTo(offset+10.0f,0.0f); + path.lineTo(offset+10.0f,-5.0f); + path.lineTo(offset+5.0f,-5.0f); + path.lineTo(offset+5.0f,0.0f); + path.closePath(); + + System.err.println("GPURegionGLListener01.createTestOutline04.X: path "+path); + path.printSegments(System.err); + outlineShape.addPathRev(path, false /* connect */); + } + + @Override + public void init(final GLAutoDrawable drawable) { + super.init(drawable); + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + final RenderState rs = getRenderer().getRenderState(); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_BLEND); + rs.setColorStatic(0.0f, 0.0f, 0.0f, 1.0f); + + outlineShape = new OutlineShape(getRenderer().getRenderState().getVertexFactory()); + switch( shape_ctor_mode ) { + case 0: + createTestOutline00(); + break; + case 2: + createTestOutline02(); + break; + case 3: + createTestOutline03(); + break; + case 4: + createTestOutline04(); + break; + default: + createTestOutline01(); + break; + } + region = GLRegion.create(gl.getGLProfile(), getRenderModes(), null); + region.addOutlineShape(outlineShape, null, region.hasColorChannel() ? getRenderer().getRenderState().getColorStatic(new float[4]) : null); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + final RegionRenderer regionRenderer = getRenderer(); + final PMVMatrix pmv = regionRenderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + pmv.glTranslatef(getXTran(), getYTran(), getZTran()); + pmv.glRotatef(getAngle(), 0, 1, 0); + if( weight != regionRenderer.getRenderState().getWeight() ) { + regionRenderer.getRenderState().setWeight(weight); + } + regionRenderer.enable(gl, true); + region.draw(gl, regionRenderer, getSampleCount()); + regionRenderer.enable(gl, false); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener10.java b/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener10.java new file mode 100644 index 000000000..6af1aac96 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener10.java @@ -0,0 +1,138 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.graph; + +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.opengl.util.PMVMatrix; + +/** Demonstrate the rendering of multiple OutlineShapes + * into one region + * + */ +public class GPURegionGLListener10 extends GPURendererListenerBase01 { + List<OutlineShape> outlineShapes = new ArrayList<OutlineShape>(); + + public GPURegionGLListener10 (final RenderState rs, final int renderModes, final int sampleCount, final boolean debug, final boolean trace) { + super(RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable), renderModes, debug, trace); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + setMatrix(-20, 00, -50, 0f, sampleCount); + } + + private void createTestOutline(final GLProfile glp){ + OutlineShape shape = new OutlineShape(getRenderer().getRenderState().getVertexFactory()); + outlineShapes.add(shape); + shape.addVertex(0.0f,-10.0f,true); + shape.addVertex(15.0f,-10.0f, true); + shape.addVertex(10.0f,5.0f, false); + shape.addVertex(15.0f,10.0f, true); + shape.addVertex(6.0f,15.0f, false); + shape.addVertex(5.0f,8.0f, false); + shape.addVertex(0.0f,10.0f,true); + shape.closeLastOutline(true); + shape.addEmptyOutline(); + shape.addVertex(5.0f,-5.0f,true); + shape.addVertex(10.0f,-5.0f, false); + shape.addVertex(10.0f,0.0f, true); + shape.addVertex(5.0f,0.0f, false); + shape.closeLastOutline(true); + + /** Same shape as above but without any off-curve vertices */ + shape = new OutlineShape(getRenderer().getRenderState().getVertexFactory()); + outlineShapes.add(shape); + final float offset = 30; + shape.addVertex(offset+0.0f,-10.0f, true); + shape.addVertex(offset+17.0f,-10.0f, true); + shape.addVertex(offset+11.0f,5.0f, true); + shape.addVertex(offset+16.0f,10.0f, true); + shape.addVertex(offset+7.0f,15.0f, true); + shape.addVertex(offset+6.0f,8.0f, true); + shape.addVertex(offset+0.0f,10.0f, true); + shape.closeLastOutline(true); + shape.addEmptyOutline(); + shape.addVertex(offset+5.0f,0.0f, true); + shape.addVertex(offset+5.0f,-5.0f, true); + shape.addVertex(offset+10.0f,-5.0f, true); + shape.addVertex(offset+10.0f,0.0f, true); + shape.closeLastOutline(true); + + region = GLRegion.create(glp, getRenderModes(), null); + region.addOutlineShapes(outlineShapes, null, null); + } + + @Override + public void init(final GLAutoDrawable drawable) { + super.init(drawable); + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + final RenderState rs = getRenderer().getRenderState(); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_BLEND); + rs.setColorStatic(0.0f, 0.0f, 0.0f, 1.0f); + + createTestOutline(gl.getGLProfile()); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + final RegionRenderer regionRenderer = getRenderer(); + + final PMVMatrix pmv = regionRenderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + pmv.glTranslatef(getXTran(), getYTran(), getZTran()); + pmv.glRotatef(getAngle(), 0, 1, 0); + if( weight != regionRenderer.getRenderState().getWeight() ) { + regionRenderer.getRenderState().setWeight(weight); + } + regionRenderer.enable(gl, true); + region.draw(gl, regionRenderer, getSampleCount()); + regionRenderer.enable(gl, false); + + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPURegionNewtDemo.java b/src/demos/com/jogamp/opengl/demos/graph/GPURegionNewtDemo.java new file mode 100644 index 000000000..59292c7be --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPURegionNewtDemo.java @@ -0,0 +1,162 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.graph; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.util.MiscUtils; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + +/** Demonstrate the rendering of multiple outlines into one region/OutlineShape + * These Outlines are not necessary connected or contained. + * The output of this demo shows two identical shapes but the left one + * has some vertices with off-curve flag set to true, and the right allt he vertices + * are on the curve. Demos the Res. Independent Nurbs based Curve rendering + * + */ +public class GPURegionNewtDemo { + static final boolean DEBUG = false; + static final boolean TRACE = false; + + static int shape_ctor_mode = 1; + static int SceneMSAASamples = 0; + static int GraphVBAASamples = 4; + static int GraphMSAASamples = 0; + static boolean GraphUseWeight = true; + + public static void main(final String[] args) { + int width = 800, height = 400; + int x = 10, y = 10; + if( 0 != args.length ) { + SceneMSAASamples = 0; + GraphMSAASamples = 0; + GraphVBAASamples = 0; + GraphUseWeight = false; + + for(int i=0; i<args.length; i++) { + if(args[i].equals("-smsaa")) { + i++; + SceneMSAASamples = MiscUtils.atoi(args[i], SceneMSAASamples); + } else if(args[i].equals("-gmsaa")) { + i++; + GraphMSAASamples = MiscUtils.atoi(args[i], GraphMSAASamples); + GraphVBAASamples = 0; + } else if(args[i].equals("-gvbaa")) { + i++; + GraphMSAASamples = 0; + GraphVBAASamples = MiscUtils.atoi(args[i], GraphVBAASamples); + } else if(args[i].equals("-gweight")) { + GraphUseWeight = true; + } else if(args[i].equals("-width")) { + i++; + width = MiscUtils.atoi(args[i], width); + } else if(args[i].equals("-height")) { + i++; + height = MiscUtils.atoi(args[i], height); + } else if(args[i].equals("-x")) { + i++; + x = MiscUtils.atoi(args[i], x); + } else if(args[i].equals("-y")) { + i++; + y = MiscUtils.atoi(args[i], y); + } else if(args[i].equals("-shape_ctor")) { + i++; + shape_ctor_mode = MiscUtils.atoi(args[i], shape_ctor_mode); + } + } + } + System.err.println("Desired win size "+width+"x"+height); + System.err.println("Desired win pos "+x+"/"+y); + System.err.println("Shape_ctor_mode "+shape_ctor_mode); + System.err.println("Scene MSAA Samples "+SceneMSAASamples); + System.err.println("Graph MSAA Samples"+GraphMSAASamples); + System.err.println("Graph VBAA Samples "+GraphVBAASamples); + System.err.println("Graph Weight Mode "+GraphUseWeight); + + final GLProfile glp = GLProfile.getGL2ES2(); + final GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(4); + if( SceneMSAASamples > 0 ) { + caps.setSampleBuffers(true); + caps.setNumSamples(SceneMSAASamples); + } + System.out.println("Requested: " + caps); + + int rmode = GraphUseWeight ? Region.VARWEIGHT_RENDERING_BIT : 0; + int sampleCount = 0; + if( GraphVBAASamples > 0 ) { + rmode |= Region.VBAA_RENDERING_BIT; + sampleCount += GraphVBAASamples; + } else if( GraphMSAASamples > 0 ) { + rmode |= Region.MSAA_RENDERING_BIT; + sampleCount += GraphMSAASamples; + } + + final GLWindow window = GLWindow.create(caps); + window.setPosition(x, y); + window.setSize(width, height); + window.setTitle("GPU Curve Region Newt Demo - graph[vbaa"+GraphVBAASamples+" msaa"+GraphMSAASamples+"], msaa "+SceneMSAASamples); + + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final GPURegionGLListener01 regionGLListener = new GPURegionGLListener01 (shape_ctor_mode, rs, rmode, sampleCount, DEBUG, TRACE); + regionGLListener.attachInputListenerTo(window); + window.addGLEventListener(regionGLListener); + window.setVisible(true); + + //FPSAnimator animator = new FPSAnimator(60); + final Animator animator = new Animator(); + animator.setUpdateFPSFrames(60, System.err); + animator.add(window); + + window.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(final KeyEvent arg0) { + if(arg0.getKeyCode() == KeyEvent.VK_F4) { + window.destroy(); + } + } + }); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyed(final WindowEvent e) { + animator.stop(); + } + }); + + animator.start(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPURendererListenerBase01.java b/src/demos/com/jogamp/opengl/demos/graph/GPURendererListenerBase01.java new file mode 100644 index 000000000..185699d55 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPURendererListenerBase01.java @@ -0,0 +1,361 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph; + +import java.io.File; +import java.io.IOException; + +import com.jogamp.opengl.FPSCounter; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLPipelineFactory; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.font.FontScale; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.opengl.util.GLReadBufferUtil; +import com.jogamp.opengl.util.PMVMatrix; + +/** + * + * Action Keys: + * - 1/2: zoom in/out + * - 6/7: 2nd pass texture size + * - 0/9: rotate + * - Q/W: change weight + * - v: toggle v-sync + * - s: screenshot + */ +public abstract class GPURendererListenerBase01 implements GLEventListener { + private final RegionRenderer renderer; + private final int renderModes; + private final boolean debug; + private final boolean trace; + + protected GLRegion region; + + private final GLReadBufferUtil screenshot; + + private KeyAction keyAction; + + private volatile GLAutoDrawable autoDrawable = null; + + private final float[] position = new float[] {0,0,0}; + + protected final float zNear = 0.1f, zFar = 7000f; + /** Describing the bounding box in model-coordinates of the near-plane parallel at distance one. */ + protected final AABBox nearPlane1Box; + + private float xTran = -10; + private float yTran = 10; + private float ang = 0f; + private float zTran = -70f; + private final int[] sampleCount = new int[] { 4 }; + + protected volatile float weight = 1.0f; + boolean ignoreInput = false; + + public GPURendererListenerBase01(final RegionRenderer renderer, final int renderModes, final boolean debug, final boolean trace) { + this.renderer = renderer; + this.renderModes = renderModes; + this.debug = debug; + this.trace = trace; + this.screenshot = new GLReadBufferUtil(false, false); + nearPlane1Box = new AABBox(); + } + + public final RegionRenderer getRenderer() { return renderer; } + public final int getRenderModes() { return renderModes; } + public final float getZTran() { return zTran; } + public final float getXTran() { return xTran; } + public final float getYTran() { return yTran; } + public final float getAngle() { return ang; } + public final int[] getSampleCount() { return sampleCount; } + public final float[] getPosition() { return position; } + + public void setMatrix(final float xtrans, final float ytrans, final float zTran, final float angle, final int sampleCount) { + this.xTran = xtrans; + this.yTran = ytrans; + this.zTran = zTran; + this.ang = angle; + this.sampleCount[0] = sampleCount; + } + + @Override + public void init(final GLAutoDrawable drawable) { + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + final Window window = (Window) upObj; + final float[] sPpMM = window.getPixelsPerMM(new float[2]); + final float[] sDPI = FontScale.perMMToPerInch( new float[] { sPpMM[0], sPpMM[1] } ); + System.err.println("DPI "+sDPI[0]+" x "+sDPI[1]+", "+sPpMM[0]+" x "+sPpMM[1]+" pixel/mm"); + + final float[] hasSurfacePixelScale1 = window.getCurrentSurfaceScale(new float[2]); + System.err.println("HiDPI PixelScale: "+hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); + } + autoDrawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(debug) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) ).getGL2ES2(); + } + if(trace) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2(); + } + System.err.println("*** "+gl.getContext().getGLVersion()); + System.err.println("*** GLDebugMessage "+gl.getContext().isGLDebugMessageEnabled()); + MSAATool.dump(drawable); + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + getRenderer().init(gl); + } + + public static void mapWin2ObjectCoords(final PMVMatrix pmv, final int[] view, + final float zNear, final float zFar, + final float orthoX, final float orthoY, final float orthoDist, + final float[] winZ, final float[] objPos) { + winZ[0] = (1f/zNear-1f/orthoDist)/(1f/zNear-1f/zFar); + pmv.gluUnProject(orthoX, orthoY, winZ[0], view, 0, objPos, 0); + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int xstart, final int ystart, final int width, final int height) { + final PMVMatrix pmv = renderer.getMatrix(); + renderer.reshapePerspective(45.0f, width, height, zNear, zFar); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + System.err.printf("Reshape: zNear %f, zFar %f%n", zNear, zFar); + System.err.printf("Reshape: Frustum: %s%n", pmv.glGetFrustum()); + { + final float orthoDist = 1f; + final float[] obj00Coord = new float[3]; + final float[] obj11Coord = new float[3]; + final float[] winZ = new float[1]; + final int[] view = new int[] { 0, 0, width, height }; + + mapWin2ObjectCoords(pmv, view, zNear, zFar, 0f, 0f, orthoDist, winZ, obj00Coord); + System.err.printf("Reshape: mapped.00: [%f, %f, %f], winZ %f -> [%f, %f, %f]%n", 0f, 0f, orthoDist, winZ[0], obj00Coord[0], obj00Coord[1], obj00Coord[2]); + + mapWin2ObjectCoords(pmv, view, zNear, zFar, width, height, orthoDist, winZ, obj11Coord); + System.err.printf("Reshape: mapped.11: [%f, %f, %f], winZ %f -> [%f, %f, %f]%n", (float)width, (float)height, orthoDist, winZ[0], obj11Coord[0], obj11Coord[1], obj11Coord[2]); + + nearPlane1Box.setSize( obj00Coord[0], // lx + obj00Coord[1], // ly + obj00Coord[2], // lz + obj11Coord[0], // hx + obj11Coord[1], // hy + obj11Coord[2] );// hz + System.err.printf("Reshape: dist1Box: %s%n", nearPlane1Box); + } + + dumpMatrix(); + // System.err.println("Reshape: "+renderer.getRenderState()); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + autoDrawable = null; + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(null != region) { + region.destroy(gl); + } + screenshot.dispose(gl); + renderer.destroy(gl); + } + + public void zoom(final int v){ + zTran += v; + dumpMatrix(); + } + + public void move(final float x, final float y){ + xTran += x; + yTran += y; + dumpMatrix(); + } + public void rotate(final float delta){ + ang += delta; + ang %= 360.0f; + dumpMatrix(); + } + public void editGlobalWeight(final float delta) { + if( !RenderState.isWeightValid(weight+delta) ) { + return; + } + weight += delta; + System.err.println("Global Weight: "+ weight); + } + + void dumpMatrix() { + System.err.println("Matrix: " + xTran + " / " + yTran + " / "+zTran + " @ "+ang); + } + + /** Attach the input listener to the window */ + public void attachInputListenerTo(final GLWindow window) { + if ( null == keyAction ) { + keyAction = new KeyAction(); + window.addKeyListener(keyAction); + } + } + + public void detachInputListenerFrom(final GLWindow window) { + if ( null == keyAction ) { + return; + } + window.removeKeyListener(keyAction); + } + + public void printScreen(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) throws GLException, IOException { + final String sw = String.format("_s%02d-%s-Z%04d-snap%02d-%03dx%03d", sampleCount[0], objName, (int)Math.abs(zTran), screenshot_num++, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + final String filename = dir + tech + sw +".png"; + if(screenshot.readPixels(drawable.getGL(), false)) { + screenshot.write(new File(filename)); + } + } + private int screenshot_num = 0; + + public void printScreenOnGLThread(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) { + drawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + try { + printScreen(drawable, dir, tech, objName, exportAlpha); + } catch (final GLException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } + return true; + } + }); + } + + public void setIgnoreInput(final boolean v) { + ignoreInput = v; + } + public boolean getIgnoreInput() { + return ignoreInput; + } + + public class KeyAction implements KeyListener { + @Override + public void keyPressed(final KeyEvent arg0) { + if(ignoreInput) { + return; + } + + if(arg0.getKeyCode() == KeyEvent.VK_1){ + zoom(10); + } + else if(arg0.getKeyCode() == KeyEvent.VK_2){ + zoom(-10); + } + else if(arg0.getKeyCode() == KeyEvent.VK_UP){ + move(0, -1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){ + move(0, 1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){ + move(-1, 0); + } + else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){ + move(1, 0); + } + else if(arg0.getKeyCode() == KeyEvent.VK_6){ + sampleCount[0] -= 1; + System.err.println("Sample Count: " + sampleCount[0]); + } + else if(arg0.getKeyCode() == KeyEvent.VK_7){ + sampleCount[0] += 1; + System.err.println("Sample Count: " + sampleCount[0]); + } + else if(arg0.getKeyCode() == KeyEvent.VK_0){ + rotate(1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_9){ + rotate(-1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_Q){ + editGlobalWeight(-0.1f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_W){ + editGlobalWeight(0.1f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_V) { + if(null != autoDrawable) { + autoDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + final int _i = gl.getSwapInterval(); + final int i; + switch(_i) { + case 0: i = -1; break; + case -1: i = 1; break; + case 1: i = 0; break; + default: i = 1; break; + } + gl.setSwapInterval(i); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + if(drawable instanceof FPSCounter) { + ((FPSCounter)drawable).resetFPSCounter(); + } + System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval()); + return true; + } + }); + } + } + else if(arg0.getKeyCode() == KeyEvent.VK_S){ + if(null != autoDrawable) { + final String modeS = Region.getRenderModeString(renderModes); + final String type = modeS + ( Region.hasVariableWeight(renderModes) ? "-vc" : "-uc" ) ; + printScreenOnGLThread(autoDrawable, "./", "demo-"+type, "", false); + } + } + } + @Override + public void keyReleased(final KeyEvent arg0) {} + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPUTextGLListener0A.java b/src/demos/com/jogamp/opengl/demos/graph/GPUTextGLListener0A.java new file mode 100644 index 000000000..8a8a49869 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPUTextGLListener0A.java @@ -0,0 +1,72 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph; + + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLProfile; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.newt.opengl.GLWindow; + +public class GPUTextGLListener0A extends GPUTextRendererListenerBase01 { + + public GPUTextGLListener0A(final GLProfile glp, final RenderState rs, final int renderModes, final int sampleCount, final boolean blending, final boolean debug, final boolean trace) { + super(glp, rs, renderModes, sampleCount, blending, debug, trace); + } + + @Override + public void init(final GLAutoDrawable drawable) { + if(drawable instanceof GLWindow) { + final GLWindow glw = (GLWindow) drawable; + attachInputListenerTo(glw); + } + super.init(drawable); + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + final RenderState rs = getRenderer().getRenderState(); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_BLEND); + rs.setColorStatic(0.1f, 0.1f, 0.1f, 1.0f); + } + + @Override + public void dispose(final GLAutoDrawable drawable) { + if(drawable instanceof GLWindow) { + final GLWindow glw = (GLWindow) drawable; + detachInputListenerFrom(glw); + } + super.dispose(drawable); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java b/src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java new file mode 100644 index 000000000..b4e91e01f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java @@ -0,0 +1,193 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph; + +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.util.MiscUtils; +import com.jogamp.opengl.math.geom.AABBox; + +import java.io.File; +import java.io.IOException; + +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontScale; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.newt.MonitorDevice; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + +public class GPUTextNewtDemo { + /** + * FIXME: + * + * If DEBUG is enabled: + * + * Caused by: com.jogamp.opengl.GLException: Thread[main-Display-X11_:0.0-1-EDT-1,5,main] glGetError() returned the following error codes after a call to glFramebufferRenderbuffer(<int> 0x8D40, <int> 0x1902, <int> 0x8D41, <int> 0x1): GL_INVALID_ENUM ( 1280 0x500), + * at com.jogamp.opengl.DebugGL4bc.checkGLGetError(DebugGL4bc.java:33961) + * at com.jogamp.opengl.DebugGL4bc.glFramebufferRenderbuffer(DebugGL4bc.java:33077) + * at jogamp.graph.curve.opengl.VBORegion2PGL3.initFBOTexture(VBORegion2PGL3.java:295) + */ + static final boolean DEBUG = false; + static final boolean TRACE = false; + + static int SceneMSAASamples = 0; + static int GraphVBAASamples = 4; + static int GraphMSAASamples = 0; + + public static void main(final String[] args) throws IOException { + Font opt_font = null; + int opt_fontSizeHead = -1; + int width = 800, height = 400; + int x = 10, y = 10; + if( 0 != args.length ) { + SceneMSAASamples = 0; + GraphMSAASamples = 0; + GraphVBAASamples = 0; + + for(int i=0; i<args.length; i++) { + if(args[i].equals("-smsaa")) { + i++; + SceneMSAASamples = MiscUtils.atoi(args[i], SceneMSAASamples); + } else if(args[i].equals("-gmsaa")) { + i++; + GraphMSAASamples = MiscUtils.atoi(args[i], GraphMSAASamples); + GraphVBAASamples = 0; + } else if(args[i].equals("-gvbaa")) { + i++; + GraphMSAASamples = 0; + GraphVBAASamples = MiscUtils.atoi(args[i], GraphVBAASamples); + } else if(args[i].equals("-width")) { + i++; + width = MiscUtils.atoi(args[i], width); + } else if(args[i].equals("-height")) { + i++; + height = MiscUtils.atoi(args[i], height); + } else if(args[i].equals("-x")) { + i++; + x = MiscUtils.atoi(args[i], x); + } else if(args[i].equals("-y")) { + i++; + y = MiscUtils.atoi(args[i], y); + } else if(args[i].equals("-font")) { + i++; + opt_font = FontFactory.get(new File(args[i])); + } else if(args[i].equals("-fontSize")) { + i++; + opt_fontSizeHead = MiscUtils.atoi(args[i], opt_fontSizeHead); + } + } + } + System.err.println("Desired win size "+width+"x"+height); + System.err.println("Desired win pos "+x+"/"+y); + System.err.println("Scene MSAA Samples "+SceneMSAASamples); + System.err.println("Graph MSAA Samples "+GraphMSAASamples); + System.err.println("Graph VBAA Samples "+GraphVBAASamples); + + final GLProfile glp = GLProfile.getGL2ES2(); + + final GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(4); + if( SceneMSAASamples > 0 ) { + caps.setSampleBuffers(true); + caps.setNumSamples(SceneMSAASamples); + } + System.out.println("Requested: " + caps); + + int rmode = 0; // Region.VARIABLE_CURVE_WEIGHT_BIT; + int sampleCount = 0; + if( GraphVBAASamples > 0 ) { + rmode |= Region.VBAA_RENDERING_BIT; + sampleCount += GraphVBAASamples; + } else if( GraphMSAASamples > 0 ) { + rmode |= Region.MSAA_RENDERING_BIT; + sampleCount += GraphMSAASamples; + } + + final GLWindow window = GLWindow.create(caps); + window.setPosition(x, y); + window.setSize(width, height); + window.setTitle("GPU Text Newt Demo - graph[vbaa"+GraphVBAASamples+" msaa"+GraphMSAASamples+"], msaa "+SceneMSAASamples); + + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final GPUTextGLListener0A textGLListener = new GPUTextGLListener0A(glp, rs, rmode, sampleCount, true, DEBUG, TRACE); + textGLListener.setFont(opt_font); + textGLListener.setFontHeadSize(opt_fontSizeHead); + // ((TextRenderer)textGLListener.getRenderer()).setCacheLimit(32); + window.addGLEventListener(textGLListener); + window.setVisible(true); + + { + final Font font2 = textGLListener.getFont(); + final float[] sDPI = FontScale.perMMToPerInch( window.getPixelsPerMM(new float[2]) ); + final float font_ptpi = 12f; + final float font_ppi = FontScale.toPixels(font_ptpi, sDPI[1]); + final AABBox fontNameBox = font2.getMetricBounds(GPUTextRendererListenerBase01.textX1); + System.err.println("GPU Text Newt Demo: "+font2.fullString()); + System.err.println("GPU Text Newt Demo: screen-dpi: "+sDPI[0]+"x"+sDPI[1]+", font "+font_ptpi+" pt, "+font_ppi+" pixel"); + System.err.println("GPU Text Newt Demo: textX2: "+fontNameBox+" em, "+fontNameBox.scale(font_ppi, new float[3])+" px"); + final MonitorDevice monitor = window.getMainMonitor(); + System.err.println("GPU Text Newt Demo: "+monitor); + // window.setSurfaceSize((int)(fontNameBox.getWidth()*1.1f), (int)(fontNameBox.getHeight()*2f)); + } + + // FPSAnimator animator = new FPSAnimator(60); + final Animator animator = new Animator(); + animator.setUpdateFPSFrames(60, null); + animator.add(window); + + window.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(final KeyEvent arg0) { + if(arg0.getKeyCode() == KeyEvent.VK_F4) { + new InterruptSource.Thread() { + @Override + public void run() { + window.destroy(); + } }.start(); + } + } + }); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyed(final WindowEvent e) { + animator.stop(); + } + }); + + animator.start(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java b/src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java new file mode 100644 index 000000000..f23548b8a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java @@ -0,0 +1,588 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph; + +import java.io.IOException; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.curve.opengl.TextRegionUtil; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontScale; +import com.jogamp.graph.font.FontSet; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.opengl.util.PMVMatrix; + +/** + * + * GPURendererListenerBase01 Keys: + * - 1/2: zoom in/out + * - 6/7: 2nd pass texture size + * - 0/9: rotate + * - v: toggle v-sync + * - s: screenshot + * + * Additional Keys: + * - 3/4: font +/- + * - h: toogle draw 'font set' + * - f: toggle draw fps + * - space: toggle font (ubuntu/java) + * - i: live input text input (CR ends it, backspace supported) + */ +public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerBase01 { + public final TextRegionUtil textRegionUtil; + private final GLRegion regionFPS, regionHead, regionBottom; + int fontSet = FontFactory.UBUNTU; + Font font; + + int headType = 1; + boolean drawFPS = true; + final float fontSizeFName = 10f; + final float fontSizeFPS = 10f; + final int[] sampleCountFPS = new int[] { 8 }; + float fontSizeHead = 12f; + float fontSizeCenter = 16f; + float dpiV = 96; + float ppmmV = 1; + final int fontSizeModulo = 100; + String fontName; + AABBox fontNameBox; + String headtext; + AABBox headbox; + + protected final AffineTransform tempT1 = new AffineTransform(); + protected final AffineTransform tempT2 = new AffineTransform(); + + static final String text2 = "The quick brown fox jumps over the lazy dog"; + public static final String text_help = + "JOGL: Java™ Binding for OpenGL®, providing hardware-accelerated 3D graphics.\n\n"+ + "JOGAMP graph demo using Resolution Independent NURBS\n"+ + "JOGAMP JOGL - OpenGL ES2 profile\n"+ + "Press 1/2 to zoom in/out the below text\n"+ + "Press 3/4 to incr/decs font size (alt: head, w/o bottom)\n"+ + "Press 6/7 to edit texture size if using VBAA\n"+ + "Press 0/9 to rotate the below string\n"+ + "Press s to screenshot\n"+ + "Press v to toggle vsync\n"+ + "Press i for live input text input (CR ends it, backspace supported)\n"+ + "Press f to toggle fps. H for different text, space for font type\n"; + + public static final String textX1 = + "JOGL: Java™ Binding for OpenGL®, providing hardware-accelerated 3D graphics.\n\n"+ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec sapien tellus. \n"+ + "Ut purus odio, rhoncus sit amet commodo eget, ullamcorper vel urna. Mauris ultricies \n"+ + "quam iaculis urna cursus ornare. Nullam ut felis a ante ultrices ultricies nec a elit. \n"+ + "In hac habitasse platea dictumst. Vivamus et mi a quam lacinia pharetra at venenatis est. \n"+ + "Morbi quis bibendum nibh. Donec lectus orci, sagittis in consequat nec, volutpat nec nisi. \n"+ + "Donec ut dolor et nulla tristique varius. In nulla magna, fermentum id tempus quis, semper \n"+ + "in lorem. Maecenas in ipsum ac justo scelerisque sollicitudin. Quisque sit amet neque lorem, \n" + + "-------Press H to change text---------"; + + public static final String textX2 = + "I “Ask Jeff” or ‘Ask Jeff’. Take the chef d’œuvre! Two of [of] (of) ‘of’ “of” of? of! of*.\n"+ + "Les Woëvres, the Fôret de Wœvres, the Voire and Vauvise. Yves is in heaven; D’Amboise is in jail.\n"+ + "Lyford’s in Texas & L’Anse-aux-Griffons in Québec; the Łyna in Poland. Yriarte, Yciar and Ysaÿe are at Yale.\n"+ + "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvæven in Norway, Kyulu in Kenya, not in Rwanda.…\n"+ + "Von-Vincke-Straße in Münster, Vdovino in Russia, Ytterbium in the periodic table. Are Toussaint L’Ouverture, Wölfflin, Wolfe,\n"+ + "Miłosz and Wū Wŭ all in the library? 1510–1620, 11:00 pm, and the 1980s are over. X\n"+ + "-------Press H to change text---------"; + + public static final String textX20 = + "I “Ask Jeff” or ‘Ask Jeff’. Take the chef d’œuvre! Two of [of] (of) ‘of’ “of” of? of! of*.\n"+ + "Two of [of] (of) ‘of’ “of” of? of! of*. Ydes, Yffignac and Ygrande are in France: so are Ypres,\n"+ + "Les Woëvres, the Fôret de Wœvres, the Voire and Vauvise. Yves is in heaven; D’Amboise is in jail.\n"+ + "Lyford’s in Texas & L’Anse-aux-Griffons in Québec; the Łyna in Poland. Yriarte, Yciar and Ysaÿe are at Yale.\n"+ + "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvæven in Norway, Kyulu in Kenya, not in Rwanda.…\n"+ + "Walton’s in West Virginia, but «Wren» is in Oregon. Tlálpan is near Xochimilco in México.\n"+ + "The Zygos & Xylophagou are in Cyprus, Zwettl in Austria, Fænø in Denmark, the Vøringsfossen and Værøy in Norway.\n"+ + "Tchula is in Mississippi, the Tittabawassee in Michigan. Twodot is here in Montana, Ywamun in Burma.\n"+ + "Yggdrasil and Ymir, Yngvi and Vóden, Vídrið and Skeggjöld and Týr are all in the Eddas.\n"+ + "Tørberget and Våg, of course, are in Norway, Ktipas and Tmolos in Greece, but Vázquez is in Argentina, Vreden in Germany,\n"+ + "Von-Vincke-Straße in Münster, Vdovino in Russia, Ytterbium in the periodic table. Are Toussaint L’Ouverture, Wölfflin, Wolfe,\n"+ + "Miłosz and Wū Wŭ all in the library? 1510–1620, 11:00 pm, and the 1980s are over.\n"+ + "Ut purus odio, rhoncus sit amet commodo eget, ullamcorper vel urna. Mauris ultricies \n"+ + "-------Press H to change text---------"; + + static final String textXLast = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ\n0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]"; + + Window upstream_window = null; + StringBuilder userString = new StringBuilder(textX1); + boolean userInput = false; + public GPUTextRendererListenerBase01(final GLProfile glp, final RenderState rs, final int renderModes, final int sampleCount, final boolean blending, final boolean debug, final boolean trace) { + // NOTE_ALPHA_BLENDING: We use alpha-blending + super(RegionRenderer.create(rs, blending ? RegionRenderer.defaultBlendEnable : null, + blending ? RegionRenderer.defaultBlendDisable : null), + renderModes, debug, trace); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + this.textRegionUtil = new TextRegionUtil(renderModes); + this.regionFPS = GLRegion.create(glp, renderModes, null); + this.regionHead = GLRegion.create(glp, renderModes, null); + this.regionBottom = GLRegion.create(glp, renderModes, null); + setFontSet(fontSet, FontSet.FAMILY_LIGHT, FontSet.STYLE_NONE); + setMatrix(0, 0, 0, 0f, sampleCount); + } + + void switchHeadBox() { + setHeadBox( ( headType + 1 ) % 5, true ); + } + public int getHeadBoxType() { return headType; } + public AABBox getHeadBox() { return headbox; } + public void setHeadBox(final int choice, final boolean resize) { + headType = choice % 5 ; + switch(headType) { + case 0: + headtext = null; + break; + + case 1: + headtext= textX1; + break; + case 2: + headtext= textX2; + break; + case 3: + headtext= text_help; + break; + + default: + headtext = textXLast; + } + if(resize && null != headtext) { + headbox = font.getMetricBounds(headtext); + if( headtext != text_help ) { + final float pxSz = FontScale.toPixels(fontSizeHead, dpiV); + upsizeWindowSurface(upstream_window, true, (int)(headbox.getWidth()*pxSz*1.1f), (int)(headbox.getHeight()*pxSz*2f)); + } + } + } + + public void setHeadBox(final String text, final boolean resize) { + headtext = text; + if(resize && null != headtext) { + headbox = font.getMetricBounds(headtext); + if( headtext != text_help ) { + final float pxSz = FontScale.toPixels(fontSizeHead, dpiV); + upsizeWindowSurface(upstream_window, true, (int)(headbox.getWidth()*pxSz*1.1f), (int)(headbox.getHeight()*pxSz*2f)); + } + } + } + + public static void upsizeWindowSurface(final Window window, final boolean off_thread, final int w, final int h) { + if( null == window ) { + return; + } + final int w2 = Math.max(window.getSurfaceWidth(), w); + final int h2 = Math.max(window.getSurfaceHeight(), h); + System.err.println("upsizeWindowSurface: "+window.getSurfaceWidth()+"x"+window.getSurfaceHeight()+" -> "+w+"x"+h+" -> "+w2+"x"+h2); + if( off_thread ) { + new InterruptSource.Thread() { + @Override + public void run() { + window.setSurfaceSize(w2, h2); + } }.start(); + } else { + window.setSurfaceSize(w2, h2); + } + } + + @Override + public void init(final GLAutoDrawable drawable) { + super.init(drawable); + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + upstream_window = (Window) upObj; + final float[] sPpMM = upstream_window.getPixelsPerMM(new float[2]); + final float[] sDPI = FontScale.perMMToPerInch( new float[] { sPpMM[0], sPpMM[1] } ); + dpiV = sDPI[1]; + ppmmV = sPpMM[1]; + System.err.println("Using vertical screen DPI of "+dpiV+", "+ppmmV+" pixel/mm"); + } else { + System.err.println("Using vertical default DPI of "+dpiV+", "+ppmmV+" pixel/mm"); + } + fontNameBox = font.getGlyphBounds(fontName, tempT1, tempT2); + setHeadBox(headType, true); + { + final float pixelSizeFName = FontScale.toPixels(fontSizeFName, dpiV); + System.err.println("XXX: fontName size "+fontSizeFName+"pt, dpiV "+dpiV+" -> "+pixelSizeFName+"px"); + System.err.println("XXX: fontName boxM fu "+font.getMetricBoundsFU(fontName)); + System.err.println("XXX: fontName boxG fu "+font.getGlyphBoundsFU(fontName, tempT1, tempT2)); + System.err.println("XXX: fontName boxM em "+font.getMetricBounds(fontName)); + System.err.println("XXX: fontName boxG em "+font.getGlyphBounds(fontName, tempT1, tempT2)); + System.err.println("XXX: fontName box height px "+(fontNameBox.getHeight() * pixelSizeFName)); + } + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int xstart, final int ystart, final int width, final int height) { + super.reshape(drawable, xstart, ystart, width, height); + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + upstream_window = (Window) upObj; + } + final float dist = 100f; + nearPlaneX0 = nearPlane1Box.getMinX() * dist; + nearPlaneY0 = nearPlane1Box.getMinY() * dist; + nearPlaneZ0 = nearPlane1Box.getMinZ() * dist; + final float xd = nearPlane1Box.getWidth() * dist; + final float yd = nearPlane1Box.getHeight() * dist; + nearPlaneSx = xd / width; + nearPlaneSy = yd / height; + nearPlaneS = nearPlaneSy; + System.err.printf("Scale: [%f x %f] / [%d x %d] = [%f, %f] -> %f%n", xd, yd, width, height, nearPlaneSx, nearPlaneSy, nearPlaneS); + } + float nearPlaneX0, nearPlaneY0, nearPlaneZ0, nearPlaneSx, nearPlaneSy, nearPlaneS; + + @Override + public void dispose(final GLAutoDrawable drawable) { + upstream_window = null; + regionFPS.destroy(drawable.getGL().getGL2ES2()); + regionHead.destroy(drawable.getGL().getGL2ES2()); + regionBottom.destroy(drawable.getGL().getGL2ES2()); + super.dispose(drawable); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + upstream_window = (Window) upObj; + } + final int width = drawable.getSurfaceWidth(); + final int height = drawable.getSurfaceHeight(); + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + // final float zDistance0 = 500f; + // final float zDistance1 = 400f; + // final float[] objPos = new float[3]; + // final float[] winZ = new float[1]; + // final int[] view = new int[] { 0, 0, drawable.getWidth(), drawable.getHeight() }; + + final RegionRenderer renderer = getRenderer(); + final RenderState rs = renderer.getRenderState(); + final PMVMatrix pmv = renderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + rs.setColorStatic(0.1f, 0.1f, 0.1f, 1.0f); + final float pixelSizeFName = FontScale.toPixels(fontSizeFName, dpiV); + final float pixelSizeHead = FontScale.toPixels(fontSizeHead, dpiV); + final float mmSizeHead = pixelSizeHead / ppmmV; + final float pixelSizeCenter = FontScale.toPixels(fontSizeCenter, dpiV); + final float mmSizeCenter = pixelSizeCenter / ppmmV; + + renderer.enable(gl, true); + + if( drawFPS ) { + pmv.glPushMatrix(); + final float pixelSizeFPS = FontScale.toPixels(fontSizeFPS, dpiV); + final float lfps, tfps, td; + final GLAnimatorControl animator = drawable.getAnimator(); + if( null != animator ) { + lfps = animator.getLastFPS(); + tfps = animator.getTotalFPS(); + td = animator.getTotalFPSDuration()/1000f; + } else { + lfps = 0f; + tfps = 0f; + td = 0f; + } + final String modeS = Region.getRenderModeString(regionFPS.getRenderModes()); + final String text = String.format("%03.1f/%03.1f fps, v-sync %d, dpiV %.2f %.2f px/mm, font[head %.1fpt %.2fpx %.2fmm, center %.1fpt %.2fpx %.2fmm], %s-samples[%d, this %d], blend %b, alpha %d", + lfps, tfps, gl.getSwapInterval(), dpiV, ppmmV, + fontSizeHead, pixelSizeHead, mmSizeHead, + fontSizeCenter, pixelSizeCenter, mmSizeCenter, + modeS, getSampleCount()[0], sampleCountFPS[0], + renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED), + drawable.getChosenGLCapabilities().getAlphaBits()); + + // bottom, half line up + pmv.glTranslatef(nearPlaneX0, nearPlaneY0+(nearPlaneS * pixelSizeFPS / 2f), nearPlaneZ0); + { + final float sxy = nearPlaneS * pixelSizeFPS; + pmv.glScalef(sxy, sxy, 1.0f); + } + // No cache, keep region alive! + TextRegionUtil.drawString3D(gl, regionFPS.clear(gl), renderer, font, text, null, sampleCountFPS, tempT1, tempT2); + pmv.glPopMatrix(); + } + + // float dx = width - ( fontNameBox.getWidth() + font.getAdvanceWidth( Glyph.ID_SPACE ) ) * pixelSizeFName; + float dx = width - ( fontNameBox.getWidth() + 2 * font.getAdvanceWidth( font.getGlyphID('X') ) ) * pixelSizeFName; + float dy = height - fontNameBox.getHeight() * pixelSizeFName; + { + pmv.glPushMatrix(); + pmv.glTranslatef(nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy), nearPlaneZ0); + { + final float sxy = nearPlaneS * pixelSizeFName; + pmv.glScalef(sxy, sxy, 1.0f); + } + // System.err.printf("FontN: [%f %f] -> [%f %f]%n", dx, dy, nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy)); + textRegionUtil.drawString3D(gl, renderer, font, fontName, null, getSampleCount()); + pmv.glPopMatrix(); + } + + dx = 10f; + dy += -fontNameBox.getHeight() * pixelSizeFName - 10f; + + if(null != headtext) { + pmv.glPushMatrix(); + // System.err.printf("Head: [%f %f] -> [%f %f]%n", dx, dy, nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy)); + pmv.glTranslatef(nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy), nearPlaneZ0); + { + final float sxy = nearPlaneS * pixelSizeHead; + pmv.glScalef(sxy, sxy, 1.0f); + } + // pmv.glTranslatef(x0, y1, z0); + textRegionUtil.drawString3D(gl, renderer, font, headtext, null, getSampleCount()); + pmv.glPopMatrix(); + } + + dy += ( -headbox.getHeight() - font.getLineHeight() ) * pixelSizeCenter; + + { + pmv.glPushMatrix(); + pmv.glTranslatef(nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy), nearPlaneZ0); + // System.err.printf("Bottom: [%f %f] -> [%f %f]%n", dx, dy, nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy)); + pmv.glTranslatef(getXTran(), getYTran(), getZTran()); + pmv.glRotatef(getAngle(), 0, 1, 0); + { + final float sxy = nearPlaneS * pixelSizeCenter; + pmv.glScalef(sxy, sxy, 1.0f); + } + rs.setColorStatic(0.9f, 0.0f, 0.0f, 1.0f); + + if( bottomTextUseFrustum ) { + regionBottom.setFrustum(pmv.glGetFrustum()); + } + if(!userInput) { + if( bottomTextUseFrustum ) { + TextRegionUtil.drawString3D(gl, regionBottom.clear(gl), renderer, font, text2, null, getSampleCount(), tempT1, tempT2); + } else { + textRegionUtil.drawString3D(gl, renderer, font, text2, null, getSampleCount()); + } + } else { + if( bottomTextUseFrustum ) { + TextRegionUtil.drawString3D(gl, regionBottom.clear(gl), renderer, font, userString.toString(), null, getSampleCount(), tempT1, tempT2); + } else { + textRegionUtil.drawString3D(gl, renderer, font, userString.toString(), null, getSampleCount()); + } + } + pmv.glPopMatrix(); + } + renderer.enable(gl, false); + } + final boolean bottomTextUseFrustum = true; + + public Font getFont() { return font; } + public float getFontSizeHead() { return fontSizeHead; } + + public void fontBottomIncr(final int v) { + fontSizeCenter = Math.abs((fontSizeCenter + v) % fontSizeModulo) ; + dumpMatrix(true); + } + + public void fontHeadIncr(final int v) { + fontSizeHead = Math.abs((fontSizeHead + v) % fontSizeModulo) ; + updateFontNameBox(); + if(null != headtext) { + headbox = font.getMetricBounds(headtext); + } + } + + public void setFontHeadSize(final int v) { + if( 0 < v ) { + fontSizeHead = v % fontSizeModulo; + updateFontNameBox(); + if(null != headtext) { + headbox = font.getMetricBounds(headtext); + } + } + } + + public boolean nextFontSet() { + try { + final int set = ( fontSet == FontFactory.UBUNTU ) ? FontFactory.JAVA : FontFactory.UBUNTU ; + final Font _font = FontFactory.get(set).getDefault(); + if(null != _font) { + fontSet = set; + font = _font; + updateFontNameBox(); + return true; + } + } catch (final IOException ex) { + System.err.println("Caught: "+ex.getMessage()); + } + return false; + } + + public boolean setFontSet(final int set, final int family, final int stylebits) { + try { + final Font _font = FontFactory.get(set).get(family, stylebits); + if(null != _font) { + fontSet = set; + font = _font; + updateFontNameBox(); + return true; + } + } catch (final IOException ex) { + System.err.println("Caught: "+ex.getMessage()); + } + return false; + } + + public boolean setFont(final Font _font) { + if(null != _font) { + // fontSet = ??? + font = _font; + updateFontNameBox(); + return true; + } + return false; + } + + private void updateFontNameBox() { + fontName = font.getFullFamilyName()+" (head "+fontSizeHead+"pt)"; + fontNameBox = font.getMetricBounds(fontName); + } + + public boolean isUserInputMode() { return userInput; } + + void dumpMatrix(final boolean bbox) { + System.err.println("Matrix: " + getXTran() + "/" + getYTran() + " x"+getZTran() + " @"+getAngle() +" fontSize "+fontSizeCenter); + if(bbox) { + System.err.println("bbox em: "+font.getMetricBounds(text2)); + System.err.println("bbox px: "+font.getMetricBounds(text2).scale(nearPlaneS * FontScale.toPixels(fontSizeCenter, dpiV), new float[3])); + } + } + + KeyAction keyAction = null; + + @Override + public void attachInputListenerTo(final GLWindow window) { + if ( null == keyAction ) { + keyAction = new KeyAction(); + window.addKeyListener(keyAction); + super.attachInputListenerTo(window); + } + } + + @Override + public void detachInputListenerFrom(final GLWindow window) { + super.detachInputListenerFrom(window); + if ( null == keyAction ) { + return; + } + window.removeKeyListener(keyAction); + } + + @Override + public void printScreen(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) throws GLException, IOException { + final String fn = font.getFullFamilyName().replace(' ', '_').replace('-', '_'); + final String modes = Region.getRenderModeString(getRenderModes()); + final String fsaa = "fsaa"+drawable.getChosenGLCapabilities().getNumSamples(); + super.printScreen(drawable, dir, tech+"-"+modes, fsaa+"-"+fn+"-text"+getHeadBoxType()+"-"+objName, exportAlpha); + } + + float fontHeadScale = 1f; + + public class KeyAction implements KeyListener { + @Override + public void keyPressed(final KeyEvent e) { + if(userInput) { + return; + } + final short s = e.getKeySymbol(); + if(s == KeyEvent.VK_3) { + if( e.isAltDown() ) { + fontHeadIncr(1); + } else { + fontBottomIncr(1); + } + } + else if(s == KeyEvent.VK_4) { + if( e.isAltDown() ) { + fontHeadIncr(-1); + } else { + fontBottomIncr(-1); + } + } + else if(s == KeyEvent.VK_H) { + switchHeadBox(); + } + else if(s == KeyEvent.VK_F) { + drawFPS = !drawFPS; + } + else if(s == KeyEvent.VK_SPACE) { + nextFontSet(); + } + else if(s == KeyEvent.VK_I) { + userInput = true; + setIgnoreInput(true); + } + } + + @Override + public void keyReleased(final KeyEvent e) { + if( !e.isPrintableKey() || e.isAutoRepeat() ) { + return; + } + if(userInput) { + final short k = e.getKeySymbol(); + if( KeyEvent.VK_ENTER == k ) { + userInput = false; + setIgnoreInput(false); + } else if( KeyEvent.VK_BACK_SPACE == k && userString.length()>0) { + userString.deleteCharAt(userString.length()-1); + } else { + final char c = e.getKeyChar(); + if( font.isPrintableChar( c ) ) { + userString.append(c); + } + } + } + } + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/MSAATool.java b/src/demos/com/jogamp/opengl/demos/graph/MSAATool.java new file mode 100644 index 000000000..e0815b70a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/MSAATool.java @@ -0,0 +1,96 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GL2GL3; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilitiesImmutable; + +public class MSAATool { + public static boolean glIsEnabled(final GL gl, final int name) { + boolean isEnabled = false; + try { + isEnabled = gl.glIsEnabled(name); + final int glerr = gl.glGetError(); + if(GL.GL_NO_ERROR != glerr) { + System.err.println("glIsEnabled(0x"+Integer.toHexString(name)+") -> error 0x"+Integer.toHexString(glerr)); + } + } catch (final Exception e) { + System.err.println("Caught exception: "+e.getMessage()); + // e.printStackTrace(); + } + return isEnabled; + } + public static void dump(final GLAutoDrawable drawable) { + final float[] vf = new float[] { 0f }; + final byte[] vb = new byte[] { 0 }; + final int[] vi = new int[] { 0, 0 }; + + System.out.println("GL MSAA SETUP:"); + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + final GLCapabilitiesImmutable caps = drawable.getChosenGLCapabilities(); + System.out.println(" Caps realised "+caps); + System.out.println(" Caps sample buffers "+caps.getSampleBuffers()+", samples "+caps.getNumSamples()); + + System.out.println(" GL MULTISAMPLE "+glIsEnabled(gl, GL.GL_MULTISAMPLE)); + // sample buffers min 0, same as GLX_SAMPLE_BUFFERS_ARB or WGL_SAMPLE_BUFFERS_ARB + gl.glGetIntegerv(GL.GL_SAMPLE_BUFFERS, vi, 0); + // samples min 0 + gl.glGetIntegerv(GL.GL_SAMPLES, vi, 1); + System.out.println(" GL SAMPLE_BUFFERS "+vi[0]+", SAMPLES "+vi[1]); + + System.out.println("GL CSAA SETUP:"); + // default FALSE + System.out.println(" GL SAMPLE COVERAGE "+glIsEnabled(gl, GL.GL_SAMPLE_COVERAGE)); + // default FALSE + System.out.println(" GL SAMPLE_ALPHA_TO_COVERAGE "+glIsEnabled(gl, GL.GL_SAMPLE_ALPHA_TO_COVERAGE)); + // default FALSE + System.out.println(" GL SAMPLE_ALPHA_TO_ONE "+glIsEnabled(gl, GL.GL_SAMPLE_ALPHA_TO_ONE)); + // default FALSE, value 1, invert false + gl.glGetFloatv(GL.GL_SAMPLE_COVERAGE_VALUE, vf, 0); + gl.glGetBooleanv(GL.GL_SAMPLE_COVERAGE_INVERT, vb, 0); + System.out.println(" GL SAMPLE_COVERAGE "+glIsEnabled(gl, GL.GL_SAMPLE_COVERAGE) + + ": SAMPLE_COVERAGE_VALUE "+vf[0]+ + ", SAMPLE_COVERAGE_INVERT "+vb[0]); + dumpBlend(gl); + } + public static void dumpBlend(final GL gl) { + final int[] vi = new int[] { 0, 0, 0, 0 }; + gl.glGetIntegerv(GL.GL_BLEND, vi, 0); + gl.glGetIntegerv(GL.GL_BLEND_SRC_ALPHA, vi, 1); + gl.glGetIntegerv(GL.GL_BLEND_SRC_RGB, vi, 2); + gl.glGetIntegerv(GL.GL_BLEND_DST_RGB, vi, 3); + final boolean blendEnabled = vi[0] == GL.GL_TRUE; + System.out.println("GL_BLEND "+blendEnabled+"/"+glIsEnabled(gl, GL.GL_BLEND) + + " GL_SRC_ALPHA 0x"+Integer.toHexString(vi[1])+ + " GL_SRC_RGB 0x"+Integer.toHexString(vi[2])+ + " GL_DST_RGB 0x"+Integer.toHexString(vi[3])); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/TextRendererGLELBase.java b/src/demos/com/jogamp/opengl/demos/graph/TextRendererGLELBase.java new file mode 100644 index 000000000..61240e4a2 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/TextRendererGLELBase.java @@ -0,0 +1,291 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph; + +import java.io.IOException; + +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.TextRegionUtil; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontScale; +import com.jogamp.graph.font.FontSet; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.newt.Window; +import com.jogamp.opengl.util.PMVMatrix; + +public abstract class TextRendererGLELBase implements GLEventListener { + public final int renderModes; + + protected final int[] vbaaSampleCount; + protected final float[] staticRGBAColor = new float[] { 1f, 1f, 1f, 1f }; + + private boolean exclusivePMVMatrix = true; + private PMVMatrix sharedPMVMatrix = null; + private RenderState rs = null; + private RegionRenderer.GLCallback enableCallback=null, disableCallback=null; + protected RegionRenderer renderer = null; + protected TextRegionUtil textRenderUtil = null; + + protected final AffineTransform tempT1 = new AffineTransform(); + protected final AffineTransform tempT2 = new AffineTransform(); + + /** scale pixel, default is 1f */ + protected float pixelScale = 1.0f; + + /** dpi display resolution, queried at {@link #init(GLAutoDrawable)} if NEWT, otherwise 96. */ + protected float dpiH = 96; + + boolean flipVerticalInGLOrientation = false; + + /** + * @param fontSet e.g. default is {@link FontFactory#UBUNTU} + * @param fontFamily e.g. default is {@link FontSet#FAMILY_REGULAR} + * @param fontStylebits e.g. default is {@link FontSet#STYLE_NONE} + * @return the resulting font. + */ + public static Font getFont(final int fontSet, final int fontFamily, final int fontStylebits) { + try { + return FontFactory.get(fontSet).get(fontFamily, fontStylebits); + } catch (final IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * @param renderModes + * @param sampleCount desired multisampling sample count for msaa-rendering. + * @see #setRendererCallbacks(com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback) + */ + public TextRendererGLELBase(final int renderModes, final int[] sampleCount) { + this.renderModes = renderModes; + this.vbaaSampleCount = sampleCount; + } + + /** + * <p> + * Must be called before {@link #init(GLAutoDrawable)}. + * </p> + * @param rs + */ + public void setRenderState(final RenderState rs) { this.rs = rs; } + + /** + * In exclusive mode, impl. uses a pixelScale of 1f and orthogonal PMV on window dimensions + * and renderString uses 'height' for '1'. + * <p> + * In non-exclusive mode, i.e. shared w/ custom PMV (within another 3d scene), + * it uses the custom pixelScale and renderString uses normalized 'height', i.e. '1'. + * </p> + * <p> + * Must be called before {@link #init(GLAutoDrawable)}. + * </p> + */ + public void setSharedPMVMatrix(final PMVMatrix pmv) { + this.sharedPMVMatrix = pmv; + } + + /** + * See {@link RegionRenderer#create(RenderState, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback)}. + * <p> + * Must be called before {@link #init(GLAutoDrawable)}. + * </p> + */ + public void setRendererCallbacks(final RegionRenderer.GLCallback enable, final RegionRenderer.GLCallback disable) { + this.enableCallback = enable; + this.disableCallback = disable; + } + + public void setFlipVerticalInGLOrientation(final boolean v) { flipVerticalInGLOrientation=v; } + public final RegionRenderer getRenderer() { return renderer; } + public final TextRegionUtil getTextRenderUtil() { return textRenderUtil; } + + @Override + public void init(final GLAutoDrawable drawable) { + if( null == this.rs ) { + exclusivePMVMatrix = null == sharedPMVMatrix; + this.rs = RenderState.createRenderState(SVertex.factory(), sharedPMVMatrix); + } + this.renderer = RegionRenderer.create(rs, enableCallback, disableCallback); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + this.textRenderUtil = new TextRegionUtil(renderModes); + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + renderer.init(gl); + rs.setColorStatic(staticRGBAColor[0], staticRGBAColor[1], staticRGBAColor[2], staticRGBAColor[3]); + renderer.enable(gl, false); + + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + final float[] dpi = FontScale.perMMToPerInch( ((Window)upObj).getPixelsPerMM(new float[2]) ); + dpiH = dpi[1]; + } + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + if( null != renderer ) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + renderer.enable(gl, true); + if( exclusivePMVMatrix ) { + // renderer.reshapePerspective(gl, 45.0f, width, height, 0.1f, 1000.0f); + renderer.reshapeOrtho(width, height, 0.1f, 1000.0f); + pixelScale = 1.0f; + } else { + renderer.reshapeNotify(width, height); + } + renderer.enable(gl, false); + } + } + + @Override + public abstract void display(GLAutoDrawable drawable); + + @Override + public void dispose(final GLAutoDrawable drawable) { + if( null != renderer ) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + renderer.destroy(gl); + } + } + + int lastRow = -1; + + /** + * + * @param drawable + * @param font + * @param pixelSize Use {@link Font#toPixels(float, float)} for resolution correct pixel-size. + * @param text + * @param column + * @param tx + * @param ty + * @param tz + * @param cacheRegion + */ + public void renderString(final GLAutoDrawable drawable, + final Font font, final float pixelSize, final String text, + final int column, final float tx, final float ty, final float tz, final boolean cacheRegion) { + final int row = lastRow + 1; + renderStringImpl(drawable, font, pixelSize, text, column, row, tx, ty, tz, cacheRegion, null); + } + + public void renderString(final GLAutoDrawable drawable, + final Font font, final float pixelSize, final String text, + final int column, final float tx, final float ty, final float tz, final GLRegion region) { + final int row = lastRow + 1; + renderStringImpl(drawable, font, pixelSize, text, column, row, tx, ty, tz, false, region); + } + + /** + * + * @param drawable + * @param font + * @param pixelSize Use {@link Font#toPixels(float, float)} for resolution correct pixel-size. + * @param text + * @param column + * @param row + * @param tx + * @param ty + * @param tz + * @param cacheRegion + */ + public void renderString(final GLAutoDrawable drawable, + final Font font, final float pixelSize, final String text, + final int column, final int row, + final float tx, final float ty, final float tz, final boolean cacheRegion) { + renderStringImpl(drawable, font, pixelSize, text, column, row, tx, ty, tz, cacheRegion, null); + } + + public void renderString(final GLAutoDrawable drawable, + final Font font, final float pixelSize, final String text, + final int column, final int row, + final float tx, final float ty, final float tz, final GLRegion region) { + renderStringImpl(drawable, font, pixelSize, text, column, row, tx, ty, tz, false, region); + } + + private void renderStringImpl(final GLAutoDrawable drawable, + final Font font, final float pixelSize, final String text, + final int column, final int row, + final float tx, final float ty, final float tz, final boolean cacheRegion, final GLRegion region) { + if( null != renderer ) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + float dx = tx; + float dy; + + if( !exclusivePMVMatrix ) { + dy = 1f-ty; + } else { + final int height = drawable.getSurfaceHeight(); + dy = height-ty; + } + final float sxy = pixelScale * pixelSize; + final int newLineCount = TextRegionUtil.getCharCount(text, '\n'); + final float lineHeight = font.getLineHeight(); + dx += sxy * font.getAdvanceWidth('X') * column; + dy -= sxy * lineHeight * ( row + 1 ); + + final PMVMatrix pmvMatrix = rs.getMatrix(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + if( !exclusivePMVMatrix ) { + pmvMatrix.glPushMatrix(); + } else { + pmvMatrix.glLoadIdentity(); + } + pmvMatrix.glTranslatef(dx, dy, tz); + if( flipVerticalInGLOrientation && drawable.isGLOriented() ) { + pmvMatrix.glScalef(sxy, -1f*sxy, 1.0f); + } else { + pmvMatrix.glScalef(sxy, sxy, 1.0f); + } + renderer.enable(gl, true); + if( cacheRegion ) { + textRenderUtil.drawString3D(gl, renderer, font, text, null, vbaaSampleCount); + } else if( null != region ) { + TextRegionUtil.drawString3D(gl, region, renderer, font, text, null, vbaaSampleCount, tempT1, tempT1); + } else { + TextRegionUtil.drawString3D(gl, renderModes, renderer, font, text, null, vbaaSampleCount, tempT1, tempT1); + } + renderer.enable(gl, false); + + if( !exclusivePMVMatrix ) { + pmvMatrix.glPopMatrix(); + } + lastRow = row + newLineCount; + } + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMono.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMono.ttf Binary files differnew file mode 100644 index 000000000..c4200565a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMono.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBold.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBold.ttf Binary files differnew file mode 100644 index 000000000..0bee057ec --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBold.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBoldOblique.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBoldOblique.ttf Binary files differnew file mode 100644 index 000000000..91bbc0e8a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBoldOblique.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoOblique.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoOblique.ttf Binary files differnew file mode 100644 index 000000000..3252bdda6 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoOblique.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSans.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSans.ttf Binary files differnew file mode 100644 index 000000000..e56dc6e90 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSans.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBold.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBold.ttf Binary files differnew file mode 100644 index 000000000..66e19ecb0 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBold.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBoldOblique.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBoldOblique.ttf Binary files differnew file mode 100644 index 000000000..de8a9e153 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBoldOblique.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansOblique.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansOblique.ttf Binary files differnew file mode 100644 index 000000000..b0357eabb --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansOblique.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerif.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerif.ttf Binary files differnew file mode 100644 index 000000000..dffa1aedb --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerif.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBold.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBold.ttf Binary files differnew file mode 100644 index 000000000..e2393ad22 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBold.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBoldItalic.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBoldItalic.ttf Binary files differnew file mode 100644 index 000000000..46bc4695f --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBoldItalic.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifItalic.ttf b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifItalic.ttf Binary files differnew file mode 100644 index 000000000..d173e3566 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifItalic.ttf diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneGLListener0A.java b/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneGLListener0A.java new file mode 100644 index 000000000..990143de8 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneGLListener0A.java @@ -0,0 +1,973 @@ +/** + * 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.opengl.demos.graph.ui; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLPipelineFactory; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.es2.GearsES2; +import com.jogamp.opengl.demos.graph.FontSetDemos; +import com.jogamp.opengl.demos.graph.MSAATool; +import com.jogamp.common.net.Uri; +import com.jogamp.common.util.IOUtil; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontScale; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.graph.ui.gl.Scene; +import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.shapes.Button; +import com.jogamp.graph.ui.gl.shapes.GLButton; +import com.jogamp.graph.ui.gl.shapes.ImageButton; +import com.jogamp.graph.ui.gl.shapes.Label; +import com.jogamp.graph.ui.gl.shapes.MediaButton; +import com.jogamp.graph.ui.gl.shapes.RoundButton; +import com.jogamp.newt.MonitorDevice; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.PinchToZoomGesture; +import com.jogamp.newt.event.GestureHandler.GestureEvent; +import com.jogamp.newt.event.MouseEvent.PointerClass; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.util.GLReadBufferUtil; +import com.jogamp.opengl.util.av.GLMediaPlayer; +import com.jogamp.opengl.util.av.GLMediaPlayerFactory; +import com.jogamp.opengl.util.texture.ImageSequence; +import com.jogamp.opengl.util.texture.TextureIO; + +public class GPUUISceneGLListener0A implements GLEventListener { + static private final String defaultMediaURL = "http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4"; + + private boolean debug = false; + private boolean trace = false; + + private final float noAADPIThreshold; + private final Scene sceneUICntrl; + + /** -1 == AUTO, TBD @ init(..) */ + private int renderModes; + + private final Font font; + private final Font fontFPS; + private final Uri filmURL; + + private final float sceneDist = 3000f; + private final float zNear = 0.1f, zFar = 7000f; + + private final float relTop = 80f/100f; + private final float relMiddle = 22f/100f; + private final float relLeft = 11f/100f; + + /** Proportional Button Size to Window Height, per-vertical-pixels [PVP] */ + private final float buttonYSizePVP = 0.084f; + private final float buttonXSizePVP = 0.084f; // 0.105f; + private final float fontSizePt = 10f; + /** Proportional Font Size to Window Height for Main Text, per-vertical-pixels [PVP] */ + private final float fontSizeFixedPVP = 0.04f; + /** Proportional Font Size to Window Height for FPS Status Line, per-vertical-pixels [PVP] */ + private final float fontSizeFpsPVP = 0.03f; + private float dpiV = 96; + + /** + * Default DPI threshold value to disable {@link Region#VBAA_RENDERING_BIT VBAA}: {@value} dpi + * @see #GPUUISceneGLListener0A(float) + * @see #GPUUISceneGLListener0A(float, boolean, boolean) + */ + public static final float DefaultNoAADPIThreshold = 200f; + + private int currentText = 0; + + private String actionText = null; + private Label[] labels = null; + private String[] strings = null; + private final List<RoundButton> buttons = new ArrayList<RoundButton>(); + private int buttonsLeftCount = 0; + private Label truePtSizeLabel = null; + private Label jogampLabel = null; + private Label fpsLabel = null; + + private GLAutoDrawable cDrawable; + + private final GLReadBufferUtil screenshot; + + private final String jogamp = "JogAmp - Jogl Graph Module Demo"; + private final String truePtSize = fontSizePt+" pt font size label - true scale!"; + + private final String longText = "JOGL: Java™ Binding for the OpenGL® API.\n\n"+ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec \n"+ + "Ut purus odio, rhoncus sit amet commodo eget, ullamcorper vel\n"+ + "quam iaculis urna cursus ornare. Nullam ut felis a ante ultrices\n"+ + "In hac habitasse platea dictumst. Vivamus et mi a quam lacinia\n"+ + "Morbi quis bibendum nibh. Donec lectus orci, sagittis in consequat\n"+ + "Donec ut dolor et nulla tristique varius. In nulla magna, fermentum\n"+ + "in lorem. Maecenas in ipsum ac justo scelerisque sollicitudin.\n"+ + "\n"+ + "Lyford’s in Texas & L’Anse-aux-Griffons in Québec;\n"+ + "Kwikpak on the Yukon delta, Kvæven in Norway, Kyulu in Kenya, not Rwanda.…\n"+ + "Ytterbium in the periodic table. Are Toussaint L’Ouverture, Wölfflin, Wolfe,\n"+ + "\n"+ + "The quick brown fox jumps over the lazy dog\n"; + + /** + * @param renderModes + */ + public GPUUISceneGLListener0A(final int renderModes) { + this(null, null, renderModes, false, false); + } + + /** + * @param filmURL TODO + * @param renderModes + * @param debug + * @param trace + */ + public GPUUISceneGLListener0A(final String fontfilename, final String filmURL, final int renderModes, final boolean debug, final boolean trace) { + this(fontfilename, filmURL, 0f, renderModes, debug, trace); + } + + /** + * @param filmURL TODO + * @param noAADPIThreshold see {@link #DefaultNoAADPIThreshold} + * @param debug + * @param trace + */ + public GPUUISceneGLListener0A(final String fontfilename, final String filmURL, final float noAADPIThreshold, final boolean debug, final boolean trace) { + this(fontfilename, filmURL, noAADPIThreshold, 0, debug, trace); + } + + private GPUUISceneGLListener0A(final String fontfilename, final String filmURL, final float noAADPIThreshold, final int renderModes, final boolean debug, final boolean trace) { + this.noAADPIThreshold = noAADPIThreshold; + this.debug = debug; + this.trace = trace; + + this.renderModes = renderModes; + + try { + if( null == fontfilename ) { + font = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerif.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + } else { + font = FontFactory.get( new File( fontfilename ) ); + } + System.err.println("Font "+font.getFullFamilyName()); + + fontFPS = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMonoBold.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + System.err.println("Font FPS "+fontFPS.getFullFamilyName()); + + } catch (final IOException ioe) { + throw new RuntimeException(ioe); + } + try { + this.filmURL = Uri.cast( null != filmURL ? filmURL : defaultMediaURL ); + } catch (final URISyntaxException e1) { + throw new RuntimeException(e1); + } + { + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final RegionRenderer renderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + // renderer = RegionRenderer.create(rs, null, null); + + sceneUICntrl = new Scene(renderer, sceneDist, zNear, zFar); + // sceneUIController.setSampleCount(3); // easy on embedded devices w/ just 3 samples (default is 4)? + } + screenshot = new GLReadBufferUtil(false, false); + } + + private void rotateButtons(float[] angdeg) { + angdeg = VectorUtil.scaleVec3(angdeg, angdeg, FloatUtil.PI / 180.0f); + for(int i=0; i<buttons.size(); i++) { + buttons.get(i).getRotation().rotateByEuler( angdeg ); + } + } + private void translateButtons(final float tx, final float ty, final float tz) { + for(int i=0; i<buttons.size(); i++) { + buttons.get(i).move(tx, ty, tz); + } + } + + private void setButtonsSpacing(final float dx, final float dy) { + for(int i=0; i<buttons.size(); i++) { + final RoundButton b = buttons.get(i); + if( b instanceof Button ) { + final Button lb = (Button) b; + final float sx = lb.getSpacingX()+dx, sy = lb.getSpacingY()+dy; + System.err.println("Spacing: X "+sx+", Y "+sy); + lb.setSpacing(sx, sy); + } + } + } + + private void setButtonsCorner(final float dc) { + for(int i=0; i<buttons.size(); i++) { + final float c = buttons.get(i).getCorner()+dc; + System.err.println("Corner: "+c); + buttons.get(i).setCorner(c); + } + } + + private void resetButtons() { + for(int i=0; i<buttons.size(); i++) { + final RoundButton b = buttons.get(i); + b.getRotation().setIdentity(); + b.setCorner(RoundButton.DEFAULT_CORNER); + if( b instanceof Button ) { + ((Button)b).setSpacing(Button.DEFAULT_SPACING_X, Button.DEFAULT_SPACING_Y); + } + } + } + + public static final int BUTTON_NEXTTEXT = 100; + public static final int BUTTON_FPS = 101; + public static final int BUTTON_VSYNC = 102; + public static final int BUTTON_QUIT = 102; + public static final int BUTTON_MOVIE = 200; + public static final int BUTTON_GLEL = 200; + + public Shape getShapeByName(final int name) { + return sceneUICntrl.getShapeByName(name); + } + + private void initButtons(final GL2ES2 gl, final int width, final int height) { + final boolean pass2Mode = Region.isTwoPass( renderModes ) ; + buttons.clear(); + + final float buttonXSize = buttonXSizePVP * width; + // final float buttonYSize = buttonYSizePVP * height; + final float buttonYSize = buttonXSize / 2.5f; + System.err.println("Button Size: "+buttonXSizePVP+" x "+buttonYSizePVP+" * "+width+" x "+height+" -> "+buttonXSize+" x "+buttonYSize); + final float xStartLeft = 0f; // aligned to left edge w/ space via reshape + final float yStartTop = 0f; // aligned to top edge w/ space via reshape + final float diffX = 1.2f * buttonXSize; + final float diffY = 1.5f * buttonYSize; + + Button button = new Button(SVertex.factory(), renderModes, font, "Next Text", buttonXSize, buttonYSize); + button.setName(BUTTON_NEXTTEXT); + button.move(xStartLeft,yStartTop-diffY*buttons.size(), 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + if( null != labels[currentText] ) { + labels[currentText].setEnabled(false); + } + currentText = (currentText+1)%labels.length; + if( null != labels[currentText] ) { + labels[currentText].setEnabled(true); + } + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + button = new Button(SVertex.factory(), renderModes, font, "Show FPS", buttonXSize, buttonYSize); + button.setName(BUTTON_FPS); + button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); + button.setToggleable(true); + button.setToggle(fpsLabel.isEnabled()); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + final GLAnimatorControl a = cDrawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + fpsLabel.setEnabled(!fpsLabel.isEnabled()); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + button = new Button(SVertex.factory(), renderModes, font, "V-Sync", buttonXSize, buttonYSize); + button.setName(BUTTON_VSYNC); + button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); + button.setToggleable(true); + button.setToggle(gl.getSwapInterval()>0); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + cDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + gl.setSwapInterval(gl.getSwapInterval()<=0?1:0); + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + return true; + } + }); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + button = new Button(SVertex.factory(), renderModes, font, "< Tilt >", buttonXSize, buttonYSize); + button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + rotateButtons(new float[] { 0f, -5f, 0f}); // left-half pressed + } else { + rotateButtons(new float[] { 0f, 5f, 0f}); // right-half pressed + } + } + @Override + public void mouseWheelMoved(final MouseEvent e) { + rotateButtons(new float[] { 0f, e.getRotation()[1], 0f}); + } } ); + buttons.add(button); + + if( pass2Mode ) { // second column to the left + button = new Button(SVertex.factory(), renderModes, font, "< Samples >", buttonXSize, buttonYSize); + button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + int sampleCount = sceneUICntrl.getSampleCount(); + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + // left-half pressed + sampleCount--; + } else { + // right-half pressed + sampleCount++; + } + sampleCount = sceneUICntrl.setSampleCount(sampleCount); // validated / clipped + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + button = new Button(SVertex.factory(), renderModes, font, "< Quality >", buttonXSize, buttonYSize); + button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + int quality = shapeEvent.shape.getQuality(); + + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + // left-half pressed + if( quality > 0 ) { + quality--; + } + } else { + // right-half pressed + if( quality < Region.MAX_QUALITY ) { + quality++; + } + } + sceneUICntrl.setAllShapesQuality(quality); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + } + + button = new Button(SVertex.factory(), renderModes, font, "Quit", buttonXSize, buttonYSize); + button.setName(BUTTON_QUIT); + button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); + button.setColor(0.7f, 0.0f, 0.0f, 1.0f); + button.setLabelColor(1.2f, 1.2f, 1.2f); + button.setPressedColorMod(1.1f, 0.0f, 0.0f, 1.0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + new InterruptSource.Thread() { + @Override + public void run() { + if( null != cDrawable ) { + final GLAnimatorControl actrl = cDrawable.getAnimator(); + if( null != actrl ) { + actrl.stop(); + } + cDrawable.destroy(); + } + } }.start(); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + // second column to the left + { + final int j = 1; // column + int k = 0; // row + button = new Button(SVertex.factory(), renderModes, font, "Y Flip", buttonXSize, buttonYSize); + button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + rotateButtons(new float[] { 0f, 180f, 0f}); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + k++; + button = new Button(SVertex.factory(), renderModes, font, "X Flip", buttonXSize, buttonYSize); + button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + rotateButtons(new float[] { 180f, 0f, 0f}); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + k++; + + button = new Button(SVertex.factory(), renderModes, font, "+", buttonXSize, buttonYSize); + button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + // rel position to center + final float dx = shapeEvent.objPos[0] - shapeEvent.shape.getBounds().getCenter()[0] ; + final float dy = shapeEvent.objPos[1] - shapeEvent.shape.getBounds().getCenter()[1] ; + // per-cent position to center (remove dependency on dimension) + final float awdx = Math.abs(dx)/shapeEvent.shape.getBounds().getWidth(); + final float awdy = Math.abs(dy)/shapeEvent.shape.getBounds().getHeight(); + float tx = 0, ty = 0; + if ( awdx > awdy ) { + tx = dx < 0 ? -5 : 5; + } else { + ty = dy < 0 ? -5 : 5; + } + translateButtons(tx, ty, 0f); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + k++; + + button = new Button(SVertex.factory(), renderModes, font, "< Space >", buttonXSize, buttonYSize); + button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + final float dx, dy; + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + dx=-0.01f; dy=-0.005f; + } else { + dx=0.01f; dy=0.005f; + } + setButtonsSpacing(dx, dy); + } + @Override + public void mouseWheelMoved(final MouseEvent e) { + setButtonsSpacing(e.getRotation()[0]/100f, e.getRotation()[1]/200f); + } } ); + buttons.add(button); + k++; + + button = new Button(SVertex.factory(), renderModes, font, "< Corner >", buttonXSize, buttonYSize); + button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + final float dc; + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + dc=-0.1f; + } else { + dc=0.1f; + } + setButtonsCorner(dc); + } + @Override + public void mouseWheelMoved(final MouseEvent e) { + setButtonsCorner(e.getRotation()[1]/20f); + } } ); + buttons.add(button); + k++; + + button = new Button(SVertex.factory(), renderModes, font, "Reset", buttonXSize, buttonYSize); + button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + resetButtons(); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + k++; + + button = new Button(SVertex.factory(), renderModes, font, "Snapshot", buttonXSize, buttonYSize); + button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); + button.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + cDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + printScreen(drawable.getGL()); + return true; + } + }); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + k++; + } + + buttonsLeftCount = buttons.size(); + + final float button2XSize = 2f*buttonXSize; + final float button2YSize = 2f*buttonYSize; + final float xStartRight = -button2XSize - 8f; // aligned to right edge via reshape + final int texUnitMediaPlayer, texUnitImageButton, texUnitGLELButton; + { + // works - but not required .. + texUnitMediaPlayer=1; + texUnitImageButton=2; + texUnitGLELButton=3; + } + + if( true ) { + final GLMediaPlayer mPlayer = GLMediaPlayerFactory.createDefault(); + mPlayer.setTextureUnit(texUnitMediaPlayer); + final MediaButton mPlayerButton = new MediaButton(sceneUICntrl.getVertexFactory(), renderModes, + button2XSize, button2YSize, mPlayer); + mPlayerButton.setName(BUTTON_MOVIE); + mPlayerButton.setVerbose(true); + mPlayerButton.addDefaultEventListener(); + mPlayerButton.move(xStartRight, yStartTop - diffY*1, 0f); + mPlayerButton.setToggleable(true); + mPlayerButton.setToggle(false); // toggle == false -> mute audio + mPlayerButton.setToggleOffColorMod(0f, 1f, 0f, 1.0f); + mPlayerButton.addMouseListener(dragZoomRotateListener); + mPlayerButton.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + mPlayer.setAudioVolume( mPlayerButton.isToggleOn() ? 1f : 0f ); + } } ); + buttons.add(mPlayerButton); + mPlayer.initStream(filmURL, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.TEXTURE_COUNT_DEFAULT); + } + if( true ) { + final ImageSequence imgSeq = new ImageSequence(texUnitImageButton, true); + final ImageButton imgButton = new ImageButton(sceneUICntrl.getVertexFactory(), renderModes, + button2XSize, button2YSize, imgSeq); + try { + imgSeq.addFrame(gl, GPUUISceneGLListener0A.class, "button-released-145x53.png", TextureIO.PNG); + imgSeq.addFrame(gl, GPUUISceneGLListener0A.class, "button-pressed-145x53.png", TextureIO.PNG); + } catch (final IOException e2) { + e2.printStackTrace(); + } + imgSeq.setManualStepping(true); + imgButton.move(xStartRight, yStartTop - diffY*2.5f, 0f); + imgButton.addMouseListener(dragZoomRotateListener); + imgButton.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + imgButton.setCurrentIdx(1); + System.err.println("XXX: "+imgButton); + } + @Override + public void mouseReleased(final MouseEvent e) { + imgButton.setCurrentIdx(0); + } } ); + buttons.add(imgButton); + } + if( true ) { + // Issues w/ OSX and NewtCanvasAWT when rendering / animating + // Probably related to CALayer - FBO - FBO* (of this button) + final GLEventListener glel; + { + final GearsES2 gears = new GearsES2(0); + gears.setVerbose(false); + gears.setClearColor(new float[] { 0.9f, 0.9f, 0.9f, 1f } ); + glel = gears; + } + final GLButton glelButton = new GLButton(sceneUICntrl.getVertexFactory(), renderModes, + button2XSize, button2YSize, + texUnitGLELButton, glel, false /* useAlpha */, + (int)(button2XSize), (int)(button2YSize)); + glelButton.setName(BUTTON_GLEL); + glelButton.setToggleable(true); + glelButton.setToggle(false); // toggle == true -> animation + glelButton.setAnimate(false); + glelButton.move(xStartRight, yStartTop - diffY*4f, 0f); + glelButton.addMouseListener(dragZoomRotateListener); + glelButton.addMouseListener(new Shape.MouseGestureAdapter() { + @Override + public void mouseClicked(final MouseEvent e) { + glelButton.setAnimate( glelButton.isToggleOn() ); + } } ); + buttons.add(glelButton); + } + } + + private void initTexts() { + strings = new String[4]; + int i = 0; + + strings[i++] = "- Mouse Scroll Over Object\n"+ + " - General\n"+ + " - Z Translation\n"+ + " - Ctrl: Y-Rotation (Shift: X-Rotation)\n"+ + " - Tilt, Space and Corner\n"+ + " - Their respective action via wheel\n"+ + " (shift = other value)\n"+ + "\n"+ + "- Mouse Drag On Object\n"+ + " - Click on Object and drag mouse\n"+ + " - Current postion in status line at bottom\n"+ + "\n"+ + "- Tilt Button Rotate Whole Button Group"; + + strings[i++] = "abcdefghijklmn\nopqrstuvwxyz\n"+ + "ABCDEFGHIJKL\n"+ + "MNOPQRSTUVWXYZ\n"+ + "0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]"; + + strings[i++] = "The quick brown fox jumps over the lazy dog"; + + strings[i++] = longText; + + labels = new Label[i]; + + currentText = strings.length - 1; + } + + + private static final boolean enableOthers = true; + private static final boolean reshape_ui = false; // incomplete: button positioning + + + private void setupUI(final GLAutoDrawable drawable) { + final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); + jogampLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSizeFixed, jogamp); + jogampLabel.addMouseListener(dragZoomRotateListener); + sceneUICntrl.addShape(jogampLabel); + jogampLabel.setEnabled(enableOthers); + + final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); + System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); + truePtSizeLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSize10Pt, truePtSize); + sceneUICntrl.addShape(truePtSizeLabel); + truePtSizeLabel.setEnabled(enableOthers); + truePtSizeLabel.move(0, - 1.5f * jogampLabel.getLineHeight(), 0f); + truePtSizeLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); + + /** + * + * [Label] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 18.814816 + * [FPS] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 15.679012 + */ + final float pixelSizeFPS = fontSizeFpsPVP * drawable.getSurfaceHeight(); + fpsLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, fontFPS, pixelSizeFPS, "Nothing there yet"); + fpsLabel.addMouseListener(dragZoomRotateListener); + sceneUICntrl.addShape(fpsLabel); + fpsLabel.setEnabled(enableOthers); + fpsLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); + fpsLabel.move(0f, pixelSizeFPS * (fontFPS.getMetrics().getLineGap() - fontFPS.getMetrics().getDescent()), 0f); + + initButtons(drawable.getGL().getGL2ES2(), drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); + for(int i=0; i<buttons.size(); i++) { + sceneUICntrl.addShape(buttons.get(i)); + } + } + + private void reshapeUI(final GLAutoDrawable drawable) { + final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); + jogampLabel.setPixelSize(pixelSizeFixed); + + final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); + System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); + truePtSizeLabel.setPixelSize(pixelSize10Pt); + + /** + * + * [Label] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 18.814816 + * [FPS] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 15.679012 + */ + final float pixelSizeFPS = fontSizeFpsPVP * drawable.getSurfaceHeight(); + fpsLabel.setPixelSize(pixelSizeFPS); + + final float buttonXSize = buttonXSizePVP * drawable.getSurfaceWidth(); + // final float buttonYSize = buttonYSizePVP * height; + final float buttonYSize = buttonXSize / 2.5f; + final float button2XSize = 2f*buttonXSize; + final float button2YSize = 2f*buttonYSize; + + for(int i=0; i<buttons.size() && i<buttonsLeftCount; i++) { + buttons.get(i).setSize(buttonXSize, buttonYSize); + } + for(int i=buttonsLeftCount; i<buttons.size(); i++) { + buttons.get(i).setSize(button2XSize, button2YSize); + } + + for(int i=0; i<labels.length; i++) { + final Label l = labels[i]; + if( null != l ) { + l.setPixelSize(pixelSizeFixed); + } + } + } + + @Override + public void init(final GLAutoDrawable drawable) { + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + final Window upWin = (Window)upObj; + final MonitorDevice monitor = upWin.getMainMonitor(); + final float[] monitorDPI = MonitorDevice.perMMToPerInch( monitor.getPixelsPerMM(new float[2]) ); + final float[] sDPI = MonitorDevice.perMMToPerInch( upWin.getPixelsPerMM(new float[2]) ); + dpiV = sDPI[1]; + System.err.println("Monitor detected: "+monitor); + System.err.println("Monitor dpi: "+monitorDPI[0]+" x "+monitorDPI[1]); + System.err.println("Surface scale: native "+Arrays.toString(upWin.getMaximumSurfaceScale(new float[2]))+", current "+Arrays.toString(upWin.getCurrentSurfaceScale(new float[2]))); + System.err.println("Surface dpi "+sDPI[0]+" x "+sDPI[1]); + } else { + System.err.println("Using default DPI of "+dpiV); + } + if( 0 == renderModes && !FloatUtil.isZero(noAADPIThreshold, FloatUtil.EPSILON)) { + final boolean noAA = dpiV >= noAADPIThreshold; + final String noAAs = noAA ? " >= " : " < "; + System.err.println("AUTO RenderMode: dpi "+dpiV+noAAs+noAADPIThreshold+" -> noAA "+noAA); + renderModes = noAA ? 0 : Region.VBAA_RENDERING_BIT; + } + if(drawable instanceof GLWindow) { + System.err.println("GPUUISceneGLListener0A: init (1)"); + final GLWindow glw = (GLWindow) drawable; + sceneUICntrl.attachInputListenerTo(glw); + } else { + System.err.println("GPUUISceneGLListener0A: init (0)"); + } + cDrawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(debug) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) ).getGL2ES2(); + } + if(trace) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2(); + } + System.err.println(JoglVersion.getGLInfo(gl, null, false /* withCapsAndExts */).toString()); + System.err.println("VSync Swap Interval: "+gl.getSwapInterval()); + System.err.println("Chosen: "+drawable.getChosenGLCapabilities()); + MSAATool.dump(drawable); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_BLEND); + + initTexts(); + + sceneUICntrl.init(drawable); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + + setupUI(drawable); + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + System.err.println("GPUUISceneGLListener0A: reshape"); + + // + // Layout all shapes: Relational move regarding window coordinates + // + final float dw = width - lastWidth; + final float dh = height - lastHeight; + + final float dz = 0f; + final float dyTop = dh * relTop; + final float dxLeft = dw * relLeft; + final float dxRight = dw; + + if( reshape_ui ) { + reshapeUI(drawable); + } + for(int i=0; i<buttons.size() && i<buttonsLeftCount; i++) { + buttons.get(i).move(dxLeft, dyTop, dz); + } + for(int i=buttonsLeftCount; i<buttons.size(); i++) { + buttons.get(i).move(dxRight, dyTop, dz); + } + + final float dxMiddleAbs = width * relMiddle; + final float dyTopLabelAbs = drawable.getSurfaceHeight() - 2f*jogampLabel.getLineHeight(); + jogampLabel.setPosition(dxMiddleAbs, dyTopLabelAbs, dz); + truePtSizeLabel.setPosition(dxMiddleAbs, dyTopLabelAbs, dz); + truePtSizeLabel.setPosition(dxMiddleAbs, dyTopLabelAbs - 1.5f * jogampLabel.getLineHeight(), 0f); + fpsLabel.move(0f, 0f, 0f); + if( null != labels[currentText] ) { + labels[currentText].setPosition(dxMiddleAbs, + dyTopLabelAbs - 1.5f * jogampLabel.getLineHeight() + - 1.5f * truePtSizeLabel.getLineHeight(), 0f); + System.err.println("Label["+currentText+"] MOVE: "+labels[currentText]); + System.err.println("Label["+currentText+"] MOVE: "+Arrays.toString(labels[currentText].getPosition())); + } + + sceneUICntrl.reshape(drawable, x, y, width, height); + + lastWidth = width; + lastHeight = height; + } + float lastWidth = 0f, lastHeight = 0f; + + @Override + public void dispose(final GLAutoDrawable drawable) { + System.err.println("GPUUISceneGLListener0A: dispose"); + + sceneUICntrl.dispose(drawable); // disposes all registered UIShapes + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + screenshot.dispose(gl); + } + + private int shotCount = 0; + + public void printScreen(final GL gl) { + final RegionRenderer renderer = sceneUICntrl.getRenderer(); + final String modeS = Region.getRenderModeString(jogampLabel.getRenderModes()); + final String filename = String.format((Locale)null, "GraphUIDemo-shot%03d-%03dx%03d-S_%s_%02d.png", + shotCount++, renderer.getWidth(), renderer.getHeight(), + modeS, sceneUICntrl.getSampleCount()); + gl.glFinish(); // just make sure rendering finished .. + if(screenshot.readPixels(gl, false)) { + screenshot.write(new File(filename)); + System.err.println("Wrote: "+filename); + } + } + + @Override + public void display(final GLAutoDrawable drawable) { + // System.err.println("GPUUISceneGLListener0A: display"); + + if(null == labels[currentText]) { + final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); + final float dyTop = drawable.getSurfaceHeight() - 2f*jogampLabel.getLineHeight(); + final float dxMiddle = drawable.getSurfaceWidth() * relMiddle; + labels[currentText] = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSizeFixed, strings[currentText]); + labels[currentText].setColor(0.1f, 0.1f, 0.1f, 1.0f); + labels[currentText].setEnabled(enableOthers); + labels[currentText].move(dxMiddle, + dyTop - 1.5f * jogampLabel.getLineHeight() + - 1.5f * truePtSizeLabel.getLineHeight(), 0f); + labels[currentText].addMouseListener(dragZoomRotateListener); + sceneUICntrl.addShape(labels[currentText]); + System.err.println("Label["+currentText+"] CTOR: "+labels[currentText]); + System.err.println("Label["+currentText+"] CTOR: "+Arrays.toString(labels[currentText].getPosition())); + } + if( fpsLabel.isEnabled() ) { + final String text; + if( null == actionText ) { + text = sceneUICntrl.getStatusText(drawable, renderModes, fpsLabel.getQuality(), dpiV); + } else if( null != drawable.getAnimator() ) { + text = Scene.getStatusText(drawable.getAnimator())+", "+actionText; + } else { + text = actionText; + } + if( fpsLabel.setText(text) ) { // marks dirty only if text differs. + // System.err.println(text); + } + } + sceneUICntrl.display(drawable); + } + + public void attachInputListenerTo(final GLWindow window) { + sceneUICntrl.attachInputListenerTo(window); + } + + public void detachInputListenerFrom(final GLWindow window) { + sceneUICntrl.detachInputListenerFrom(window); + } + + /** + * We can share this instance w/ all UI elements, + * since only mouse action / gesture is complete for a single one (press, drag, released and click). + */ + private final Shape.MouseGestureAdapter dragZoomRotateListener = new Shape.MouseGestureAdapter() { + @Override + public void mouseReleased(final MouseEvent e) { + actionText = null; + } + + @Override + public void mouseDragged(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + if( e.getPointerCount() == 1 ) { + final float[] tx = shapeEvent.shape.getPosition(); + actionText = String.format((Locale)null, "Pos %6.2f / %6.2f / %6.2f", tx[0], tx[1], tx[2]); + } + } + + @Override + public void mouseWheelMoved(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + final boolean isOnscreen = PointerClass.Onscreen == e.getPointerType(0).getPointerClass(); + if( 0 == ( ~InputEvent.BUTTONALL_MASK & e.getModifiers() ) && !isOnscreen ) { + // offscreen vertical mouse wheel zoom + final float tz = 100f*e.getRotation()[1]; // vertical: wheel + System.err.println("Rotate.Zoom.W: "+tz); + shapeEvent.shape.move(0f, 0f, tz); + } else if( isOnscreen || e.isControlDown() ) { + final float[] rot = VectorUtil.scaleVec3(e.getRotation(), e.getRotation(), FloatUtil.PI / 180.0f); + if( isOnscreen ) { + System.err.println("XXX: "+e); + // swap axis for onscreen rotation matching natural feel + final float tmp = rot[0]; rot[0] = rot[1]; rot[1] = tmp; + VectorUtil.scaleVec3(rot, rot, 2f); + } + shapeEvent.shape.getRotation().rotateByEuler( rot ); + } + } + @Override + public void gestureDetected(final GestureEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + if( e instanceof PinchToZoomGesture.ZoomEvent ) { + final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) e; + final float tz = ze.getDelta() * ze.getScale(); + System.err.println("Rotate.Zoom.G: "+tz); + shapeEvent.shape.move(0f, 0f, tz); + } + } }; +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneNewtDemo.java b/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneNewtDemo.java new file mode 100644 index 000000000..4ab5326d5 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneNewtDemo.java @@ -0,0 +1,201 @@ +/** + * 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.opengl.demos.graph.ui; + +import com.jogamp.nativewindow.ScalableSurface; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.util.MiscUtils; +import com.jogamp.common.util.VersionUtil; +import com.jogamp.graph.curve.Region; +import com.jogamp.newt.Display; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.caps.NonFSAAGLCapsChooser; + +public class GPUUISceneNewtDemo { + static final boolean DEBUG = false; + static final boolean TRACE = false; + + static void sleep(final long ms) { + try { + Thread.sleep(ms); + } catch (final InterruptedException ie) {} + } + + public static void main(final String[] args) { + int SceneMSAASamples = 0; + boolean GraphVBAAMode = false; + boolean GraphMSAAMode = false; + float GraphAutoMode = GPUUISceneGLListener0A.DefaultNoAADPIThreshold; + + final float[] reqSurfacePixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; + + String fontfilename = null; + String filmURL = null; + + int width = 1280, height = 720; + + boolean forceES2 = false; + boolean forceES3 = false; + boolean forceGL3 = false; + boolean forceGLDef = false; + + if( 0 != args.length ) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-smsaa")) { + i++; + SceneMSAASamples = MiscUtils.atoi(args[i], SceneMSAASamples); + GraphMSAAMode = false; + GraphVBAAMode = false; + GraphAutoMode = 0f; + } else if(args[i].equals("-gmsaa")) { + GraphMSAAMode = true; + GraphVBAAMode = false; + GraphAutoMode = 0f; + } else if(args[i].equals("-gvbaa")) { + GraphMSAAMode = false; + GraphVBAAMode = true; + GraphAutoMode = 0f; + } else if(args[i].equals("-gauto")) { + GraphMSAAMode = false; + GraphVBAAMode = true; + i++; + GraphAutoMode = MiscUtils.atof(args[i], GraphAutoMode); + } else if(args[i].equals("-font")) { + i++; + fontfilename = args[i]; + } else if(args[i].equals("-width")) { + i++; + width = MiscUtils.atoi(args[i], width); + } else if(args[i].equals("-height")) { + i++; + height = MiscUtils.atoi(args[i], height); + } else if(args[i].equals("-pixelScale")) { + i++; + final float pS = MiscUtils.atof(args[i], reqSurfacePixelScale[0]); + reqSurfacePixelScale[0] = pS; + reqSurfacePixelScale[1] = pS; + } else if(args[i].equals("-es2")) { + forceES2 = true; + } else if(args[i].equals("-es3")) { + forceES3 = true; + } else if(args[i].equals("-gl3")) { + forceGL3 = true; + } else if(args[i].equals("-gldef")) { + forceGLDef = true; + } else if(args[i].equals("-film")) { + i++; + filmURL = args[i]; + } + } + } + System.err.println("forceES2 "+forceES2); + System.err.println("forceES3 "+forceES3); + System.err.println("forceGL3 "+forceGL3); + System.err.println("forceGLDef "+forceGLDef); + System.err.println("Desired win size "+width+"x"+height); + System.err.println("Scene MSAA Samples "+SceneMSAASamples); + System.err.println("Graph MSAA Mode "+GraphMSAAMode); + System.err.println("Graph VBAA Mode "+GraphVBAAMode); + System.err.println("Graph Auto Mode "+GraphAutoMode+" no-AA dpi threshold"); + + final Display dpy = NewtFactory.createDisplay(null); + final Screen screen = NewtFactory.createScreen(dpy, 0); + System.err.println(VersionUtil.getPlatformInfo()); + System.err.println(JoglVersion.getAllAvailableCapabilitiesInfo(dpy.getGraphicsDevice(), null).toString()); + + final GLProfile glp; + if(forceGLDef) { + glp = GLProfile.getDefault(); + } else if(forceGL3) { + glp = GLProfile.get(GLProfile.GL3); + } else if(forceES3) { + glp = GLProfile.get(GLProfile.GLES3); + } else if(forceES2) { + glp = GLProfile.get(GLProfile.GLES2); + } else { + glp = GLProfile.getGL2ES2(); + } + System.err.println("GLProfile: "+glp); + final GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(4); + if( SceneMSAASamples > 0 ) { + caps.setSampleBuffers(true); + caps.setNumSamples(SceneMSAASamples); + } + System.out.println("Requested: " + caps); + + final int rmode; + if( GraphVBAAMode ) { + rmode = Region.VBAA_RENDERING_BIT; + } else if( GraphMSAAMode ) { + rmode = Region.MSAA_RENDERING_BIT; + } else { + rmode = 0; + } + + final GLWindow window = GLWindow.create(screen, caps); + if( 0 == SceneMSAASamples ) { + window.setCapabilitiesChooser(new NonFSAAGLCapsChooser(true)); + } + window.setSize(width, height); + window.setTitle("GraphUI Newt Demo: graph["+Region.getRenderModeString(rmode)+"], msaa "+SceneMSAASamples); + window.setSurfaceScale(reqSurfacePixelScale); + // final float[] valReqSurfacePixelScale = window.getRequestedSurfaceScale(new float[2]); + + final GPUUISceneGLListener0A scene = 0 < GraphAutoMode ? new GPUUISceneGLListener0A(fontfilename, filmURL, GraphAutoMode, DEBUG, TRACE) : + new GPUUISceneGLListener0A(fontfilename, filmURL, rmode, DEBUG, TRACE); + + window.addGLEventListener(scene); + scene.attachInputListenerTo(window); + + final Animator animator = new Animator(); + animator.setUpdateFPSFrames(5*60, null); + animator.add(window); + + window.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyed(final WindowEvent e) { + animator.stop(); + } + }); + + window.setVisible(true); + animator.start(); + + // sleep(3000); + // final UIShape movie = scene.getWidget(GPUUISceneGLListener0A.BUTTON_MOVIE); + } + +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneTextAnim01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneTextAnim01.java new file mode 100644 index 000000000..45bfd53f1 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneTextAnim01.java @@ -0,0 +1,351 @@ +/** + * 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.opengl.demos.graph.ui; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Locale; + +import com.jogamp.common.util.IOUtil; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontScale; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.graph.ui.gl.Scene; +import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.shapes.Label; +import com.jogamp.newt.MonitorDevice; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.GestureHandler.GestureEvent; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseEvent.PointerClass; +import com.jogamp.newt.event.PinchToZoomGesture; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLPipelineFactory; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.demos.graph.FontSetDemos; +import com.jogamp.opengl.demos.graph.MSAATool; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.util.GLReadBufferUtil; + +public class GPUUISceneTextAnim01 implements GLEventListener { + + private boolean debug = false; + private boolean trace = false; + + private final float noAADPIThreshold; + private final Scene sceneUICntrl; + + /** -1 == AUTO, TBD @ init(..) */ + private int renderModes; + + private final Font font; + private final Font fontFPS; + + private final float sceneDist = 3000f; + private final float zNear = 0.1f, zFar = 7000f; + + // private final float relTop = 80f/100f; + private final float relMiddle = 22f/100f; + // private final float relLeft = 11f/100f; + + private final float fontSizePt = 10f; + /** Proportional Font Size to Window Height for Main Text, per-vertical-pixels [PVP] */ + private final float fontSizeFixedPVP = 0.04f; + /** Proportional Font Size to Window Height for FPS Status Line, per-vertical-pixels [PVP] */ + private final float fontSizeFpsPVP = 0.03f; + private float dpiV = 96; + + /** + * Default DPI threshold value to disable {@link Region#VBAA_RENDERING_BIT VBAA}: {@value} dpi + * @see #GPUUISceneGLListener0A(float) + * @see #GPUUISceneGLListener0A(float, boolean, boolean) + */ + public static final float DefaultNoAADPIThreshold = 200f; + + private String actionText = null; + private Label jogampLabel = null; + private Label fpsLabel = null; + + // private GLAutoDrawable cDrawable; + + private final GLReadBufferUtil screenshot; + + private final String jogamp = "JogAmp - Jogl Graph Module Demo"; + + // private final String longText = "JOGL: Java™ Binding for the OpenGL® API."; + + public GPUUISceneTextAnim01(final String fontfilename, final float noAADPIThreshold, final int renderModes, final boolean debug, final boolean trace) { + this.noAADPIThreshold = noAADPIThreshold; + this.debug = debug; + this.trace = trace; + + this.renderModes = renderModes; + + try { + if( null == fontfilename ) { + font = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerif.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + } else { + font = FontFactory.get( new File( fontfilename ) ); + } + System.err.println("Font "+font.getFullFamilyName()); + + fontFPS = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMonoBold.ttf", + FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); + System.err.println("Font FPS "+fontFPS.getFullFamilyName()); + + } catch (final IOException ioe) { + throw new RuntimeException(ioe); + } + + { + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final RegionRenderer renderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + // renderer = RegionRenderer.create(rs, null, null); + + sceneUICntrl = new Scene(renderer, sceneDist, zNear, zFar); + // sceneUIController.setSampleCount(3); // easy on embedded devices w/ just 3 samples (default is 4)? + } + screenshot = new GLReadBufferUtil(false, false); + } + + private void setupUI(final GLAutoDrawable drawable) { + final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); + jogampLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSizeFixed, jogamp); + jogampLabel.addMouseListener(dragZoomRotateListener); + sceneUICntrl.addShape(jogampLabel); + jogampLabel.setEnabled(true); + + final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); + System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); + + /** + * + * [Label] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 18.814816 + * [FPS] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 15.679012 + */ + final float pixelSizeFPS = fontSizeFpsPVP * drawable.getSurfaceHeight(); + fpsLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, fontFPS, pixelSizeFPS, "Nothing there yet"); + fpsLabel.addMouseListener(dragZoomRotateListener); + sceneUICntrl.addShape(fpsLabel); + fpsLabel.setEnabled(true); + fpsLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); + fpsLabel.move(0f, pixelSizeFPS * (fontFPS.getMetrics().getLineGap() - fontFPS.getMetrics().getDescent()), 0f); + } + + @Override + public void init(final GLAutoDrawable drawable) { + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + final Window upWin = (Window)upObj; + final MonitorDevice monitor = upWin.getMainMonitor(); + final float[] monitorDPI = MonitorDevice.perMMToPerInch( monitor.getPixelsPerMM(new float[2]) ); + final float[] sDPI = MonitorDevice.perMMToPerInch( upWin.getPixelsPerMM(new float[2]) ); + dpiV = sDPI[1]; + System.err.println("Monitor detected: "+monitor); + System.err.println("Monitor dpi: "+monitorDPI[0]+" x "+monitorDPI[1]); + System.err.println("Surface scale: native "+Arrays.toString(upWin.getMaximumSurfaceScale(new float[2]))+", current "+Arrays.toString(upWin.getCurrentSurfaceScale(new float[2]))); + System.err.println("Surface dpi "+sDPI[0]+" x "+sDPI[1]); + } else { + System.err.println("Using default DPI of "+dpiV); + } + if( 0 == renderModes && !FloatUtil.isZero(noAADPIThreshold, FloatUtil.EPSILON)) { + final boolean noAA = dpiV >= noAADPIThreshold; + final String noAAs = noAA ? " >= " : " < "; + System.err.println("AUTO RenderMode: dpi "+dpiV+noAAs+noAADPIThreshold+" -> noAA "+noAA); + renderModes = noAA ? 0 : Region.VBAA_RENDERING_BIT; + } + if(drawable instanceof GLWindow) { + System.err.println("GPUUISceneGLListener0A: init (1)"); + final GLWindow glw = (GLWindow) drawable; + sceneUICntrl.attachInputListenerTo(glw); + } else { + System.err.println("GPUUISceneGLListener0A: init (0)"); + } + // cDrawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(debug) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) ).getGL2ES2(); + } + if(trace) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2(); + } + System.err.println(JoglVersion.getGLInfo(gl, null, false /* withCapsAndExts */).toString()); + System.err.println("VSync Swap Interval: "+gl.getSwapInterval()); + System.err.println("Chosen: "+drawable.getChosenGLCapabilities()); + MSAATool.dump(drawable); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_BLEND); + + sceneUICntrl.init(drawable); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + + setupUI(drawable); + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + System.err.println("GPUUISceneGLListener0A: reshape"); + + // + // Layout all shapes: Relational move regarding window coordinates + // + final float dz = 0f; + + final float dxMiddleAbs = width * relMiddle; + final float dyTopLabelAbs = drawable.getSurfaceHeight() - 2f*jogampLabel.getLineHeight(); + jogampLabel.setPosition(dxMiddleAbs, dyTopLabelAbs, dz); + fpsLabel.move(0f, 0f, 0f); + + sceneUICntrl.reshape(drawable, x, y, width, height); + + lastWidth = width; + lastHeight = height; + } + float lastWidth = 0f, lastHeight = 0f; + + @Override + public void dispose(final GLAutoDrawable drawable) { + System.err.println("GPUUISceneGLListener0A: dispose"); + + sceneUICntrl.dispose(drawable); // disposes all registered UIShapes + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + screenshot.dispose(gl); + } + + private int shotCount = 0; + + public void printScreen(final GL gl) { + final RegionRenderer renderer = sceneUICntrl.getRenderer(); + final String modeS = Region.getRenderModeString(jogampLabel.getRenderModes()); + final String filename = String.format((Locale)null, "GraphUIDemo-shot%03d-%03dx%03d-S_%s_%02d.png", + shotCount++, renderer.getWidth(), renderer.getHeight(), + modeS, sceneUICntrl.getSampleCount()); + gl.glFinish(); // just make sure rendering finished .. + if(screenshot.readPixels(gl, false)) { + screenshot.write(new File(filename)); + System.err.println("Wrote: "+filename); + } + } + + @Override + public void display(final GLAutoDrawable drawable) { + if( fpsLabel.isEnabled() ) { + final String text; + if( null == actionText ) { + text = sceneUICntrl.getStatusText(drawable, renderModes, fpsLabel.getQuality(), dpiV); + } else if( null != drawable.getAnimator() ) { + text = Scene.getStatusText(drawable.getAnimator())+", "+actionText; + } else { + text = actionText; + } + if( fpsLabel.setText(text) ) { // marks dirty only if text differs. + System.err.println(text); + } + } + sceneUICntrl.display(drawable); + } + + public void attachInputListenerTo(final GLWindow window) { + sceneUICntrl.attachInputListenerTo(window); + } + + public void detachInputListenerFrom(final GLWindow window) { + sceneUICntrl.detachInputListenerFrom(window); + } + + /** + * We can share this instance w/ all UI elements, + * since only mouse action / gesture is complete for a single one (press, drag, released and click). + */ + private final Shape.MouseGestureAdapter dragZoomRotateListener = new Shape.MouseGestureAdapter() { + @Override + public void mouseReleased(final MouseEvent e) { + actionText = null; + } + + @Override + public void mouseDragged(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + if( e.getPointerCount() == 1 ) { + final float[] tx = shapeEvent.shape.getPosition(); + actionText = String.format((Locale)null, "Pos %6.2f / %6.2f / %6.2f", tx[0], tx[1], tx[2]); + } + } + + @Override + public void mouseWheelMoved(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + final boolean isOnscreen = PointerClass.Onscreen == e.getPointerType(0).getPointerClass(); + if( 0 == ( ~InputEvent.BUTTONALL_MASK & e.getModifiers() ) && !isOnscreen ) { + // offscreen vertical mouse wheel zoom + final float tz = 100f*e.getRotation()[1]; // vertical: wheel + System.err.println("Rotate.Zoom.W: "+tz); + shapeEvent.shape.move(0f, 0f, tz); + } else if( isOnscreen || e.isControlDown() ) { + final float[] rot = VectorUtil.scaleVec3(e.getRotation(), e.getRotation(), FloatUtil.PI / 180.0f); + if( isOnscreen ) { + System.err.println("XXX: "+e); + // swap axis for onscreen rotation matching natural feel + final float tmp = rot[0]; rot[0] = rot[1]; rot[1] = tmp; + VectorUtil.scaleVec3(rot, rot, 2f); + } + shapeEvent.shape.getRotation().rotateByEuler( rot ); + } + } + @Override + public void gestureDetected(final GestureEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + if( e instanceof PinchToZoomGesture.ZoomEvent ) { + final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) e; + final float tz = ze.getDelta() * ze.getScale(); + System.err.println("Rotate.Zoom.G: "+tz); + shapeEvent.shape.move(0f, 0f, tz); + } + } }; +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UIShapeDemo01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UIShapeDemo01.java new file mode 100644 index 000000000..b89b3e2b9 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UIShapeDemo01.java @@ -0,0 +1,569 @@ +/** + * 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.opengl.demos.graph.ui; + +import java.io.File; +import java.io.IOException; + +import com.jogamp.opengl.FPSCounter; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLPipelineFactory; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.demos.graph.MSAATool; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.curve.opengl.TextRegionUtil; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontSet; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.shapes.Button; +import com.jogamp.graph.ui.gl.shapes.CrossHair; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLReadBufferUtil; +import com.jogamp.opengl.util.PMVMatrix; + +/** + * Basic UIShape and Type Rendering demo. + * + * Action Keys: + * - 1/2: zoom in/out + * - 4/5: increase/decrease shape/text spacing + * - 6/7: increase/decrease corner size + * - 0/9: rotate + * - v: toggle v-sync + * - s: screenshot + */ +public class UIShapeDemo01 implements GLEventListener { + static final boolean DEBUG = false; + static final boolean TRACE = false; + + public static void main(final String[] args) throws IOException { + Font font = null; + if( 0 != args.length ) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-font")) { + i++; + font = FontFactory.get(new File(args[i])); + } + } + } + if( null == font ) { + font = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_SERIF); + } + System.err.println("Font: "+font.getFullFamilyName()); + + final GLProfile glp = GLProfile.getGL2ES2(); + final GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(4); + caps.setSampleBuffers(true); + caps.setNumSamples(4); + System.out.println("Requested: " + caps); + + final GLWindow window = GLWindow.create(caps); + // window.setPosition(10, 10); + window.setSize(800, 400); + window.setTitle(UIShapeDemo01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final UIShapeDemo01 uiGLListener = new UIShapeDemo01(font, Region.COLORCHANNEL_RENDERING_BIT, rs, DEBUG, TRACE); + uiGLListener.attachInputListenerTo(window); + window.addGLEventListener(uiGLListener); + window.setVisible(true); + + final Animator animator = new Animator(); + // animator.setUpdateFPSFrames(60, System.err); + animator.add(window); + + window.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(final KeyEvent arg0) { + if(arg0.getKeyCode() == KeyEvent.VK_F4) { + new InterruptSource.Thread() { + @Override + public void run() { + window.destroy(); + } }.start(); + } + } + }); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyed(final WindowEvent e) { + animator.stop(); + } + }); + + animator.start(); + } + + private final Font font; + private final GLReadBufferUtil screenshot; + private final int renderModes; + private final RegionRenderer rRenderer; + private final boolean debug; + private final boolean trace; + + private final Button button; + private final CrossHair crossHair; + + private KeyAction keyAction; + private MouseAction mouseAction; + + private volatile GLAutoDrawable autoDrawable = null; + + private final float[] position = new float[] {0,0,0}; + + private static final float xTran = 0f; + private static final float yTran = 0f; + private static final float zTran = -1/5f; + private static final float zNear = 0.1f; + private static final float zFar = 7000.0f; + + boolean ignoreInput = false; + + protected final AffineTransform tempT1 = new AffineTransform(); + protected final AffineTransform tempT2 = new AffineTransform(); + + public UIShapeDemo01(final Font font, final int renderModes, final RenderState rs, final boolean debug, final boolean trace) { + this.font = font; + this.renderModes = renderModes; + this.rRenderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + this.debug = debug; + this.trace = trace; + this.screenshot = new GLReadBufferUtil(false, false); + + button = new Button(SVertex.factory(), renderModes, font, "Click me!", 1/8f, 1/16f); + button.setLabelColor(0.0f,0.0f,0.0f); + /** Button defaults ! + button.setLabelColor(1.0f,1.0f,1.0f); + button.setButtonColor(0.6f,0.6f,0.6f); + button.setCorner(1.0f); + button.setSpacing(2.0f); + */ + System.err.println(button); + crossHair = new CrossHair(SVertex.factory(), renderModes, 1/20f, 1/20f, 1/1000f); + crossHair.setColor(0f,0f,1f,1f); + crossHair.setEnabled(true); + } + + public final RegionRenderer getRegionRenderer() { return rRenderer; } + public final float[] getPosition() { return position; } + + @Override + public void init(final GLAutoDrawable drawable) { + autoDrawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(debug) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) ).getGL2ES2(); + } + if(trace) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2(); + } + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + getRegionRenderer().init(gl); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); + MSAATool.dump(drawable); + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int xstart, final int ystart, final int width, final int height) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glViewport(xstart, ystart, width, height); + rRenderer.reshapePerspective(45.0f, width, height, zNear, zFar); + // rRenderer.reshapeOrtho(width, height, zNear, zFar); + + lastWidth = width; + lastHeight = height; + if( drawable instanceof Window ) { + ((Window)drawable).setTitle(UIShapeDemo01.class.getSimpleName()+": "+drawable.getSurfaceWidth()+" x "+drawable.getSurfaceHeight()); + } + } + float lastWidth = 0f, lastHeight = 0f; + + final int[] sampleCount = { 4 }; + + private void drawShape(final GL2ES2 gl, final PMVMatrix pmv, final RegionRenderer renderer, final Shape shape) { + pmv.glPushMatrix(); + shape.setTransform(pmv); + shape.drawShape(gl, renderer, sampleCount); + pmv.glPopMatrix(); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + final RegionRenderer renderer = getRegionRenderer(); + final PMVMatrix pmv = renderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + pmv.glTranslatef(xTran, yTran, zTran); + renderer.enable(gl, true); + drawShape(gl, pmv, renderer, button); + drawShape(gl, pmv, renderer, crossHair); + { + final String text = "Hello Origin."; + final float full_width_o; + { + final float orthoDist = -zTran; // assume orthogonal plane at -zTran + float glWinX = 0; + float glWinY = 0; + final float winZ = FloatUtil.getOrthoWinZ(orthoDist, zNear, zFar); + final float[] objCoord0 = new float[3]; + final float[] objCoord1 = new float[3]; + if( pmv.gluUnProject(glWinX, glWinY, winZ, renderer.getViewport(), 0, objCoord0, 0) ) { + if( once ) { + System.err.printf("winToObjCoord: win [%f, %f, %f] -> obj [%f, %f, %f]%n", glWinX, glWinY, winZ, objCoord0[0], objCoord0[1], objCoord0[2]); + } + } + glWinX = drawable.getSurfaceWidth(); + glWinY = drawable.getSurfaceHeight(); + if( pmv.gluUnProject(glWinX, glWinY, winZ, renderer.getViewport(), 0, objCoord1, 0) ) { + if( once ) { + System.err.printf("winToObjCoord: win [%f, %f, %f] -> obj [%f, %f, %f]%n", glWinX, glWinY, winZ, objCoord1[0], objCoord1[1], objCoord1[2]); + } + } + full_width_o = objCoord1[0] - objCoord0[0]; + } + final AABBox txt_box_em = font.getGlyphBounds(text, tempT1, tempT2); + final float full_width_s = full_width_o / txt_box_em.getWidth(); + final float txt_scale = full_width_s/2f; + pmv.glPushMatrix(); + pmv.glScalef(txt_scale, txt_scale, 1f); + pmv.glTranslatef(-txt_box_em.getWidth(), 0f, 0f); + final AABBox txt_box_r = TextRegionUtil.drawString3D(gl, renderModes, renderer, font, text, new float[] { 0, 0, 0, 1 }, sampleCount, tempT1, tempT2); + if( once ) { + final AABBox txt_box_em2 = font.getGlyphShapeBounds(null, text); + System.err.println("XXX: full_width: "+full_width_o+" / "+txt_box_em.getWidth()+" -> "+full_width_s); + System.err.println("XXX: txt_box_em "+txt_box_em); + System.err.println("XXX: txt_box_e2 "+txt_box_em2); + System.err.println("XXX: txt_box_rg "+txt_box_r); + once = false; + } + pmv.glPopMatrix(); + } + renderer.enable(gl, false); + } + static boolean once = true; + + @Override + public void dispose(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + button.destroy(gl, getRegionRenderer()); + crossHair.destroy(gl, getRegionRenderer()); + + autoDrawable = null; + screenshot.dispose(gl); + rRenderer.destroy(gl); + } + + /** Attach the input listener to the window */ + public void attachInputListenerTo(final GLWindow window) { + if ( null == keyAction ) { + keyAction = new KeyAction(); + window.addKeyListener(keyAction); + } + if ( null == mouseAction ) { + mouseAction = new MouseAction(); + window.addMouseListener(mouseAction); + } + } + + public void detachFrom(final GLWindow window) { + if ( null == keyAction ) { + return; + } + if ( null == mouseAction ) { + return; + } + window.removeGLEventListener(this); + window.removeKeyListener(keyAction); + window.removeMouseListener(mouseAction); + } + + public void printScreen(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) throws GLException, IOException { + final String sw = String.format("-%03dx%03d-Z%04d-T%04d-%s", drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), (int)Math.abs(zTran), 0, objName); + + final String filename = dir + tech + sw +".png"; + if(screenshot.readPixels(drawable.getGL(), false)) { + screenshot.write(new File(filename)); + } + } + + int screenshot_num = 0; + + public void setIgnoreInput(final boolean v) { + ignoreInput = v; + } + public boolean getIgnoreInput() { + return ignoreInput; + } + + public class MouseAction implements MouseListener{ + + @Override + public void mouseClicked(final MouseEvent e) { + + } + + @Override + public void mouseEntered(final MouseEvent e) { + } + + @Override + public void mouseExited(final MouseEvent e) { + } + + @Override + public void mousePressed(final MouseEvent e) { + autoDrawable.invoke(false, new GLRunnable() { // avoid data-race + @Override + public boolean run(final GLAutoDrawable drawable) { + System.err.println("\n\nMouse: "+e); + + final RegionRenderer renderer = getRegionRenderer(); + final PMVMatrix pmv = renderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + pmv.glTranslatef(xTran, yTran, zTran); + + // flip to GL window coordinates, origin bottom-left + final int[] viewport = renderer.getViewport(new int[4]); + final int glWinX = e.getX(); + final int glWinY = viewport[3] - e.getY() - 1; + + { + pmv.glPushMatrix(); + button.setTransform(pmv); + + final float[] objPos = new float[3]; + System.err.println("\n\nButton: "+button); + button.winToObjCoord(renderer, glWinX, glWinY, objPos); + System.err.println("Button: Click: Win "+glWinX+"/"+glWinY+" -> Obj "+objPos[0]+"/"+objPos[1]+"/"+objPos[1]); + + final int[] surfaceSize = new int[2]; + button.getSurfaceSize(renderer, surfaceSize); + System.err.println("Button: Size: Pixel "+surfaceSize[0]+" x "+surfaceSize[1]); + + pmv.glPopMatrix(); + } + { + pmv.glPushMatrix(); + crossHair.setTransform(pmv); + + final float[] objPosC = crossHair.getBounds().getCenter(); + final int[] objWinPos = new int[2]; + System.err.println("\n\nCrossHair: "+crossHair); + if( crossHair.objToWinCoord(renderer, objPosC, objWinPos) ) { + System.err.println("CrossHair: Obj: Obj "+objPosC[0]+"/"+objPosC[1]+"/"+objPosC[1]+" -> Win "+objWinPos[0]+"/"+objWinPos[1]); + } + + final float[] objPos2 = new float[3]; + crossHair.winToObjCoord(renderer, objWinPos[0], objWinPos[1], objPos2); + System.err.println("CrossHair: Obj: Win "+objWinPos[0]+"/"+objWinPos[1]+" -> Obj "+objPos2[0]+"/"+objPos2[1]+"/"+objPos2[1]); + + final float[] winObjPos = new float[3]; + if( crossHair.winToObjCoord(renderer, glWinX, glWinY, winObjPos) ) { + // final float[] translate = crossHair.getTranslate(); + // final float[] objPosT = new float[] { objPosC[0]+translate[0], objPosC[1]+translate[1], objPosC[2]+translate[2] }; + final float dx = winObjPos[0] - objPosC[0]; + final float dy = winObjPos[1] - objPosC[1]; + // final float dz = winObjPos[2] - objPosT[2]; + if( !FloatUtil.isZero(dx, FloatUtil.EPSILON) || !FloatUtil.isZero(dy, FloatUtil.EPSILON) ) { + System.err.println("CrossHair: Move.1: Win "+glWinX+"/"+glWinY+" -> Obj "+winObjPos[0]+"/"+winObjPos[1]+"/"+winObjPos[1]+" -> diff "+dx+" / "+dy); + crossHair.move(dx, dy, 0f); + } else { + System.err.println("CrossHair: Move.0: Win "+glWinX+"/"+glWinY+" -> Obj "+winObjPos[0]+"/"+winObjPos[1]+"/"+winObjPos[1]+" -> diff "+dx+" / "+dy); + } + } + + final int[] surfaceSize = new int[2]; + crossHair.getSurfaceSize(renderer, surfaceSize); + System.err.println("CrossHair: Size: Pixel "+surfaceSize[0]+" x "+surfaceSize[1]); + + pmv.glPopMatrix(); + } + return true; + } } ); + + } + + @Override + public void mouseReleased(final MouseEvent e) { + } + + @Override + public void mouseMoved(final MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseDragged(final MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseWheelMoved(final MouseEvent e) { + // TODO Auto-generated method stub + + } + + } + + public class KeyAction implements KeyListener { + @Override + public void keyPressed(final KeyEvent arg0) { + if(ignoreInput) { + return; + } + + if(arg0.getKeyCode() == KeyEvent.VK_1){ + button.move(0f, 0f, -zTran/10f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_2){ + button.move(0f, 0f, zTran/10f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_UP){ + button.move(0f, button.getHeight()/10f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){ + button.move(0f, -button.getHeight()/10f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){ + button.move(-button.getWidth()/10f, 0f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){ + button.move(button.getWidth()/10f, 0f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_4){ + button.setSpacing(button.getSpacingX()-0.01f, button.getSpacingY()-0.005f); + System.err.println("Button Spacing: " + button.getSpacingX()); + } + else if(arg0.getKeyCode() == KeyEvent.VK_5){ + button.setSpacing(button.getSpacingX()+0.01f, button.getSpacingY()+0.005f); + System.err.println("Button Spacing: " + button.getSpacingX()); + } + else if(arg0.getKeyCode() == KeyEvent.VK_6){ + button.setCorner(button.getCorner()-0.01f); + System.err.println("Button Corner: " + button.getCorner()); + } + else if(arg0.getKeyCode() == KeyEvent.VK_7){ + button.setCorner(button.getCorner()+0.01f); + System.err.println("Button Corner: " + button.getCorner()); + } + else if(arg0.getKeyCode() == KeyEvent.VK_0){ + // rotate(1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_9){ + // rotate(-1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_V) { + if(null != autoDrawable) { + autoDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + final int _i = gl.getSwapInterval(); + final int i; + switch(_i) { + case 0: i = 1; break; + case 1: i = -1; break; + case -1: i = 0; break; + default: i = 1; break; + } + gl.setSwapInterval(i); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + if(drawable instanceof FPSCounter) { + ((FPSCounter)drawable).resetFPSCounter(); + } + System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval()); + return true; + } + }); + } + } + else if(arg0.getKeyCode() == KeyEvent.VK_S){ + if(null != autoDrawable) { + autoDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + try { + final String type = Region.getRenderModeString(renderModes); + printScreen(drawable, "./", "demo-"+type, "snap"+screenshot_num, false); + screenshot_num++; + } catch (final GLException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } + return true; + } + }); + } + } + } + @Override + public void keyReleased(final KeyEvent arg0) {} + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UITypeDemo01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UITypeDemo01.java new file mode 100644 index 000000000..56962e110 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UITypeDemo01.java @@ -0,0 +1,617 @@ +/** + * 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.opengl.demos.graph.ui; + +import java.io.File; +import java.io.IOException; + +import com.jogamp.opengl.FPSCounter; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLPipelineFactory; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.GLRunnable; +import com.jogamp.opengl.demos.graph.MSAATool; +import com.jogamp.opengl.demos.graph.ui.testshapes.Glyph03FreeMonoRegular_M; +import com.jogamp.opengl.demos.graph.ui.testshapes.Glyph04FreeSans_0; +import com.jogamp.opengl.demos.graph.ui.testshapes.Glyph05FreeSerifBoldItalic_ae; +import com.jogamp.opengl.demos.util.MiscUtils; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.common.util.InterruptSource; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.curve.opengl.TextRegionUtil; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontSet; +import com.jogamp.graph.font.Font.Glyph; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.shapes.CrossHair; +import com.jogamp.graph.ui.gl.shapes.Rectangle; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLReadBufferUtil; +import com.jogamp.opengl.util.PMVMatrix; + +/** + * Basic UIShape and Type Rendering demo. + * + * Action Keys: + * - 1/2: zoom in/out + * - 4/5: increase/decrease shape/text spacing + * - 6/7: increase/decrease corner size + * - 0/9: rotate + * - v: toggle v-sync + * - s: screenshot + */ +public class UITypeDemo01 implements GLEventListener { + static final boolean DEBUG = false; + static final boolean TRACE = false; + + public static void main(final String[] args) throws IOException { + Font font = null; + String text = "Hello Origin."; + int glyph_id = Glyph.ID_UNKNOWN; + if( 0 != args.length ) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-font")) { + i++; + font = FontFactory.get(new File(args[i])); + } else if(args[i].equals("-text")) { + i++; + text = args[i]; + } else if(args[i].equals("-glyph")) { + i++; + glyph_id = MiscUtils.atoi(args[i], 0); + } + } + } + if( null == font ) { + font = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_SERIF); + } + System.err.println("Font: "+font.getFullFamilyName()); + System.err.println("Text: "+text); + + final GLProfile glp = GLProfile.getGL2ES2(); + final GLCapabilities caps = new GLCapabilities(glp); + caps.setAlphaBits(4); + caps.setSampleBuffers(true); + caps.setNumSamples(4); + System.out.println("Requested: " + caps); + + final GLWindow window = GLWindow.create(caps); + // window.setPosition(10, 10); + window.setSize(800, 400); + window.setTitle(UITypeDemo01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final UITypeDemo01 uiGLListener = new UITypeDemo01(font, glyph_id, text, Region.COLORCHANNEL_RENDERING_BIT, rs, DEBUG, TRACE); + uiGLListener.attachInputListenerTo(window); + window.addGLEventListener(uiGLListener); + window.setVisible(true); + + final Animator animator = new Animator(); + // animator.setUpdateFPSFrames(60, System.err); + animator.add(window); + + window.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(final KeyEvent arg0) { + if(arg0.getKeyCode() == KeyEvent.VK_F4) { + new InterruptSource.Thread() { + @Override + public void run() { + window.destroy(); + } }.start(); + } + } + }); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyed(final WindowEvent e) { + animator.stop(); + } + }); + + animator.start(); + } + + private final float[] fg_color = new float[] { 0, 0, 0, 1 }; + private final Font font; + private final String text; + private final int glyph_id; + private final GLReadBufferUtil screenshot; + private final int renderModes; + private final RegionRenderer rRenderer; + private final boolean debug; + private final boolean trace; + + private final CrossHair crossHair; + private final Shape testObj; + + private KeyAction keyAction; + private MouseAction mouseAction; + + private volatile GLAutoDrawable autoDrawable = null; + + private final float[] position = new float[] {0,0,0}; + + private static final float xTran = 0f; + private static final float yTran = 0f; + private static final float zTran = -1/5f; + private static final float zNear = 0.1f; + private static final float zFar = 7000.0f; + + boolean ignoreInput = false; + + protected final AffineTransform tempT1 = new AffineTransform(); + protected final AffineTransform tempT2 = new AffineTransform(); + + @SuppressWarnings("unused") + public UITypeDemo01(final Font font, final int glyph_id, final String text, final int renderModes, final RenderState rs, final boolean debug, final boolean trace) { + this.font = font; + this.text = text; + this.glyph_id = glyph_id; + this.renderModes = renderModes; + this.rRenderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + this.debug = debug; + this.trace = trace; + this.screenshot = new GLReadBufferUtil(false, false); + + crossHair = new CrossHair(SVertex.factory(), renderModes, 1/20f, 1/20f, 1/1000f); + crossHair.setColor(0f,0f,1f,1f); + crossHair.setEnabled(true); + + if (false ) { + final Rectangle o = new Rectangle(SVertex.factory(), renderModes, 1/10f, 1/20f, 1/1000f); + o.move(o.getWidth(), -o.getHeight(), 0f); + testObj = o; + } else { + final float scale = 0.15312886f; + final float size_xz = 0.541f; + final Shape o = new Glyph03FreeMonoRegular_M(SVertex.factory(), renderModes); + o.scale(scale, scale, 1f); + // o.translate(size_xz, -size_xz, 0f); + testObj = o; + } + testObj.setColor(0f, 0f, 0f, 1f); + testObj.setEnabled(true); + } + + public final RegionRenderer getRegionRenderer() { return rRenderer; } + public final float[] getPosition() { return position; } + + @Override + public void init(final GLAutoDrawable drawable) { + autoDrawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(debug) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) ).getGL2ES2(); + } + if(trace) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2(); + } + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + getRegionRenderer().init(gl); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); + MSAATool.dump(drawable); + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int xstart, final int ystart, final int width, final int height) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glViewport(xstart, ystart, width, height); + rRenderer.reshapePerspective(45.0f, width, height, zNear, zFar); + // rRenderer.reshapeOrtho(width, height, zNear, zFar); + + lastWidth = width; + lastHeight = height; + if( drawable instanceof Window ) { + ((Window)drawable).setTitle(UITypeDemo01.class.getSimpleName()+": "+drawable.getSurfaceWidth()+" x "+drawable.getSurfaceHeight()); + } + } + float lastWidth = 0f, lastHeight = 0f; + + final int[] sampleCount = { 4 }; + + private void drawShape(final GL2ES2 gl, final PMVMatrix pmv, final RegionRenderer renderer, final Shape shape) { + pmv.glPushMatrix(); + shape.setTransform(pmv); + shape.drawShape(gl, renderer, sampleCount); + pmv.glPopMatrix(); + } + + @Override + public void display(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + final RegionRenderer renderer = getRegionRenderer(); + final PMVMatrix pmv = renderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + pmv.glTranslatef(xTran, yTran, zTran); + renderer.enable(gl, true); + { + pmv.glPushMatrix(); + pmv.glScalef(0.8f, 0.8f, 1f); + drawShape(gl, pmv, renderer, testObj); + pmv.glPopMatrix(); + } + // drawShape(gl, pmv, renderer, crossHair); + { + final float full_width_o; + final float full_height_o; + { + final float orthoDist = -zTran; // assume orthogonal plane at -zTran + float glWinX = 0; + float glWinY = 0; + final float winZ = FloatUtil.getOrthoWinZ(orthoDist, zNear, zFar); + final float[] objCoord0 = new float[3]; + final float[] objCoord1 = new float[3]; + if( pmv.gluUnProject(glWinX, glWinY, winZ, renderer.getViewport(), 0, objCoord0, 0) ) { + if( once ) { + System.err.printf("winToObjCoord: win [%f, %f, %f] -> obj [%f, %f, %f]%n", glWinX, glWinY, winZ, objCoord0[0], objCoord0[1], objCoord0[2]); + } + } + glWinX = drawable.getSurfaceWidth(); + glWinY = drawable.getSurfaceHeight(); + if( pmv.gluUnProject(glWinX, glWinY, winZ, renderer.getViewport(), 0, objCoord1, 0) ) { + if( once ) { + System.err.printf("winToObjCoord: win [%f, %f, %f] -> obj [%f, %f, %f]%n", glWinX, glWinY, winZ, objCoord1[0], objCoord1[1], objCoord1[2]); + } + } + full_width_o = objCoord1[0] - objCoord0[0]; + full_height_o = objCoord1[1] - objCoord0[1]; + } + pmv.glPushMatrix(); + + final Font.Glyph glyph; + if( Glyph.ID_UNKNOWN < glyph_id ) { + glyph = font.getGlyph(glyph_id); + if( once ) { + System.err.println("glyph_id "+glyph_id+": "+glyph); + } + } else { + glyph = null; + } + if( null != glyph && glyph.getID() != Glyph.ID_UNKNOWN ) { + final AABBox txt_box_em = glyph.getBBox(); + final float full_width_s = full_width_o / txt_box_em.getWidth(); + final float full_height_s = full_height_o / txt_box_em.getHeight(); + final float txt_scale = full_width_s < full_height_s ? full_width_s/2f : full_height_s/2f; + pmv.glScalef(txt_scale, txt_scale, 1f); + pmv.glTranslatef(-txt_box_em.getWidth(), 0f, 0f); + if( null != glyph.getShape() ) { + final GLRegion region = GLRegion.create(gl.getGLProfile(), renderModes, null); + region.addOutlineShape(glyph.getShape(), null, region.hasColorChannel() ? fg_color : null); + region.draw(gl, renderer, sampleCount); + region.destroy(gl); + } + if( once ) { + final AABBox txt_box_em2 = font.getGlyphShapeBounds(null, text); + System.err.println("XXX: full_width: "+full_width_o+" / "+txt_box_em.getWidth()+" -> "+full_width_s); + System.err.println("XXX: full_height: "+full_height_o+" / "+txt_box_em.getHeight()+" -> "+full_height_s); + System.err.println("XXX: txt_scale: "+txt_scale); + System.err.println("XXX: txt_box_em "+txt_box_em); + System.err.println("XXX: txt_box_e2 "+txt_box_em2); + } + } else if( Glyph.ID_UNKNOWN == glyph_id ) { + final AABBox txt_box_em = font.getGlyphBounds(text, tempT1, tempT2); + final float full_width_s = full_width_o / txt_box_em.getWidth(); + final float full_height_s = full_height_o / txt_box_em.getHeight(); + final float txt_scale = full_width_s < full_height_s ? full_width_s/2f : full_height_s/2f; + pmv.glScalef(txt_scale, txt_scale, 1f); + pmv.glTranslatef(-txt_box_em.getWidth(), 0f, 0f); + final AABBox txt_box_r = TextRegionUtil.drawString3D(gl, renderModes, renderer, font, text, fg_color, sampleCount, tempT1, tempT2); + if( once ) { + final AABBox txt_box_em2 = font.getGlyphShapeBounds(null, text); + System.err.println("XXX: full_width: "+full_width_o+" / "+txt_box_em.getWidth()+" -> "+full_width_s); + System.err.println("XXX: full_height: "+full_height_o+" / "+txt_box_em.getHeight()+" -> "+full_height_s); + System.err.println("XXX: txt_scale: "+txt_scale); + System.err.println("XXX: txt_box_em "+txt_box_em); + System.err.println("XXX: txt_box_e2 "+txt_box_em2); + System.err.println("XXX: txt_box_rg "+txt_box_r); + } + } + pmv.glPopMatrix(); + if( once ) { + try { + printScreen(drawable); + } catch (GLException | IOException e) { + e.printStackTrace(); + } + } + once = false; + } + renderer.enable(gl, false); + } + private boolean once = true; + + @Override + public void dispose(final GLAutoDrawable drawable) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + crossHair.destroy(gl, getRegionRenderer()); + testObj.destroy(gl, getRegionRenderer()); + + autoDrawable = null; + screenshot.dispose(gl); + rRenderer.destroy(gl); + } + + /** Attach the input listener to the window */ + public void attachInputListenerTo(final GLWindow window) { + if ( null == keyAction ) { + keyAction = new KeyAction(); + window.addKeyListener(keyAction); + } + if ( null == mouseAction ) { + mouseAction = new MouseAction(); + window.addMouseListener(mouseAction); + } + } + + public void detachFrom(final GLWindow window) { + if ( null == keyAction ) { + return; + } + if ( null == mouseAction ) { + return; + } + window.removeGLEventListener(this); + window.removeKeyListener(keyAction); + window.removeMouseListener(mouseAction); + } + + public void printScreen(final GLAutoDrawable drawable) throws GLException, IOException { + final String dir = "./"; + final String tech="demo-"+Region.getRenderModeString(renderModes); + final String objName = "snap"+screenshot_num; + { + final String sw = String.format("-%03dx%03d-Z%04d-T%04d-%s", drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), (int)Math.abs(zTran), 0, objName); + + final String filename = dir + tech + sw +".png"; + if(screenshot.readPixels(drawable.getGL(), false)) { + screenshot.write(new File(filename)); + } + } + screenshot_num++; + } + int screenshot_num = 0; + + public void setIgnoreInput(final boolean v) { + ignoreInput = v; + } + public boolean getIgnoreInput() { + return ignoreInput; + } + + public class MouseAction implements MouseListener{ + + @Override + public void mouseClicked(final MouseEvent e) { + + } + + @Override + public void mouseEntered(final MouseEvent e) { + } + + @Override + public void mouseExited(final MouseEvent e) { + } + + @Override + public void mousePressed(final MouseEvent e) { + autoDrawable.invoke(false, new GLRunnable() { // avoid data-race + @Override + public boolean run(final GLAutoDrawable drawable) { + System.err.println("\n\nMouse: "+e); + + final RegionRenderer renderer = getRegionRenderer(); + final PMVMatrix pmv = renderer.getMatrix(); + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + pmv.glTranslatef(xTran, yTran, zTran); + + // flip to GL window coordinates, origin bottom-left + final int[] viewport = renderer.getViewport(new int[4]); + final int glWinX = e.getX(); + final int glWinY = viewport[3] - e.getY() - 1; + + { + pmv.glPushMatrix(); + crossHair.setTransform(pmv); + + final float[] objPosC = crossHair.getBounds().getCenter(); + final int[] objWinPos = new int[2]; + System.err.println("\n\nCrossHair: "+crossHair); + if( crossHair.objToWinCoord(renderer, objPosC, objWinPos) ) { + System.err.println("CrossHair: Obj: Obj "+objPosC[0]+"/"+objPosC[1]+"/"+objPosC[1]+" -> Win "+objWinPos[0]+"/"+objWinPos[1]); + } + + final float[] objPos2 = new float[3]; + crossHair.winToObjCoord(renderer, objWinPos[0], objWinPos[1], objPos2); + System.err.println("CrossHair: Obj: Win "+objWinPos[0]+"/"+objWinPos[1]+" -> Obj "+objPos2[0]+"/"+objPos2[1]+"/"+objPos2[1]); + + final float[] winObjPos = new float[3]; + if( crossHair.winToObjCoord(renderer, glWinX, glWinY, winObjPos) ) { + // final float[] translate = crossHair.getTranslate(); + // final float[] objPosT = new float[] { objPosC[0]+translate[0], objPosC[1]+translate[1], objPosC[2]+translate[2] }; + final float dx = winObjPos[0] - objPosC[0]; + final float dy = winObjPos[1] - objPosC[1]; + // final float dz = winObjPos[2] - objPosT[2]; + if( !FloatUtil.isZero(dx, FloatUtil.EPSILON) || !FloatUtil.isZero(dy, FloatUtil.EPSILON) ) { + System.err.println("CrossHair: Move.1: Win "+glWinX+"/"+glWinY+" -> Obj "+winObjPos[0]+"/"+winObjPos[1]+"/"+winObjPos[1]+" -> diff "+dx+" / "+dy); + crossHair.move(dx, dy, 0f); + } else { + System.err.println("CrossHair: Move.0: Win "+glWinX+"/"+glWinY+" -> Obj "+winObjPos[0]+"/"+winObjPos[1]+"/"+winObjPos[1]+" -> diff "+dx+" / "+dy); + } + } + + final int[] surfaceSize = new int[2]; + crossHair.getSurfaceSize(renderer, surfaceSize); + System.err.println("CrossHair: Size: Pixel "+surfaceSize[0]+" x "+surfaceSize[1]); + + pmv.glPopMatrix(); + } + return true; + } } ); + + } + + @Override + public void mouseReleased(final MouseEvent e) { + } + + @Override + public void mouseMoved(final MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseDragged(final MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseWheelMoved(final MouseEvent e) { + // TODO Auto-generated method stub + + } + + } + + public class KeyAction implements KeyListener { + @Override + public void keyPressed(final KeyEvent arg0) { + if(ignoreInput) { + return; + } + + if(arg0.getKeyCode() == KeyEvent.VK_1){ + crossHair.move(0f, 0f, -zTran/10f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_2){ + crossHair.move(0f, 0f, zTran/10f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_UP){ + crossHair.move(0f, crossHair.getHeight()/10f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){ + crossHair.move(0f, -crossHair.getHeight()/10f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){ + crossHair.move(-crossHair.getWidth()/10f, 0f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){ + crossHair.move(crossHair.getWidth()/10f, 0f, 0f); + } + else if(arg0.getKeyCode() == KeyEvent.VK_0){ + // rotate(1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_9){ + // rotate(-1); + } + else if(arg0.getKeyCode() == KeyEvent.VK_V) { + if(null != autoDrawable) { + autoDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + final GL gl = drawable.getGL(); + final int _i = gl.getSwapInterval(); + final int i; + switch(_i) { + case 0: i = 1; break; + case 1: i = -1; break; + case -1: i = 0; break; + default: i = 1; break; + } + gl.setSwapInterval(i); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + if(drawable instanceof FPSCounter) { + ((FPSCounter)drawable).resetFPSCounter(); + } + System.err.println("Swap Interval: "+_i+" -> "+i+" -> "+gl.getSwapInterval()); + return true; + } + }); + } + } + else if(arg0.getKeyCode() == KeyEvent.VK_S){ + if(null != autoDrawable) { + autoDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + try { + printScreen(drawable); + } catch (final GLException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } + return true; + } + }); + } + } + } + @Override + public void keyReleased(final KeyEvent arg0) {} + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/button-pressed-145x53.png b/src/demos/com/jogamp/opengl/demos/graph/ui/button-pressed-145x53.png Binary files differnew file mode 100644 index 000000000..1eba3a09e --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/button-pressed-145x53.png diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/button-released-145x53.png b/src/demos/com/jogamp/opengl/demos/graph/ui/button-released-145x53.png Binary files differnew file mode 100644 index 000000000..fe223c6d3 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/button-released-145x53.png diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java new file mode 100644 index 000000000..4171eeda8 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java @@ -0,0 +1,316 @@ +/** + * Copyright 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.opengl.demos.graph.ui.testshapes; + +import com.jogamp.opengl.GL2ES2; +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.graph.geom.plane.Winding; +import com.jogamp.graph.ui.gl.Shape; + +/** + * GPU based resolution independent test object + * - Ubuntu-Light, lower case 'o' + * - TTF Shape for Glyph 82 + */ +public class Glyph01UbuntuLight_o extends Shape { + + public Glyph01UbuntuLight_o(final Factory<? extends Vertex> factory, final int renderModes) { + super(factory, renderModes); + } + + @Override + protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @Override + protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @SuppressWarnings("unused") + @Override + protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { + final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); + + // Ubuntu-Light, lower case 'o' + // Start TTF Shape for Glyph 82 + if( false ) { + // Original Outer shape: Winding.CW + // Moved into OutlineShape reverse -> Winding.CCW -> OK + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.527000f, 0.258000f, true); + // 000: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.527000f, 0.197000f, false); + shape.addVertex(0, 0.510000f, 0.147000f, true); + // 002: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.492000f, 0.097000f, false); + shape.addVertex(0, 0.461000f, 0.062000f, true); + // 003: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.429000f, 0.027000f, false); + shape.addVertex(0, 0.386000f, 0.008000f, true); + // 004: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.343000f, -0.012000f, false); + shape.addVertex(0, 0.291000f, -0.012000f, true); + // 005: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.239000f, -0.012000f, false); + shape.addVertex(0, 0.196000f, 0.007000f, true); + // 007: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.153000f, 0.027000f, false); + shape.addVertex(0, 0.122000f, 0.062000f, true); + // 008: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.090000f, 0.097000f, false); + shape.addVertex(0, 0.073000f, 0.147000f, true); + // 009: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.055000f, 0.197000f, false); + shape.addVertex(0, 0.055000f, 0.258000f, true); + // 010: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.055000f, 0.319000f, false); + shape.addVertex(0, 0.072000f, 0.369000f, true); + // 012: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.090000f, 0.419000f, false); + shape.addVertex(0, 0.121000f, 0.454000f, true); + // 013: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.153000f, 0.490000f, false); + shape.addVertex(0, 0.196000f, 0.509000f, true); + // 014: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.239000f, 0.529000f, false); + shape.addVertex(0, 0.291000f, 0.529000f, true); + // 015: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.343000f, 0.529000f, false); + shape.addVertex(0, 0.386000f, 0.510000f, true); + // 017: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.429000f, 0.490000f, false); + shape.addVertex(0, 0.460000f, 0.455000f, true); + // 018: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.492000f, 0.419000f, false); + shape.addVertex(0, 0.509000f, 0.369000f, true); + // 019: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.527000f, 0.319000f, false); + shape.addVertex(0, 0.527000f, 0.258000f, true); + System.err.println("Glyph01UbuntuLight_o.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Outer shape: Winding.CW + // Moved into OutlineShape same-order -> Winding.CW -> ERROR (so we fix it in the end, see below) + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0.527000f, 0.258000f, true); + // 000: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.527000f, 0.197000f, false); + shape.addVertex(0.510000f, 0.147000f, true); + // 002: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.492000f, 0.097000f, false); + shape.addVertex(0.461000f, 0.062000f, true); + // 003: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.429000f, 0.027000f, false); + shape.addVertex(0.386000f, 0.008000f, true); + // 004: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.343000f, -0.012000f, false); + shape.addVertex(0.291000f, -0.012000f, true); + // 005: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.239000f, -0.012000f, false); + shape.addVertex(0.196000f, 0.007000f, true); + // 007: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.153000f, 0.027000f, false); + shape.addVertex(0.122000f, 0.062000f, true); + // 008: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.090000f, 0.097000f, false); + shape.addVertex(0.073000f, 0.147000f, true); + // 009: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.055000f, 0.197000f, false); + shape.addVertex(0.055000f, 0.258000f, true); + // 010: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.055000f, 0.319000f, false); + shape.addVertex(0.072000f, 0.369000f, true); + // 012: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.090000f, 0.419000f, false); + shape.addVertex(0.121000f, 0.454000f, true); + // 013: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.153000f, 0.490000f, false); + shape.addVertex(0.196000f, 0.509000f, true); + // 014: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.239000f, 0.529000f, false); + shape.addVertex(0.291000f, 0.529000f, true); + // 015: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.343000f, 0.529000f, false); + shape.addVertex(0.386000f, 0.510000f, true); + // 017: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.429000f, 0.490000f, false); + shape.addVertex(0.460000f, 0.455000f, true); + // 018: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.492000f, 0.419000f, false); + shape.addVertex(0.509000f, 0.369000f, true); + // 019: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.527000f, 0.319000f, false); + shape.addVertex(0.527000f, 0.258000f, true); + System.err.println("Glyph01UbuntuLight_o.shape01b.1.winding_area: "+shape.getWindingOfLastOutline()); + shape.setWindingOfLastOutline(Winding.CCW); + System.err.println("Glyph01UbuntuLight_o.shape01b.2.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } + + if( true ) { + // Original Inner shape: Winding.CCW + // Moved into OutlineShape reverse -> Winding.CW -> OK + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.458000f, 0.258000f, true); + // 020: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.458000f, 0.355000f, false); + shape.addVertex(0, 0.413000f, 0.412000f, true); + // 022: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.368000f, 0.470000f, false); + shape.addVertex(0, 0.291000f, 0.470000f, true); + // 023: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.214000f, 0.470000f, false); + shape.addVertex(0, 0.169000f, 0.413000f, true); + // 025: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.124000f, 0.355000f, false); + shape.addVertex(0, 0.124000f, 0.258000f, true); + // 026: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.124000f, 0.161000f, false); + shape.addVertex(0, 0.169000f, 0.104000f, true); + // 028: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.214000f, 0.047000f, false); + shape.addVertex(0, 0.291000f, 0.047000f, true); + // 029: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.368000f, 0.047000f, false); + shape.addVertex(0, 0.413000f, 0.104000f, true); + // 031: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.458000f, 0.161000f, false); + shape.addVertex(0, 0.458000f, 0.258000f, true); + System.err.println("Glyph01UbuntuLight_o.shape02a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Inner shape: Winding.CCW + // Moved into OutlineShape same-order -> Winding.CCW -> OK + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + + shape.addVertex(0.458000f, 0.258000f, true); + // 020: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.458000f, 0.355000f, false); + shape.addVertex(0.413000f, 0.412000f, true); + // 022: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.368000f, 0.470000f, false); + shape.addVertex(0.291000f, 0.470000f, true); + // 023: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.214000f, 0.470000f, false); + shape.addVertex(0.169000f, 0.413000f, true); + // 025: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.124000f, 0.355000f, false); + shape.addVertex(0.124000f, 0.258000f, true); + // 026: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.124000f, 0.161000f, false); + shape.addVertex(0.169000f, 0.104000f, true); + // 028: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.214000f, 0.047000f, false); + shape.addVertex(0.291000f, 0.047000f, true); + // 029: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.368000f, 0.047000f, false); + shape.addVertex(0.413000f, 0.104000f, true); + // 031: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.458000f, 0.161000f, false); + shape.addVertex(0.458000f, 0.258000f, true); + + System.err.println("Glyph01UbuntuLight_o.shape02b.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } + // End Shape for Glyph 82 + + shape.setIsQuadraticNurbs(); + shape.setSharpness(shapesSharpness); + region.addOutlineShape(shape, null, rgbaColor); + + box.resize(shape.getBounds()); + } + + @Override + public String getSubString() { + return super.getSubString(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java new file mode 100644 index 000000000..28d6f6390 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java @@ -0,0 +1,652 @@ +/** + * Copyright 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.opengl.demos.graph.ui.testshapes; + +import com.jogamp.opengl.GL2ES2; +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.graph.ui.gl.Shape; + +/** + * GPU based resolution independent test object + * - Ubuntu-Light, lower case 'æ' + * - TTF Shape for Glyph 193 + */ +public class Glyph02UbuntuLight_ae extends Shape { + + public Glyph02UbuntuLight_ae(final Factory<? extends Vertex> factory, final int renderModes) { + super(factory, renderModes); + } + + @Override + protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @Override + protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @SuppressWarnings("unused") + @Override + protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { + final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); + + // Ubuntu-Light, lower case 'æ' + + // Start TTF Shape for Glyph 193 + if( true ) { + // Original Inner e-shape: Winding.CCW + // Moved into OutlineShape reverse -> Winding.CW -> OK + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.728000f, 0.300000f, true); + // 000: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.726000f, 0.381000f, false); + shape.addVertex(0, 0.690000f, 0.426000f, true); + // 002: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.654000f, 0.471000f, false); + shape.addVertex(0, 0.588000f, 0.471000f, true); + // 003: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.553000f, 0.471000f, false); + shape.addVertex(0, 0.526000f, 0.457000f, true); + // 005: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.498000f, 0.443000f, false); + shape.addVertex(0, 0.478000f, 0.420000f, true); + // 006: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.457000f, 0.396000f, false); + shape.addVertex(0, 0.446000f, 0.365000f, true); + // 007: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.434000f, 0.334000f, false); + shape.addVertex(0, 0.432000f, 0.300000f, true); + // 008: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.728000f, 0.300000f, true); + System.err.println("Glyph02UbuntuLight_ae.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Inner e-shape: Winding.CCW + // Moved into OutlineShape same-order -> Winding.CCW -> ?? + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0.728000f, 0.300000f, true); + // 000: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.726000f, 0.381000f, false); + shape.addVertex(0.690000f, 0.426000f, true); + // 002: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.654000f, 0.471000f, false); + shape.addVertex(0.588000f, 0.471000f, true); + // 003: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.553000f, 0.471000f, false); + shape.addVertex(0.526000f, 0.457000f, true); + // 005: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.498000f, 0.443000f, false); + shape.addVertex(0.478000f, 0.420000f, true); + // 006: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.457000f, 0.396000f, false); + shape.addVertex(0.446000f, 0.365000f, true); + // 007: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.434000f, 0.334000f, false); + shape.addVertex(0.432000f, 0.300000f, true); + // 008: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.728000f, 0.300000f, true); + System.err.println("Glyph02UbuntuLight_ae.shape01b.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } + + if( true ) { + // Original Outer shape: Winding.CW + // Moved into OutlineShape reverse -> Winding.CCW -> OK + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.252000f, -0.011000f, true); + // 009: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.208000f, -0.011000f, false); + shape.addVertex(0, 0.171000f, -0.002000f, true); + // 011: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.133000f, 0.007000f, false); + shape.addVertex(0, 0.106000f, 0.026000f, true); + // 012: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.079000f, 0.046000f, false); + shape.addVertex(0, 0.064000f, 0.076000f, true); + // 013: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.048000f, 0.107000f, false); + shape.addVertex(0, 0.048000f, 0.151000f, true); + // 014: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.048000f, 0.193000f, false); + shape.addVertex(0, 0.064000f, 0.223000f, true); + // 016: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.080000f, 0.253000f, false); + shape.addVertex(0, 0.109000f, 0.272000f, true); + // 017: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.138000f, 0.292000f, false); + shape.addVertex(0, 0.178000f, 0.301000f, true); + // 018: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.218000f, 0.310000f, false); + shape.addVertex(0, 0.265000f, 0.310000f, true); + // 019: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.279000f, 0.310000f, false); + shape.addVertex(0, 0.294000f, 0.309000f, true); + // 021: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.310000f, 0.307000f, false); + shape.addVertex(0, 0.324000f, 0.305000f, true); + // 022: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.339000f, 0.302000f, false); + shape.addVertex(0, 0.349000f, 0.300000f, true); + // 023: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.360000f, 0.297000f, false); + shape.addVertex(0, 0.364000f, 0.295000f, true); + // 024: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.364000f, 0.327000f, true); + // 025: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.364000f, 0.354000f, false); + shape.addVertex(0, 0.360000f, 0.379000f, true); + // 027: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.356000f, 0.405000f, false); + shape.addVertex(0, 0.343000f, 0.425000f, true); + // 028: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.329000f, 0.446000f, false); + shape.addVertex(0, 0.305000f, 0.458000f, true); + // 029: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.280000f, 0.471000f, false); + shape.addVertex(0, 0.240000f, 0.471000f, true); + // 030: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.186000f, 0.471000f, false); + shape.addVertex(0, 0.156000f, 0.464000f, true); + // 032: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.126000f, 0.456000f, false); + shape.addVertex(0, 0.113000f, 0.451000f, true); + // 033: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.105000f, 0.507000f, true); + // 034: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.122000f, 0.515000f, false); + shape.addVertex(0, 0.158000f, 0.522000f, true); + // 036: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.194000f, 0.529000f, false); + shape.addVertex(0, 0.243000f, 0.529000f, true); + // 037: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.314000f, 0.529000f, false); + shape.addVertex(0, 0.354000f, 0.503000f, true); + // 039: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.395000f, 0.476000f, false); + shape.addVertex(0, 0.412000f, 0.431000f, true); + // 040: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.445000f, 0.480000f, false); + shape.addVertex(0, 0.491000f, 0.504000f, true); + // 042: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.537000f, 0.529000f, false); + shape.addVertex(0, 0.587000f, 0.529000f, true); + // 043: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.682000f, 0.529000f, false); + shape.addVertex(0, 0.738000f, 0.467000f, true); + // 045: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.795000f, 0.405000f, false); + shape.addVertex(0, 0.795000f, 0.276000f, true); + // 046: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.795000f, 0.268000f, false); + shape.addVertex(0, 0.795000f, 0.260000f, true); + // 048: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.794000f, 0.252000f, false); + shape.addVertex(0, 0.793000f, 0.245000f, true); + // 049: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.430000f, 0.245000f, true); + // 050: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.433000f, 0.150000f, false); + shape.addVertex(0, 0.477000f, 0.099000f, true); + // 052: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.521000f, 0.048000f, false); + shape.addVertex(0, 0.617000f, 0.048000f, true); + // 053: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.670000f, 0.048000f, false); + shape.addVertex(0, 0.701000f, 0.058000f, true); + // 055: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.732000f, 0.068000f, false); + shape.addVertex(0, 0.746000f, 0.075000f, true); + // 056: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.758000f, 0.019000f, true); + // 057: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.744000f, 0.011000f, false); + shape.addVertex(0, 0.706000f, 0.000000f, true); + // 059: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.667000f, -0.011000f, false); + shape.addVertex(0, 0.615000f, -0.011000f, true); + // 060: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.558000f, -0.011000f, false); + shape.addVertex(0, 0.514000f, 0.003000f, true); + // 062: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.470000f, 0.017000f, false); + shape.addVertex(0, 0.437000f, 0.049000f, true); + // 063: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.426000f, 0.040000f, false); + shape.addVertex(0, 0.410000f, 0.030000f, true); + // 065: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.393000f, 0.019000f, false); + shape.addVertex(0, 0.370000f, 0.010000f, true); + // 066: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.347000f, 0.001000f, false); + shape.addVertex(0, 0.318000f, -0.005000f, true); + // 067: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.289000f, -0.011000f, false); + shape.addVertex(0, 0.252000f, -0.011000f, true); + System.err.println("Glyph02UbuntuLight_ae.shape02a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Outer shape: Winding.CW + // Moved into OutlineShape same-order -> Winding.CW -> OK now + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0.252000f, -0.011000f, true); + // 009: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.208000f, -0.011000f, false); + shape.addVertex(0.171000f, -0.002000f, true); + // 011: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.133000f, 0.007000f, false); + shape.addVertex(0.106000f, 0.026000f, true); + // 012: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.079000f, 0.046000f, false); + shape.addVertex(0.064000f, 0.076000f, true); + // 013: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.048000f, 0.107000f, false); + shape.addVertex(0.048000f, 0.151000f, true); + // 014: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.048000f, 0.193000f, false); + shape.addVertex(0.064000f, 0.223000f, true); + // 016: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.080000f, 0.253000f, false); + shape.addVertex(0.109000f, 0.272000f, true); + // 017: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.138000f, 0.292000f, false); + shape.addVertex(0.178000f, 0.301000f, true); + // 018: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.218000f, 0.310000f, false); + shape.addVertex(0.265000f, 0.310000f, true); + // 019: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.279000f, 0.310000f, false); + shape.addVertex(0.294000f, 0.309000f, true); + // 021: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.310000f, 0.307000f, false); + shape.addVertex(0.324000f, 0.305000f, true); + // 022: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.339000f, 0.302000f, false); + shape.addVertex(0.349000f, 0.300000f, true); + // 023: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.360000f, 0.297000f, false); + shape.addVertex(0.364000f, 0.295000f, true); + // 024: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.364000f, 0.327000f, true); + // 025: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.364000f, 0.354000f, false); + shape.addVertex(0.360000f, 0.379000f, true); + // 027: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.356000f, 0.405000f, false); + shape.addVertex(0.343000f, 0.425000f, true); + // 028: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.329000f, 0.446000f, false); + shape.addVertex(0.305000f, 0.458000f, true); + // 029: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.280000f, 0.471000f, false); + shape.addVertex(0.240000f, 0.471000f, true); + // 030: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.186000f, 0.471000f, false); + shape.addVertex(0.156000f, 0.464000f, true); + // 032: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.126000f, 0.456000f, false); + shape.addVertex(0.113000f, 0.451000f, true); + // 033: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.105000f, 0.507000f, true); + // 034: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.122000f, 0.515000f, false); + shape.addVertex(0.158000f, 0.522000f, true); + // 036: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.194000f, 0.529000f, false); + shape.addVertex(0.243000f, 0.529000f, true); + // 037: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.314000f, 0.529000f, false); + shape.addVertex(0.354000f, 0.503000f, true); + // 039: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.395000f, 0.476000f, false); + shape.addVertex(0.412000f, 0.431000f, true); + // 040: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.445000f, 0.480000f, false); + shape.addVertex(0.491000f, 0.504000f, true); + // 042: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.537000f, 0.529000f, false); + shape.addVertex(0.587000f, 0.529000f, true); + // 043: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.682000f, 0.529000f, false); + shape.addVertex(0.738000f, 0.467000f, true); + // 045: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.795000f, 0.405000f, false); + shape.addVertex(0.795000f, 0.276000f, true); + // 046: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.795000f, 0.268000f, false); + shape.addVertex(0.795000f, 0.260000f, true); + // 048: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.794000f, 0.252000f, false); + shape.addVertex(0.793000f, 0.245000f, true); + // 049: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.430000f, 0.245000f, true); + // 050: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.433000f, 0.150000f, false); + shape.addVertex(0.477000f, 0.099000f, true); + // 052: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.521000f, 0.048000f, false); + shape.addVertex(0.617000f, 0.048000f, true); + // 053: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.670000f, 0.048000f, false); + shape.addVertex(0.701000f, 0.058000f, true); + // 055: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.732000f, 0.068000f, false); + shape.addVertex(0.746000f, 0.075000f, true); + // 056: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0.758000f, 0.019000f, true); + // 057: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.744000f, 0.011000f, false); + shape.addVertex(0.706000f, 0.000000f, true); + // 059: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.667000f, -0.011000f, false); + shape.addVertex(0.615000f, -0.011000f, true); + // 060: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.558000f, -0.011000f, false); + shape.addVertex(0.514000f, 0.003000f, true); + // 062: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.470000f, 0.017000f, false); + shape.addVertex(0.437000f, 0.049000f, true); + // 063: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.426000f, 0.040000f, false); + shape.addVertex(0.410000f, 0.030000f, true); + // 065: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.393000f, 0.019000f, false); + shape.addVertex(0.370000f, 0.010000f, true); + // 066: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.347000f, 0.001000f, false); + shape.addVertex(0.318000f, -0.005000f, true); + // 067: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.289000f, -0.011000f, false); + shape.addVertex(0.252000f, -0.011000f, true); + System.err.println("Glyph02UbuntuLight_ae.shape02b.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } + + if( true ) { + // Original Inner a-shape: Winding.CCW + // Moved into OutlineShape reverse -> Winding.CW -> OK now + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.365000f, 0.238000f, true); + // 068: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.354000f, 0.243000f, false); + shape.addVertex(0, 0.330000f, 0.248000f, true); + // 070: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.305000f, 0.254000f, false); + shape.addVertex(0, 0.263000f, 0.254000f, true); + // 071: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.239000f, 0.254000f, false); + shape.addVertex(0, 0.213000f, 0.251000f, true); + // 073: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.187000f, 0.247000f, false); + shape.addVertex(0, 0.165000f, 0.236000f, true); + // 074: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.143000f, 0.224000f, false); + shape.addVertex(0, 0.129000f, 0.204000f, true); + // 075: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.115000f, 0.184000f, false); + shape.addVertex(0, 0.115000f, 0.151000f, true); + // 076: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.115000f, 0.122000f, false); + shape.addVertex(0, 0.125000f, 0.102000f, true); + // 078: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.135000f, 0.082000f, false); + shape.addVertex(0, 0.153000f, 0.070000f, true); + // 079: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.172000f, 0.058000f, false); + shape.addVertex(0, 0.197000f, 0.053000f, true); + // 080: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.222000f, 0.047000f, false); + shape.addVertex(0, 0.252000f, 0.047000f, true); + // 081: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.314000f, 0.047000f, false); + shape.addVertex(0, 0.350000f, 0.063000f, true); + // 083: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.386000f, 0.080000f, false); + shape.addVertex(0, 0.400000f, 0.093000f, true); + // 084: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.384000f, 0.119000f, false); + shape.addVertex(0, 0.375000f, 0.154000f, true); + // 086: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.366000f, 0.190000f, false); + shape.addVertex(0, 0.365000f, 0.238000f, true); + System.err.println("Glyph02UbuntuLight_ae.shape03a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + // Inner a-shape: Winding.CCW + // Moved into OutlineShape same-order -> Winding.CCW -> OK + // + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0.365000f, 0.238000f, true); + // 068: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.354000f, 0.243000f, false); + shape.addVertex(0.330000f, 0.248000f, true); + // 070: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.305000f, 0.254000f, false); + shape.addVertex(0.263000f, 0.254000f, true); + // 071: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.239000f, 0.254000f, false); + shape.addVertex(0.213000f, 0.251000f, true); + // 073: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.187000f, 0.247000f, false); + shape.addVertex(0.165000f, 0.236000f, true); + // 074: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.143000f, 0.224000f, false); + shape.addVertex(0.129000f, 0.204000f, true); + // 075: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.115000f, 0.184000f, false); + shape.addVertex(0.115000f, 0.151000f, true); + // 076: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.115000f, 0.122000f, false); + shape.addVertex(0.125000f, 0.102000f, true); + // 078: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.135000f, 0.082000f, false); + shape.addVertex(0.153000f, 0.070000f, true); + // 079: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0.172000f, 0.058000f, false); + shape.addVertex(0.197000f, 0.053000f, true); + // 080: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.222000f, 0.047000f, false); + shape.addVertex(0.252000f, 0.047000f, true); + // 081: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.314000f, 0.047000f, false); + shape.addVertex(0.350000f, 0.063000f, true); + // 083: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.386000f, 0.080000f, false); + shape.addVertex(0.400000f, 0.093000f, true); + // 084: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0.384000f, 0.119000f, false); + shape.addVertex(0.375000f, 0.154000f, true); + // 086: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0.366000f, 0.190000f, false); + shape.addVertex(0.365000f, 0.238000f, true); + System.err.println("Glyph02UbuntuLight_ae.shape03b.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } + // End Shape for Glyph 193 + + shape.setIsQuadraticNurbs(); + shape.setSharpness(shapesSharpness); + region.addOutlineShape(shape, null, rgbaColor); + + box.resize(shape.getBounds()); + } + + @Override + public String getSubString() { + return super.getSubString(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java new file mode 100644 index 000000000..45868762c --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java @@ -0,0 +1,804 @@ +/** + * Copyright 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.opengl.demos.graph.ui.testshapes; + +import com.jogamp.opengl.GL2ES2; +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.graph.ui.gl.Shape; + +/** + * GPU based resolution independent test object + * - FreeMono-Regular, capital case 'M' + * - TTF Shape for Glyph 48 + */ +public class Glyph03FreeMonoRegular_M extends Shape { + + public Glyph03FreeMonoRegular_M(final Factory<? extends Vertex> factory, final int renderModes) { + super(factory, renderModes); + } + + @Override + protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @Override + protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @SuppressWarnings("unused") + @Override + protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { + final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); + + if( false ) { + // Start TTF Shape for Glyph 48 + // GlyphShape<48>: offset 0 of 45/45 points + // pM[044] P[483/522, on true, end true] + // p0[000] P[326/169, on true, end false] + // p1[001] P[280/169, on true, end false] + // p2[002] P[121/522, on true, end false] + // 000: B0a: move-to p0 + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.326000f, 0.169000f, true); + // 000: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.280000f, 0.169000f, true); + // GlyphShape<48>: offset 1 of 45/45 points + // pM[000] P[326/169, on true, end false] + // p0[001] P[280/169, on true, end false] + // p1[002] P[121/522, on true, end false] + // p2[003] P[113/522, on true, end false] + // 001: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.121000f, 0.522000f, true); + // GlyphShape<48>: offset 2 of 45/45 points + // pM[001] P[280/169, on true, end false] + // p0[002] P[121/522, on true, end false] + // p1[003] P[113/522, on true, end false] + // p2[004] P[113/41, on true, end false] + // 002: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.113000f, 0.522000f, true); + // GlyphShape<48>: offset 3 of 45/45 points + // pM[002] P[121/522, on true, end false] + // p0[003] P[113/522, on true, end false] + // p1[004] P[113/41, on true, end false] + // p2[005] P[187/41, on true, end false] + // 003: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.113000f, 0.041000f, true); + // GlyphShape<48>: offset 4 of 45/45 points + // pM[003] P[113/522, on true, end false] + // p0[004] P[113/41, on true, end false] + // p1[005] P[187/41, on true, end false] + // p2[006] P[215/41, on false, end false] + // 004: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.187000f, 0.041000f, true); + // GlyphShape<48>: offset 5 of 45/45 points + // pM[004] P[113/41, on true, end false] + // p0[005] P[187/41, on true, end false] + // p1[006] P[215/41, on false, end false] + // p2[007] P[215/21, on true, end false] + // 005: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.215000f, 0.041000f, false); + shape.addVertex(0, 0.215000f, 0.021000f, true); + // GlyphShape<48>: offset 7 of 45/45 points + // pM[006] P[215/41, on false, end false] + // p0[007] P[215/21, on true, end false] + // p1[008] P[215/0, on false, end false] + // p2[009] P[187/0, on true, end false] + // 007: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.215000f, 0.000000f, false); + shape.addVertex(0, 0.187000f, 0.000000f, true); + // GlyphShape<48>: offset 9 of 45/45 points + // pM[008] P[215/0, on false, end false] + // p0[009] P[187/0, on true, end false] + // p1[010] P[38/0, on true, end false] + // p2[011] P[11/0, on false, end false] + // 009: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.038000f, 0.000000f, true); + // GlyphShape<48>: offset 10 of 45/45 points + // pM[009] P[187/0, on true, end false] + // p0[010] P[38/0, on true, end false] + // p1[011] P[11/0, on false, end false] + // p2[012] P[11/21, on true, end false] + // 010: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.011000f, 0.000000f, false); + shape.addVertex(0, 0.011000f, 0.021000f, true); + // GlyphShape<48>: offset 12 of 45/45 points + // pM[011] P[11/0, on false, end false] + // p0[012] P[11/21, on true, end false] + // p1[013] P[11/41, on false, end false] + // p2[014] P[38/41, on true, end false] + // 012: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.011000f, 0.041000f, false); + shape.addVertex(0, 0.038000f, 0.041000f, true); + // GlyphShape<48>: offset 14 of 45/45 points + // pM[013] P[11/41, on false, end false] + // p0[014] P[38/41, on true, end false] + // p1[015] P[72/41, on true, end false] + // p2[016] P[72/522, on true, end false] + // 014: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.072000f, 0.041000f, true); + // GlyphShape<48>: offset 15 of 45/45 points + // pM[014] P[38/41, on true, end false] + // p0[015] P[72/41, on true, end false] + // p1[016] P[72/522, on true, end false] + // p2[017] P[47/522, on true, end false] + // 015: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.072000f, 0.522000f, true); + // GlyphShape<48>: offset 16 of 45/45 points + // pM[015] P[72/41, on true, end false] + // p0[016] P[72/522, on true, end false] + // p1[017] P[47/522, on true, end false] + // p2[018] P[20/522, on false, end false] + // 016: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.047000f, 0.522000f, true); + // GlyphShape<48>: offset 17 of 45/45 points + // pM[016] P[72/522, on true, end false] + // p0[017] P[47/522, on true, end false] + // p1[018] P[20/522, on false, end false] + // p2[019] P[20/543, on true, end false] + // 017: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.020000f, 0.522000f, false); + shape.addVertex(0, 0.020000f, 0.543000f, true); + // GlyphShape<48>: offset 19 of 45/45 points + // pM[018] P[20/522, on false, end false] + // p0[019] P[20/543, on true, end false] + // p1[020] P[20/563, on false, end false] + // p2[021] P[47/563, on true, end false] + // 019: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.020000f, 0.563000f, false); + shape.addVertex(0, 0.047000f, 0.563000f, true); + // GlyphShape<48>: offset 21 of 45/45 points + // pM[020] P[20/563, on false, end false] + // p0[021] P[47/563, on true, end false] + // p1[022] P[146/563, on true, end false] + // p2[023] P[303/215, on true, end false] + // 021: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.146000f, 0.563000f, true); + // GlyphShape<48>: offset 22 of 45/45 points + // pM[021] P[47/563, on true, end false] + // p0[022] P[146/563, on true, end false] + // p1[023] P[303/215, on true, end false] + // p2[024] P[457/563, on true, end false] + // 022: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.303000f, 0.215000f, true); + // GlyphShape<48>: offset 23 of 45/45 points + // pM[022] P[146/563, on true, end false] + // p0[023] P[303/215, on true, end false] + // p1[024] P[457/563, on true, end false] + // p2[025] P[557/563, on true, end false] + // 023: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.457000f, 0.563000f, true); + // GlyphShape<48>: offset 24 of 45/45 points + // pM[023] P[303/215, on true, end false] + // p0[024] P[457/563, on true, end false] + // p1[025] P[557/563, on true, end false] + // p2[026] P[584/563, on false, end false] + // 024: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.557000f, 0.563000f, true); + // GlyphShape<48>: offset 25 of 45/45 points + // pM[024] P[457/563, on true, end false] + // p0[025] P[557/563, on true, end false] + // p1[026] P[584/563, on false, end false] + // p2[027] P[584/543, on true, end false] + // 025: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.584000f, 0.563000f, false); + shape.addVertex(0, 0.584000f, 0.543000f, true); + // GlyphShape<48>: offset 27 of 45/45 points + // pM[026] P[584/563, on false, end false] + // p0[027] P[584/543, on true, end false] + // p1[028] P[584/522, on false, end false] + // p2[029] P[557/522, on true, end false] + // 027: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.584000f, 0.522000f, false); + shape.addVertex(0, 0.557000f, 0.522000f, true); + // GlyphShape<48>: offset 29 of 45/45 points + // pM[028] P[584/522, on false, end false] + // p0[029] P[557/522, on true, end false] + // p1[030] P[532/522, on true, end false] + // p2[031] P[532/41, on true, end false] + // 029: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.532000f, 0.522000f, true); + // GlyphShape<48>: offset 30 of 45/45 points + // pM[029] P[557/522, on true, end false] + // p0[030] P[532/522, on true, end false] + // p1[031] P[532/41, on true, end false] + // p2[032] P[566/41, on true, end false] + // 030: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.532000f, 0.041000f, true); + // GlyphShape<48>: offset 31 of 45/45 points + // pM[030] P[532/522, on true, end false] + // p0[031] P[532/41, on true, end false] + // p1[032] P[566/41, on true, end false] + // p2[033] P[593/41, on false, end false] + // 031: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.566000f, 0.041000f, true); + // GlyphShape<48>: offset 32 of 45/45 points + // pM[031] P[532/41, on true, end false] + // p0[032] P[566/41, on true, end false] + // p1[033] P[593/41, on false, end false] + // p2[034] P[593/21, on true, end false] + // 032: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.593000f, 0.041000f, false); + shape.addVertex(0, 0.593000f, 0.021000f, true); + // GlyphShape<48>: offset 34 of 45/45 points + // pM[033] P[593/41, on false, end false] + // p0[034] P[593/21, on true, end false] + // p1[035] P[593/0, on false, end false] + // p2[036] P[566/0, on true, end false] + // 034: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.593000f, 0.000000f, false); + shape.addVertex(0, 0.566000f, 0.000000f, true); + // GlyphShape<48>: offset 36 of 45/45 points + // pM[035] P[593/0, on false, end false] + // p0[036] P[566/0, on true, end false] + // p1[037] P[417/0, on true, end false] + // p2[038] P[390/0, on false, end false] + // 036: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.417000f, 0.000000f, true); + // GlyphShape<48>: offset 37 of 45/45 points + // pM[036] P[566/0, on true, end false] + // p0[037] P[417/0, on true, end false] + // p1[038] P[390/0, on false, end false] + // p2[039] P[390/21, on true, end false] + // 037: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.390000f, 0.000000f, false); + shape.addVertex(0, 0.390000f, 0.021000f, true); + // GlyphShape<48>: offset 39 of 45/45 points + // pM[038] P[390/0, on false, end false] + // p0[039] P[390/21, on true, end false] + // p1[040] P[390/41, on false, end false] + // p2[041] P[417/41, on true, end false] + // 039: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.390000f, 0.041000f, false); + shape.addVertex(0, 0.417000f, 0.041000f, true); + // GlyphShape<48>: offset 41 of 45/45 points + // pM[040] P[390/41, on false, end false] + // p0[041] P[417/41, on true, end false] + // p1[042] P[491/41, on true, end false] + // p2[043] P[491/522, on true, end false] + // 041: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.491000f, 0.041000f, true); + // GlyphShape<48>: offset 42 of 45/45 points + // pM[041] P[417/41, on true, end false] + // p0[042] P[491/41, on true, end false] + // p1[043] P[491/522, on true, end false] + // p2[044] P[483/522, on true, end true] + // 042: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.491000f, 0.522000f, true); + // GlyphShape<48>: offset 43 of 45/45 points + // pM[042] P[491/41, on true, end false] + // p0[043] P[491/522, on true, end false] + // p1[044] P[483/522, on true, end true] + // p2[000] P[326/169, on true, end false] + // 043: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.483000f, 0.522000f, true); + // GlyphShape<48>: offset 44 of 45/45 points + // pM[043] P[491/522, on true, end false] + // p0[044] P[483/522, on true, end true] + // p1[000] P[326/169, on true, end false] + // p2[001] P[280/169, on true, end false] + // 044: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.326000f, 0.169000f, true); + System.err.println("Glyph03FreeMonoRegular_M.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + + // End Shape for Glyph 48 + } else if( false ) { + // Start TTF Shape for Glyph 48 + // GlyphShape<48>: offset 0 of 45/45 points + // pM[044] P[483/522, on true, end true] + // p0[000] P[326/169, on true, end false] + // p1[001] P[280/169, on true, end false] + // p2[002] P[121/522, on true, end false] + // 000: B0a: move-to p0 + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.326000f, 0.169000f, true); + // 000: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.280000f, 0.169000f, true); + // GlyphShape<48>: offset 1 of 45/45 points + // pM[000] P[326/169, on true, end false] + // p0[001] P[280/169, on true, end false] + // p1[002] P[121/522, on true, end false] + // p2[003] P[113/522, on true, end false] + // 001: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.121000f, 0.522000f, true); + // GlyphShape<48>: offset 2 of 45/45 points + // pM[001] P[280/169, on true, end false] + // p0[002] P[121/522, on true, end false] + // p1[003] P[113/522, on true, end false] + // p2[004] P[113/41, on true, end false] + // 002: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.113000f, 0.522000f, true); + // GlyphShape<48>: offset 3 of 45/45 points + // pM[002] P[121/522, on true, end false] + // p0[003] P[113/522, on true, end false] + // p1[004] P[113/41, on true, end false] + // p2[005] P[187/41, on true, end false] + // 003: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.113000f, 0.041000f, true); + // GlyphShape<48>: offset 4 of 45/45 points + // pM[003] P[113/522, on true, end false] + // p0[004] P[113/41, on true, end false] + // p1[005] P[187/41, on true, end false] + // p2[006] P[215/41, on false, end false] + // 004: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.187000f, 0.041000f, true); + // GlyphShape<48>: offset 5 of 45/45 points + // pM[004] P[113/41, on true, end false] + // p0[005] P[187/41, on true, end false] + // p1[006] P[215/41, on false, end false] + // p2[007] P[215/21, on true, end false] + // 005: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.215000f, 0.041000f, true); // curve -> line + shape.addVertex(0, 0.215000f, 0.021000f, true); + // GlyphShape<48>: offset 7 of 45/45 points + // pM[006] P[215/41, on false, end false] + // p0[007] P[215/21, on true, end false] + // p1[008] P[215/0, on false, end false] + // p2[009] P[187/0, on true, end false] + // 007: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.215000f, 0.000000f, true); // curve -> line + shape.addVertex(0, 0.187000f, 0.000000f, true); + // GlyphShape<48>: offset 9 of 45/45 points + // pM[008] P[215/0, on false, end false] + // p0[009] P[187/0, on true, end false] + // p1[010] P[38/0, on true, end false] + // p2[011] P[11/0, on false, end false] + // 009: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.038000f, 0.000000f, true); + // GlyphShape<48>: offset 10 of 45/45 points + // pM[009] P[187/0, on true, end false] + // p0[010] P[38/0, on true, end false] + // p1[011] P[11/0, on false, end false] + // p2[012] P[11/21, on true, end false] + // 010: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.011000f, 0.000000f, true); // curve -> line + shape.addVertex(0, 0.011000f, 0.021000f, true); + // GlyphShape<48>: offset 12 of 45/45 points + // pM[011] P[11/0, on false, end false] + // p0[012] P[11/21, on true, end false] + // p1[013] P[11/41, on false, end false] + // p2[014] P[38/41, on true, end false] + // 012: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.011000f, 0.041000f, true); // curve -> line + shape.addVertex(0, 0.038000f, 0.041000f, true); + // GlyphShape<48>: offset 14 of 45/45 points + // pM[013] P[11/41, on false, end false] + // p0[014] P[38/41, on true, end false] + // p1[015] P[72/41, on true, end false] + // p2[016] P[72/522, on true, end false] + // 014: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.072000f, 0.041000f, true); + // GlyphShape<48>: offset 15 of 45/45 points + // pM[014] P[38/41, on true, end false] + // p0[015] P[72/41, on true, end false] + // p1[016] P[72/522, on true, end false] + // p2[017] P[47/522, on true, end false] + // 015: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.072000f, 0.522000f, true); + // GlyphShape<48>: offset 16 of 45/45 points + // pM[015] P[72/41, on true, end false] + // p0[016] P[72/522, on true, end false] + // p1[017] P[47/522, on true, end false] + // p2[018] P[20/522, on false, end false] + // 016: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.047000f, 0.522000f, true); + // GlyphShape<48>: offset 17 of 45/45 points + // pM[016] P[72/522, on true, end false] + // p0[017] P[47/522, on true, end false] + // p1[018] P[20/522, on false, end false] + // p2[019] P[20/543, on true, end false] + // 017: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.020000f, 0.522000f, true); // curve -> line + shape.addVertex(0, 0.020000f, 0.543000f, true); + // GlyphShape<48>: offset 19 of 45/45 points + // pM[018] P[20/522, on false, end false] + // p0[019] P[20/543, on true, end false] + // p1[020] P[20/563, on false, end false] + // p2[021] P[47/563, on true, end false] + // 019: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.020000f, 0.563000f, true); // curve -> line + shape.addVertex(0, 0.047000f, 0.563000f, true); + // GlyphShape<48>: offset 21 of 45/45 points + // pM[020] P[20/563, on false, end false] + // p0[021] P[47/563, on true, end false] + // p1[022] P[146/563, on true, end false] + // p2[023] P[303/215, on true, end false] + // 021: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.146000f, 0.563000f, true); + // GlyphShape<48>: offset 22 of 45/45 points + // pM[021] P[47/563, on true, end false] + // p0[022] P[146/563, on true, end false] + // p1[023] P[303/215, on true, end false] + // p2[024] P[457/563, on true, end false] + // 022: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.303000f, 0.215000f, true); + // GlyphShape<48>: offset 23 of 45/45 points + // pM[022] P[146/563, on true, end false] + // p0[023] P[303/215, on true, end false] + // p1[024] P[457/563, on true, end false] + // p2[025] P[557/563, on true, end false] + // 023: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.457000f, 0.563000f, true); + // GlyphShape<48>: offset 24 of 45/45 points + // pM[023] P[303/215, on true, end false] + // p0[024] P[457/563, on true, end false] + // p1[025] P[557/563, on true, end false] + // p2[026] P[584/563, on false, end false] + // 024: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.557000f, 0.563000f, true); + // GlyphShape<48>: offset 25 of 45/45 points + // pM[024] P[457/563, on true, end false] + // p0[025] P[557/563, on true, end false] + // p1[026] P[584/563, on false, end false] + // p2[027] P[584/543, on true, end false] + // 025: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.584000f, 0.563000f, true); // curve -> line + shape.addVertex(0, 0.584000f, 0.543000f, true); + // GlyphShape<48>: offset 27 of 45/45 points + // pM[026] P[584/563, on false, end false] + // p0[027] P[584/543, on true, end false] + // p1[028] P[584/522, on false, end false] + // p2[029] P[557/522, on true, end false] + // 027: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.584000f, 0.522000f, true); // curve -> line + shape.addVertex(0, 0.557000f, 0.522000f, true); + // GlyphShape<48>: offset 29 of 45/45 points + // pM[028] P[584/522, on false, end false] + // p0[029] P[557/522, on true, end false] + // p1[030] P[532/522, on true, end false] + // p2[031] P[532/41, on true, end false] + // 029: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.532000f, 0.522000f, true); + // GlyphShape<48>: offset 30 of 45/45 points + // pM[029] P[557/522, on true, end false] + // p0[030] P[532/522, on true, end false] + // p1[031] P[532/41, on true, end false] + // p2[032] P[566/41, on true, end false] + // 030: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.532000f, 0.041000f, true); + // GlyphShape<48>: offset 31 of 45/45 points + // pM[030] P[532/522, on true, end false] + // p0[031] P[532/41, on true, end false] + // p1[032] P[566/41, on true, end false] + // p2[033] P[593/41, on false, end false] + // 031: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.566000f, 0.041000f, true); + // GlyphShape<48>: offset 32 of 45/45 points + // pM[031] P[532/41, on true, end false] + // p0[032] P[566/41, on true, end false] + // p1[033] P[593/41, on false, end false] + // p2[034] P[593/21, on true, end false] + // 032: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.593000f, 0.041000f, true); // curve -> line + shape.addVertex(0, 0.593000f, 0.021000f, true); + // GlyphShape<48>: offset 34 of 45/45 points + // pM[033] P[593/41, on false, end false] + // p0[034] P[593/21, on true, end false] + // p1[035] P[593/0, on false, end false] + // p2[036] P[566/0, on true, end false] + // 034: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.593000f, 0.000000f, true); // curve -> line + shape.addVertex(0, 0.566000f, 0.000000f, true); + // GlyphShape<48>: offset 36 of 45/45 points + // pM[035] P[593/0, on false, end false] + // p0[036] P[566/0, on true, end false] + // p1[037] P[417/0, on true, end false] + // p2[038] P[390/0, on false, end false] + // 036: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.417000f, 0.000000f, true); + // GlyphShape<48>: offset 37 of 45/45 points + // pM[036] P[566/0, on true, end false] + // p0[037] P[417/0, on true, end false] + // p1[038] P[390/0, on false, end false] + // p2[039] P[390/21, on true, end false] + // 037: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.390000f, 0.000000f, true); // curve -> line + shape.addVertex(0, 0.390000f, 0.021000f, true); + // GlyphShape<48>: offset 39 of 45/45 points + // pM[038] P[390/0, on false, end false] + // p0[039] P[390/21, on true, end false] + // p1[040] P[390/41, on false, end false] + // p2[041] P[417/41, on true, end false] + // 039: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.390000f, 0.041000f, true); // curve -> line + shape.addVertex(0, 0.417000f, 0.041000f, true); + // GlyphShape<48>: offset 41 of 45/45 points + // pM[040] P[390/41, on false, end false] + // p0[041] P[417/41, on true, end false] + // p1[042] P[491/41, on true, end false] + // p2[043] P[491/522, on true, end false] + // 041: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.491000f, 0.041000f, true); + // GlyphShape<48>: offset 42 of 45/45 points + // pM[041] P[417/41, on true, end false] + // p0[042] P[491/41, on true, end false] + // p1[043] P[491/522, on true, end false] + // p2[044] P[483/522, on true, end true] + // 042: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.491000f, 0.522000f, true); + // GlyphShape<48>: offset 43 of 45/45 points + // pM[042] P[491/41, on true, end false] + // p0[043] P[491/522, on true, end false] + // p1[044] P[483/522, on true, end true] + // p2[000] P[326/169, on true, end false] + // 043: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.483000f, 0.522000f, true); + // GlyphShape<48>: offset 44 of 45/45 points + // pM[043] P[491/522, on true, end false] + // p0[044] P[483/522, on true, end true] + // p1[000] P[326/169, on true, end false] + // p2[001] P[280/169, on true, end false] + // 044: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.326000f, 0.169000f, true); + System.err.println("Glyph03FreeMonoRegular_M.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } else { + final boolean with_left_leg = true; // ERROR + final boolean with_right_leg = false; // OK + + // Start TTF Shape for Glyph 48 + // GlyphShape<48>: offset 0 of 45/45 points + // pM[044] P[483/522, on true, end true] + // p0[000] P[326/169, on true, end false] + // p1[001] P[280/169, on true, end false] + // p2[002] P[121/522, on true, end false] + // 000: B0a: move-to p0 + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.326000f, 0.169000f, true); + // 000: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.280000f, 0.169000f, true); + // GlyphShape<48>: offset 1 of 45/45 points + // pM[000] P[326/169, on true, end false] + // p0[001] P[280/169, on true, end false] + // p1[002] P[121/522, on true, end false] + // p2[003] P[113/522, on true, end false] + // 001: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.121000f, 0.522000f, true); // ID 11 + + // GlyphShape<48>: offset 2 of 45/45 points + // pM[001] P[280/169, on true, end false] + // p0[002] P[121/522, on true, end false] + // p1[003] P[113/522, on true, end false] + // p2[004] P[113/41, on true, end false] + // 002: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.113000f, 0.522000f, true); + + if( with_left_leg ) { + // GlyphShape<48>: offset 3 of 45/45 points + // pM[002] P[121/522, on true, end false] + // p0[003] P[113/522, on true, end false] + // p1[004] P[113/41, on true, end false] + // p2[005] P[187/41, on true, end false] + // 003: B1: line-to p0-p1 + // Shape.LineTo: + // shape.addVertex(0, 0.113000f, 0.041000f, true); + + shape.addVertex(0, 0.113000f, 0.000000f, true); + shape.addVertex(0, 0.072000f, 0.000000f, true); + + // GlyphShape<48>: offset 14 of 45/45 points + // pM[013] P[11/41, on false, end false] + // p0[014] P[38/41, on true, end false] + // p1[015] P[72/41, on true, end false] + // p2[016] P[72/522, on true, end false] + // 014: B1: line-to p0-p1 + // Shape.LineTo: + // shape.addVertex(0, 0.072000f, 0.041000f, true); + + // GlyphShape<48>: offset 15 of 45/45 points + // pM[014] P[38/41, on true, end false] + // p0[015] P[72/41, on true, end false] + // p1[016] P[72/522, on true, end false] + // p2[017] P[47/522, on true, end false] + // 015: B1: line-to p0-p1 + // Shape.LineTo: + // shape.addVertex(0, 0.072000f, 0.522000f, true); + + shape.addVertex(0, 0.072000f, 0.563000f, true); // ID 7 + } else { + shape.addVertex(0, 0.113000f, 0.563000f, true); + } + + // GlyphShape<48>: offset 21 of 45/45 points + // pM[020] P[20/563, on false, end false] + // p0[021] P[47/563, on true, end false] + // p1[022] P[146/563, on true, end false] + // p2[023] P[303/215, on true, end false] + // 021: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.146000f, 0.563000f, true); + // GlyphShape<48>: offset 22 of 45/45 points + // pM[021] P[47/563, on true, end false] + // p0[022] P[146/563, on true, end false] + // p1[023] P[303/215, on true, end false] + // p2[024] P[457/563, on true, end false] + // 022: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.303000f, 0.215000f, true); + // GlyphShape<48>: offset 23 of 45/45 points + // pM[022] P[146/563, on true, end false] + // p0[023] P[303/215, on true, end false] + // p1[024] P[457/563, on true, end false] + // p2[025] P[557/563, on true, end false] + // 023: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.457000f, 0.563000f, true); // ID 4 + + if( with_right_leg ) { + shape.addVertex(0, 0.532000f, 0.563000f, true); + + // GlyphShape<48>: offset 29 of 45/45 points + // pM[028] P[584/522, on false, end false] + // p0[029] P[557/522, on true, end false] + // p1[030] P[532/522, on true, end false] + // p2[031] P[532/41, on true, end false] + // 029: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.532000f, 0.522000f, true); + // GlyphShape<48>: offset 30 of 45/45 points + // pM[029] P[557/522, on true, end false] + // p0[030] P[532/522, on true, end false] + // p1[031] P[532/41, on true, end false] + // p2[032] P[566/41, on true, end false] + // 030: B1: line-to p0-p1 + // Shape.LineTo: + // shape.addVertex(0, 0.532000f, 0.041000f, true); + + shape.addVertex(0, 0.532000f, 0.000000f, true); + shape.addVertex(0, 0.491000f, 0.000000f, true); + } else { + shape.addVertex(0, 0.491000f, 0.563000f, true); // ID 3 + } + + // GlyphShape<48>: offset 41 of 45/45 points + // pM[040] P[390/41, on false, end false] + // p0[041] P[417/41, on true, end false] + // p1[042] P[491/41, on true, end false] + // p2[043] P[491/522, on true, end false] + // 041: B1: line-to p0-p1 + // Shape.LineTo: + // shape.addVertex(0, 0.491000f, 0.041000f, true); + + // GlyphShape<48>: offset 42 of 45/45 points + // pM[041] P[417/41, on true, end false] + // p0[042] P[491/41, on true, end false] + // p1[043] P[491/522, on true, end false] + // p2[044] P[483/522, on true, end true] + // 042: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.491000f, 0.522000f, true); // ID 2 + // GlyphShape<48>: offset 43 of 45/45 points + // pM[042] P[491/41, on true, end false] + // p0[043] P[491/522, on true, end false] + // p1[044] P[483/522, on true, end true] + // p2[000] P[326/169, on true, end false] + // 043: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.483000f, 0.522000f, true); // ID 1 + // GlyphShape<48>: offset 44 of 45/45 points + // pM[043] P[491/522, on true, end false] + // p0[044] P[483/522, on true, end true] + // p1[000] P[326/169, on true, end false] + // p2[001] P[280/169, on true, end false] + // 044: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.326000f, 0.169000f, true); + System.err.println("Glyph03FreeMonoRegular_M.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } + + shape.setIsQuadraticNurbs(); + shape.setSharpness(shapesSharpness); + region.addOutlineShape(shape, null, rgbaColor); + + box.resize(shape.getBounds()); + } + + @Override + public String getSubString() { + return super.getSubString(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java new file mode 100644 index 000000000..63bc0b5b5 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java @@ -0,0 +1,150 @@ +/** + * Copyright 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.opengl.demos.graph.ui.testshapes; + +import com.jogamp.opengl.GL2ES2; +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.graph.ui.gl.Shape; + +/** + * GPU based resolution independent test object + * - FreeSans, '0' + * - TTF Shape for Glyph 19 + */ +public class Glyph04FreeSans_0 extends Shape { + + public Glyph04FreeSans_0(final Factory<? extends Vertex> factory, final int renderModes) { + super(factory, renderModes); + } + + @Override + protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @Override + protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @Override + protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { + final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); + + // Start TTF Shape for Glyph 19 + // 000: B0a: move-to p0 + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.043000f, 0.343000f, true); + // 000: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.043000f, 0.432000f, false); + shape.addVertex(0, 0.058000f, 0.500000f, true); + // 002: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.073000f, 0.568000f, false); + shape.addVertex(0, 0.096000f, 0.606000f, true); + // 003: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.119000f, 0.645000f, false); + shape.addVertex(0, 0.151000f, 0.669000f, true); + // 004: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.183000f, 0.693000f, false); + shape.addVertex(0, 0.212000f, 0.701000f, true); + // 005: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.242000f, 0.709000f, false); + shape.addVertex(0, 0.275000f, 0.709000f, true); + // 006: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.507000f, 0.709000f, false); + shape.addVertex(0, 0.507000f, 0.337000f, true); + // 008: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.507000f, 0.162000f, false); + shape.addVertex(0, 0.448000f, 0.070000f, true); + // 010: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.388000f, -0.023000f, false); + shape.addVertex(0, 0.275000f, -0.023000f, true); + // 011: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.161000f, -0.023000f, false); + shape.addVertex(0, 0.102000f, 0.070000f, true); + // 013: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.043000f, 0.164000f, false); + shape.addVertex(0, 0.043000f, 0.343000f, true); + System.err.println("Glyph04FreeSans_0.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + + // 021: B0b: move-to pM + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.417000f, 0.345000f, true); + // 021: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.417000f, 0.631000f, false); + shape.addVertex(0, 0.275000f, 0.631000f, true); + // 015: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.133000f, 0.631000f, false); + shape.addVertex(0, 0.133000f, 0.342000f, true); + // 016: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.133000f, 0.050000f, false); + shape.addVertex(0, 0.273000f, 0.050000f, true); + // 018: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.347000f, 0.050000f, false); + shape.addVertex(0, 0.382000f, 0.122000f, true); + // 020: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.417000f, 0.194000f, false); + shape.addVertex(0, 0.417000f, 0.345000f, true); + System.err.println("Glyph04FreeSans_0.shape02a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + + // End Shape for Glyph 19 + + shape.setIsQuadraticNurbs(); + shape.setSharpness(shapesSharpness); + region.addOutlineShape(shape, null, rgbaColor); + + box.resize(shape.getBounds()); + } + + @Override + public String getSubString() { + return super.getSubString(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java new file mode 100644 index 000000000..dd92228ff --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java @@ -0,0 +1,287 @@ +/** + * Copyright 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.opengl.demos.graph.ui.testshapes; + +import com.jogamp.opengl.GL2ES2; +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.graph.ui.gl.Shape; + +/** + * GPU based resolution independent test object + * - FreeSans, '0' + * - TTF Shape for Glyph 19 + */ +public class Glyph05FreeSerifBoldItalic_ae extends Shape { + + public Glyph05FreeSerifBoldItalic_ae(final Factory<? extends Vertex> factory, final int renderModes) { + super(factory, renderModes); + } + + @Override + protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @Override + protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { + } + + @Override + protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { + final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); + + // Start TTF Shape for Glyph 168 + // 000: B0a: move-to p0 + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.450000f, -0.013000f, true); + // 000: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.386000f, -0.013000f, false); + shape.addVertex(0, 0.353000f, 0.018000f, true); + // 002: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.319000f, 0.049000f, false); + shape.addVertex(0, 0.307000f, 0.118000f, true); + // 003: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.265000f, 0.049000f, false); + shape.addVertex(0, 0.225000f, 0.019000f, true); + // 005: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.184000f, -0.012000f, false); + shape.addVertex(0, 0.134000f, -0.012000f, true); + // 006: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.085000f, -0.012000f, false); + shape.addVertex(0, 0.053000f, 0.021000f, true); + // 008: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.020000f, 0.055000f, false); + shape.addVertex(0, 0.020000f, 0.106000f, true); + // 009: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.020000f, 0.185000f, false); + shape.addVertex(0, 0.062000f, 0.269000f, true); + // 011: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.105000f, 0.353000f, false); + shape.addVertex(0, 0.170000f, 0.407000f, true); + // 012: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.235000f, 0.462000f, false); + shape.addVertex(0, 0.296000f, 0.462000f, true); + // 013: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.328000f, 0.462000f, false); + shape.addVertex(0, 0.346000f, 0.448000f, true); + // 015: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.364000f, 0.433000f, false); + shape.addVertex(0, 0.377000f, 0.396000f, true); + // 016: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.395000f, 0.454000f, true); + // 017: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.498000f, 0.459000f, true); + // 018: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.478000f, 0.394000f, true); + // 019: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.510000f, 0.431000f, false); + shape.addVertex(0, 0.535000f, 0.445000f, true); + // 021: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.561000f, 0.459000f, false); + shape.addVertex(0, 0.598000f, 0.459000f, true); + // 022: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.645000f, 0.459000f, false); + shape.addVertex(0, 0.671000f, 0.436000f, true); + // 024: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.698000f, 0.413000f, false); + shape.addVertex(0, 0.698000f, 0.372000f, true); + // 025: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.698000f, 0.310000f, false); + shape.addVertex(0, 0.639000f, 0.263000f, true); + // 027: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.579000f, 0.215000f, false); + shape.addVertex(0, 0.470000f, 0.190000f, true); + // 028: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.431000f, 0.181000f, true); + // 029: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.426000f, 0.156000f, false); + shape.addVertex(0, 0.426000f, 0.134000f, true); + // 031: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.426000f, 0.096000f, false); + shape.addVertex(0, 0.444000f, 0.073000f, true); + // 033: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.462000f, 0.050000f, false); + shape.addVertex(0, 0.493000f, 0.050000f, true); + // 034: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.565000f, 0.050000f, false); + shape.addVertex(0, 0.616000f, 0.139000f, true); + // 036: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.644000f, 0.122000f, true); + // 037: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.578000f, -0.013000f, false); + shape.addVertex(0, 0.450000f, -0.013000f, true); + System.err.println("Glyph05FreeSerifBoldItalic_ae.shape01a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + + // 039: B0a: move-to p0 + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.194000f, 0.058000f, true); + // 039: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.238000f, 0.058000f, false); + shape.addVertex(0, 0.278000f, 0.122000f, true); + // 041: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.319000f, 0.187000f, false); + shape.addVertex(0, 0.338000f, 0.256000f, true); + // 042: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.358000f, 0.326000f, false); + shape.addVertex(0, 0.358000f, 0.363000f, true); + // 043: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.358000f, 0.387000f, false); + shape.addVertex(0, 0.345000f, 0.403000f, true); + // 045: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.331000f, 0.419000f, false); + shape.addVertex(0, 0.310000f, 0.419000f, true); + // 046: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.267000f, 0.419000f, false); + shape.addVertex(0, 0.227000f, 0.356000f, true); + // 048: B5: quad-to pMh-p0-p1h ***** MID + // Shape.QuadTo: + shape.addVertex(0, 0.187000f, 0.293000f, false); + shape.addVertex(0, 0.167000f, 0.225000f, true); + // 049: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.146000f, 0.156000f, false); + shape.addVertex(0, 0.146000f, 0.119000f, true); + // 050: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.146000f, 0.092000f, false); + shape.addVertex(0, 0.159000f, 0.075000f, true); + // 052: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.172000f, 0.058000f, false); + shape.addVertex(0, 0.194000f, 0.058000f, true); + System.err.println("Glyph05FreeSerifBoldItalic_ae.shape02a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + + if( true ) { + // GlyphShape<168>: offset 0 of 8/61 points + // pM[060] P[443/231, on true, end true] + // p0[053] P[438/214, on true, end false] + // p1[054] P[498/223, on false, end false] + // p2[055] P[608/320, on false, end false] + // 053: B0a: move-to p0 + // Shape.MoveTo: + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, 0.438000f, 0.214000f, true); + // 053: B4: quad-to p0-p1-p2h **** MID + // Shape.QuadTo: + shape.addVertex(0, 0.498000f, 0.223000f, false); + shape.addVertex(0, 0.553000f, 0.271000f, true); + // GlyphShape<168>: offset 2 of 8/61 points + // pM[054] P[498/223, on false, end false] + // p0[055] P[608/320, on false, end false] + // p1[056] P[608/388, on true, end false] + // p2[057] P[608/429, on false, end false] + // 055: B6: quad-to pMh-p0-p1 + // Shape.QuadTo: + shape.addVertex(0, 0.608000f, 0.320000f, false); + shape.addVertex(0, 0.608000f, 0.388000f, true); + // GlyphShape<168>: offset 3 of 8/61 points + // pM[055] P[608/320, on false, end false] + // p0[056] P[608/388, on true, end false] + // p1[057] P[608/429, on false, end false] + // p2[058] P[575/429, on true, end false] + // 056: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.608000f, 0.429000f, false); + shape.addVertex(0, 0.575000f, 0.429000f, true); + // GlyphShape<168>: offset 5 of 8/61 points + // pM[057] P[608/429, on false, end false] + // p0[058] P[575/429, on true, end false] + // p1[059] P[502/429, on false, end false] + // p2[060] P[443/231, on true, end true] + // 058: B2: quad-to p0-p1-p2 + // Shape.QuadTo: + shape.addVertex(0, 0.502000f, 0.429000f, false); + shape.addVertex(0, 0.443000f, 0.231000f, true); + // GlyphShape<168>: offset 7 of 8/61 points + // pM[059] P[502/429, on false, end false] + // p0[060] P[443/231, on true, end true] + // p1[053] P[438/214, on true, end false] + // p2[054] P[498/223, on false, end false] + // 060: B1: line-to p0-p1 + // Shape.LineTo: + shape.addVertex(0, 0.438000f, 0.214000f, true); + System.err.println("Glyph05FreeSerifBoldItalic_ae.shape03a.winding_area: "+shape.getWindingOfLastOutline()); + shape.closeLastOutline(false); + } + + // End Shape for Glyph 168 + + shape.setIsQuadraticNurbs(); + shape.setSharpness(shapesSharpness); + region.addOutlineShape(shape, null, rgbaColor); + + box.resize(shape.getBounds()); + } + + @Override + public String getSubString() { + return super.getSubString(); + } +} diff --git a/src/demos/com/jogamp/opengl/demos/MiscUtils.java b/src/demos/com/jogamp/opengl/demos/util/MiscUtils.java index 304e4f18a..f1c367e95 100644 --- a/src/demos/com/jogamp/opengl/demos/MiscUtils.java +++ b/src/demos/com/jogamp/opengl/demos/util/MiscUtils.java @@ -27,7 +27,7 @@ */ -package com.jogamp.opengl.demos; +package com.jogamp.opengl.demos.util; import java.io.BufferedReader; import java.io.IOException; diff --git a/src/demos/com/jogamp/opengl/demos/util/QuitAdapter.java b/src/demos/com/jogamp/opengl/demos/util/QuitAdapter.java new file mode 100644 index 000000000..b7c3a6c22 --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/util/QuitAdapter.java @@ -0,0 +1,64 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.demos.util; + +import com.jogamp.newt.event.*; + +public class QuitAdapter extends WindowAdapter implements WindowListener, KeyListener { + boolean shouldQuit = false; + boolean enabled = true; + + public void enable(final boolean v) { enabled = v; } + + public void clear() { shouldQuit = false; } + + public boolean shouldQuit() { return shouldQuit; } + public void doQuit() { shouldQuit=true; } + + public void windowDestroyNotify(final WindowEvent e) { + if( enabled ) { + System.err.println("QUIT Window "+Thread.currentThread()); + shouldQuit = true; + } + } + + public void keyReleased(final KeyEvent e) { + if( !e.isPrintableKey() || e.isAutoRepeat() ) { + return; + } + if( enabled ) { + if(e.getKeyChar()=='q') { + System.err.println("QUIT Key "+Thread.currentThread()); + shouldQuit = true; + } + } + } + public void keyPressed(final KeyEvent e) {} +} + |