aboutsummaryrefslogtreecommitdiffstats
path: root/src/demos/com/jogamp
diff options
context:
space:
mode:
Diffstat (limited to 'src/demos/com/jogamp')
-rw-r--r--src/demos/com/jogamp/opengl/demos/Launcher0.java1
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/LauncherUtil.java430
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0a.java166
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieCubeActivity0b.java168
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0a.java87
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher0b.java87
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1a.java87
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieCubeActivityLauncher1b.java87
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity0.java159
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivity1.java262
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00b.java84
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher00c.java84
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01a.java87
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher01b.java87
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/MovieSimpleActivityLauncher02.java87
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2Activity.java134
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ActivityLauncher.java84
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2ECTActivityLauncher.java80
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2RGB565ActivityLauncher.java80
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivity.java88
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGearsES2TransActivityLauncher.java58
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivity.java80
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI1pActivityLauncher.java52
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivity.java79
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTGraphUI2pActivityLauncher.java52
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2Activity.java99
-rw-r--r--src/demos/com/jogamp/opengl/demos/android/NEWTRedSquareES2ActivityLauncher.java21
-rw-r--r--src/demos/com/jogamp/opengl/demos/av/CrossFadePlayer.java212
-rw-r--r--src/demos/com/jogamp/opengl/demos/av/MovieCube.java655
-rw-r--r--src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java887
-rw-r--r--src/demos/com/jogamp/opengl/demos/av/MovieSimple.java1123
-rw-r--r--src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java403
-rw-r--r--src/demos/com/jogamp/opengl/demos/es2/GearsES2.java3
-rw-r--r--src/demos/com/jogamp/opengl/demos/es2/GearsObjectES2.java4
-rw-r--r--src/demos/com/jogamp/opengl/demos/es2/TextureSequenceCubeES2.java491
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/FontSetDemos.java35
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener00.java134
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener01.java299
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPURegionGLListener10.java138
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPURegionNewtDemo.java162
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPURendererListenerBase01.java361
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPUTextGLListener0A.java72
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java193
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java588
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/MSAATool.java96
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/TextRendererGLELBase.java291
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMono.ttfbin0 -> 592632 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBold.ttfbin0 -> 299136 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBoldOblique.ttfbin0 -> 298940 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoOblique.ttfbin0 -> 395188 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSans.ttfbin0 -> 1563256 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBold.ttfbin0 -> 416128 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBoldOblique.ttfbin0 -> 342492 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansOblique.ttfbin0 -> 763676 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerif.ttfbin0 -> 3303588 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBold.ttfbin0 -> 1310828 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBoldItalic.ttfbin0 -> 608676 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifItalic.ttfbin0 -> 922104 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneGLListener0A.java973
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneNewtDemo.java201
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/GPUUISceneTextAnim01.java351
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/UIShapeDemo01.java569
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/UITypeDemo01.java617
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/button-pressed-145x53.pngbin0 -> 8603 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/button-released-145x53.pngbin0 -> 9429 bytes
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java316
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java652
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java804
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java150
-rw-r--r--src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java287
-rw-r--r--src/demos/com/jogamp/opengl/demos/util/MiscUtils.java (renamed from src/demos/com/jogamp/opengl/demos/MiscUtils.java)2
-rw-r--r--src/demos/com/jogamp/opengl/demos/util/QuitAdapter.java64
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
new file mode 100644
index 000000000..c4200565a
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMono.ttf
Binary files differ
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
new file mode 100644
index 000000000..0bee057ec
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBold.ttf
Binary files differ
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
new file mode 100644
index 000000000..91bbc0e8a
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoBoldOblique.ttf
Binary files differ
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
new file mode 100644
index 000000000..3252bdda6
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeMonoOblique.ttf
Binary files differ
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
new file mode 100644
index 000000000..e56dc6e90
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSans.ttf
Binary files differ
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
new file mode 100644
index 000000000..66e19ecb0
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBold.ttf
Binary files differ
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
new file mode 100644
index 000000000..de8a9e153
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansBoldOblique.ttf
Binary files differ
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
new file mode 100644
index 000000000..b0357eabb
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSansOblique.ttf
Binary files differ
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
new file mode 100644
index 000000000..dffa1aedb
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerif.ttf
Binary files differ
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
new file mode 100644
index 000000000..e2393ad22
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBold.ttf
Binary files differ
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
new file mode 100644
index 000000000..46bc4695f
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifBoldItalic.ttf
Binary files differ
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
new file mode 100644
index 000000000..d173e3566
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/fonts/freefont/FreeSerifItalic.ttf
Binary files differ
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
new file mode 100644
index 000000000..1eba3a09e
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/ui/button-pressed-145x53.png
Binary files differ
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
new file mode 100644
index 000000000..fe223c6d3
--- /dev/null
+++ b/src/demos/com/jogamp/opengl/demos/graph/ui/button-released-145x53.png
Binary files differ
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) {}
+}
+