From 308497ffa60fafa087d195bbe7deb60a7f88ecb6 Mon Sep 17 00:00:00 2001 From: Izumi Kawashima Date: Sun, 20 Nov 2016 17:37:01 +0900 Subject: [PATCH] Update vtm-web modules (#240) #51 --- README.md | 1 + build.gradle | 1 + settings.gradle | 4 +- vtm-web-app/build.gradle | 4 +- .../src/org/oscim/web/VtmWebApp.gwt.xml | 3 +- .../src/org/oscim/web/client/GwtLauncher.java | 11 +- .../src/org/oscim/web/client/GwtMap.java | 12 +- vtm-web-js/build.gradle | 4 +- vtm-web-js/src/org/oscim/web/VtmWebJs.gwt.xml | 6 +- .../src/org/oscim/web/client/GwtLauncher.java | 11 +- .../gdx/backends/gwt/GwtApplication.java | 494 +++++++++---- .../gdx/backends/gwt/GwtGraphics.java | 293 +++++++- .../badlogic/gdx/backends/gwt/GwtInput.java | 665 +++++++++--------- .../emu/com/badlogic/gdx/graphics/Pixmap.java | 548 +++++++++------ .../gdx/emu/java/io/FileInputStream.java | 22 + .../js/soundmanager2-nodebug-jsmin.js | 83 +++ 16 files changed, 1410 insertions(+), 752 deletions(-) create mode 100644 vtm-web/src/org/oscim/gdx/emu/java/io/FileInputStream.java create mode 100755 vtm-web/src/org/oscim/gdx/resources/js/soundmanager2-nodebug-jsmin.js diff --git a/README.md b/README.md index 44700344..45d03542 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ If you have any questions or problems, don't hesitate to ask our public [mailing - **vtm-web-app** HTML5/GWT application The libGDX backend for GWT is experimental. +- `./gradlew :vtm-web-app:jettyDraftWar` will run standalone Jetty server at port 8080. See http://localhost:8080/vtm-web-app in your web browser. ## Applications - VTM is used by many [applications](docs/Applications.md). diff --git a/build.gradle b/build.gradle index 434a29db..f10e5c9a 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ allprojects { ext.androidBuildVersionTools = "25.0.0" ext.gdxVersion = "1.9.4" + ext.gwtVersion = "2.7.0" if (JavaVersion.current().isJava8Compatible()) { tasks.withType(Javadoc) { diff --git a/settings.gradle b/settings.gradle index f069bcc2..f353fcc6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,8 +10,8 @@ include ':vtm-themes' include ':vtm-gdx' include ':vtm-desktop' include ':vtm-android-gdx' -//include ':vtm-web' -//include ':vtm-web-app' +include ':vtm-web' +include ':vtm-web-app' //include ':vtm-web-js' include ':vtm-jeo' include ':vtm-playground' diff --git a/vtm-web-app/build.gradle b/vtm-web-app/build.gradle index 783eeffd..eeb78160 100644 --- a/vtm-web-app/build.gradle +++ b/vtm-web-app/build.gradle @@ -5,7 +5,7 @@ buildscript { maven { url 'http://dl.bintray.com/steffenschaefer/maven' } } dependencies { - classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.5' + classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6' } } @@ -38,7 +38,7 @@ evaluationDependsOn(':vtm-gdx') evaluationDependsOn(':vtm-web') gwt { - gwtVersion = '2.6.1' + gwtVersion = project.ext.gwtVersion modules 'org.oscim.web.VtmWebApp' superDev { diff --git a/vtm-web-app/src/org/oscim/web/VtmWebApp.gwt.xml b/vtm-web-app/src/org/oscim/web/VtmWebApp.gwt.xml index 5b6c922d..6fb47b17 100644 --- a/vtm-web-app/src/org/oscim/web/VtmWebApp.gwt.xml +++ b/vtm-web-app/src/org/oscim/web/VtmWebApp.gwt.xml @@ -6,8 +6,6 @@ - - @@ -23,4 +21,5 @@ + diff --git a/vtm-web-app/src/org/oscim/web/client/GwtLauncher.java b/vtm-web-app/src/org/oscim/web/client/GwtLauncher.java index 3940dd88..e7987f2c 100644 --- a/vtm-web-app/src/org/oscim/web/client/GwtLauncher.java +++ b/vtm-web-app/src/org/oscim/web/client/GwtLauncher.java @@ -27,6 +27,8 @@ import org.oscim.gdx.client.MapConfig; public class GwtLauncher extends GwtApplication { + private ApplicationListener applicationListener; + @Override public GwtApplicationConfiguration getConfig() { @@ -36,7 +38,6 @@ public class GwtLauncher extends GwtApplication { cfg.canvasId = "map-canvas"; cfg.stencil = true; - cfg.fps = 120; return cfg; } @@ -45,6 +46,14 @@ public class GwtLauncher extends GwtApplication { public ApplicationListener getApplicationListener() { Tile.SIZE = MapConfig.get().getTileSize(); + if (applicationListener == null) { + applicationListener = createApplicationListener(); + } + return applicationListener; + } + + @Override + public ApplicationListener createApplicationListener() { return new GwtMap(); } diff --git a/vtm-web-app/src/org/oscim/web/client/GwtMap.java b/vtm-web-app/src/org/oscim/web/client/GwtMap.java index 0c52c878..bc1c3285 100644 --- a/vtm-web-app/src/org/oscim/web/client/GwtMap.java +++ b/vtm-web-app/src/org/oscim/web/client/GwtMap.java @@ -1,5 +1,6 @@ /* * Copyright 2013 Hannes Janetzek + * Copyright 2016 Izumi Kawashima * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -63,6 +64,7 @@ class GwtMap extends GdxMap { GdxAssets.init(""); CanvasAdapter.textScale = 0.7f; + log.debug("GLAdapter.init"); GLAdapter.init((GL) Gdx.graphics.getGL20()); GLAdapter.GDX_WEBGL_QUIRKS = true; MapRenderer.setBackgroundColor(0xffffff); @@ -92,12 +94,18 @@ class GwtMap extends GdxMap { ts = DefaultSources.STAMEN_TONER.build(); else if ("osm".equals(mapName)) ts = DefaultSources.OPENSTREETMAP.build(); + else if ("osm-transport".equals(mapName)) + ts = DefaultSources.OSM_TRANSPORT.build(); else if ("watercolor".equals(mapName)) ts = DefaultSources.STAMEN_WATERCOLOR.build(); - else if ("arcgis-shaded".equals(mapName)) - ts = DefaultSources.ARCGIS_RELIEF.build(); else if ("imagico".equals(mapName)) ts = DefaultSources.IMAGICO_LANDCOVER.build(); + else if ("ne-landcover".equals(mapName)) + ts = DefaultSources.NE_LANDCOVER.build(); + else if ("hikebike".equals(mapName)) + ts = DefaultSources.HIKEBIKE.build(); + else if ("hikebike-hillshade".equals(mapName)) + ts = DefaultSources.HIKEBIKE_HILLSHADE.build(); else ts = DefaultSources.STAMEN_TONER.build(); diff --git a/vtm-web-js/build.gradle b/vtm-web-js/build.gradle index 55dd0b58..899350a4 100644 --- a/vtm-web-js/build.gradle +++ b/vtm-web-js/build.gradle @@ -5,7 +5,7 @@ buildscript { maven { url 'http://dl.bintray.com/steffenschaefer/maven' } } dependencies { - classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.5' + classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6' } } @@ -39,7 +39,7 @@ evaluationDependsOn(':vtm-gdx') evaluationDependsOn(':vtm-web') gwt { - gwtVersion = '2.6.1' + gwtVersion = project.ext.gwtVersion modules 'org.oscim.web.VtmWebJs' superDev { diff --git a/vtm-web-js/src/org/oscim/web/VtmWebJs.gwt.xml b/vtm-web-js/src/org/oscim/web/VtmWebJs.gwt.xml index cf963562..7fef4444 100644 --- a/vtm-web-js/src/org/oscim/web/VtmWebJs.gwt.xml +++ b/vtm-web-js/src/org/oscim/web/VtmWebJs.gwt.xml @@ -10,8 +10,6 @@ - - @@ -25,4 +23,8 @@ + + + + diff --git a/vtm-web-js/src/org/oscim/web/client/GwtLauncher.java b/vtm-web-js/src/org/oscim/web/client/GwtLauncher.java index f7b32548..427cb2e9 100644 --- a/vtm-web-js/src/org/oscim/web/client/GwtLauncher.java +++ b/vtm-web-js/src/org/oscim/web/client/GwtLauncher.java @@ -28,6 +28,8 @@ import org.timepedia.exporter.client.ExporterUtil; public class GwtLauncher extends GwtApplication { + private ApplicationListener applicationListener; + @Override public void onModuleLoad() { //GWT.create(GwtGdxMap.class); @@ -46,7 +48,6 @@ public class GwtLauncher extends GwtApplication { cfg.canvasId = "map-canvas"; cfg.stencil = true; - cfg.fps = 120; return cfg; } @@ -55,6 +56,14 @@ public class GwtLauncher extends GwtApplication { public ApplicationListener getApplicationListener() { Tile.SIZE = MapConfig.get().getTileSize(); + if (applicationListener == null) { + applicationListener = createApplicationListener(); + } + return applicationListener; + } + + @Override + public ApplicationListener createApplicationListener() { return new GwtMap(); } diff --git a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtApplication.java b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtApplication.java index 56b5ef4a..3a711f8f 100644 --- a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtApplication.java +++ b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtApplication.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2011 See libgdx AUTHORS file. - *

+ * Copyright 2011 See AUTHORS file. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -29,37 +29,44 @@ import com.badlogic.gdx.Preferences; import com.badlogic.gdx.backends.gwt.preloader.Preloader; import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderCallback; import com.badlogic.gdx.backends.gwt.preloader.Preloader.PreloaderState; -import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Clipboard; -import com.badlogic.gdx.utils.GdxRuntimeException; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.TimeUtils; +import com.google.gwt.animation.client.AnimationScheduler; +import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; -import com.google.gwt.user.client.Timer; +import com.google.gwt.dom.client.CanvasElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.ui.HasHorizontalAlignment; +import com.google.gwt.user.client.ui.HasVerticalAlignment; +import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.InlineHTML; +import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.TextArea; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation of an {@link Application} based on GWT. Clients have to - * override {@link #getConfig()} and {@link #getApplicationListener()}. Clients - * can override the default loading screen via {@link #getPreloaderCallback()} - * and implement any loading screen drawing via GWT widgets. - * - * @author mzechner - */ +/** Implementation of an {@link Application} based on GWT. Clients have to override {@link #getConfig()} and + * {@link #createApplicationListener()}. Clients can override the default loading screen via + * {@link #getPreloaderCallback()} and implement any loading screen drawing via GWT widgets. + * @author mzechner */ public abstract class GwtApplication implements EntryPoint, Application { - private final static Logger log = LoggerFactory.getLogger(GwtApplication.class); - private ApplicationListener listener; - private GwtApplicationConfiguration config; - private GwtGraphics graphics; + GwtApplicationConfiguration config; + GwtGraphics graphics; private GwtInput input; private GwtNet net; + private Panel root = null; + private TextArea log = null; private int logLevel = LOG_ERROR; private Array runnables = new Array(); private Array runnablesHelper = new Array(); @@ -69,55 +76,104 @@ public abstract class GwtApplication implements EntryPoint, Application { Preloader preloader; private static AgentInfo agentInfo; private ObjectMap prefs = new ObjectMap(); + private Clipboard clipboard; + LoadingListener loadingListener; - /** - * @return the configuration for the {@link GwtApplication}. - */ - public abstract GwtApplicationConfiguration getConfig(); + /** @return the configuration for the {@link GwtApplication}. */ + public abstract GwtApplicationConfiguration getConfig (); - public String getPreloaderBaseURL() { + + public String getPreloaderBaseURL() + { return GWT.getHostPageBaseURL() + "assets/"; } @Override - public void onModuleLoad() { + public ApplicationListener getApplicationListener() { + return listener; + } + + public abstract ApplicationListener createApplicationListener(); + + @Override + public void onModuleLoad () { GwtApplication.agentInfo = computeAgentInfo(); - this.listener = getApplicationListener(); + this.listener = createApplicationListener(); this.config = getConfig(); + this.log = config.log; + + addEventListeners(); + + if (config.rootPanel != null) { + this.root = config.rootPanel; + } else { + Element element = Document.get().getElementById("embed-" + GWT.getModuleName()); + if (element == null) { + VerticalPanel panel = new VerticalPanel(); + panel.setWidth("" + config.width + "px"); + panel.setHeight("" + config.height + "px"); + panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); + panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); + RootPanel.get().add(panel); + RootPanel.get().setWidth("" + config.width + "px"); + RootPanel.get().setHeight("" + config.height + "px"); + this.root = panel; + } else { + VerticalPanel panel = new VerticalPanel(); + panel.setWidth("" + config.width + "px"); + panel.setHeight("" + config.height + "px"); + panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); + panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); + element.appendChild(panel.getElement()); + root = panel; + } + } final PreloaderCallback callback = getPreloaderCallback(); preloader = createPreloader(); preloader.preload("assets.txt", new PreloaderCallback() { @Override - public void error(String file) { + public void error (String file) { callback.error(file); } @Override - public void update(PreloaderState state) { + public void update (PreloaderState state) { callback.update(state); if (state.hasEnded()) { - //getRootPanel().clear(); + getRootPanel().clear(); + if(loadingListener != null) + loadingListener.beforeSetup(); setupLoop(); + if(loadingListener != null) + loadingListener.afterSetup(); } } }); } - void setupLoop() { - Gdx.app = this; + /** + * Override this method to return a custom widget informing the that their browser lacks support of WebGL. + * + * @return Widget to display when WebGL is not supported. + */ + public Widget getNoWebGLSupportWidget() { + return new Label("Sorry, your browser doesn't seem to support WebGL"); + } + + void setupLoop () { // setup modules try { - graphics = new GwtGraphics(null, config); + graphics = new GwtGraphics(root, config); } catch (Throwable e) { - error("GwtApplication", "exception: " + e.getMessage(), e); - //root.clear(); - //root.add(new Label("Sorry, your browser doesn't seem to support WebGL")); + root.clear(); + root.add(getNoWebGLSupportWidget()); return; } lastWidth = graphics.getWidth(); lastHeight = graphics.getHeight(); Gdx.app = this; + Gdx.audio = new GwtAudio(); Gdx.graphics = graphics; Gdx.gl20 = graphics.getGL20(); Gdx.gl = Gdx.gl20; @@ -126,6 +182,8 @@ public abstract class GwtApplication implements EntryPoint, Application { Gdx.input = this.input; this.net = new GwtNet(); Gdx.net = this.net; + this.clipboard = new GwtClipboard(); + updateLogLabelSize(); // tell listener about app creation try { @@ -137,26 +195,21 @@ public abstract class GwtApplication implements EntryPoint, Application { throw new RuntimeException(t); } - Gdx.gl.glClearColor(1, 1, 1, 1); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - final int frameTime = (int) ((1f / config.fps) * 1000); - - // setup rendering timer - new Timer() { + AnimationScheduler.get().requestAnimationFrame(new AnimationCallback() { @Override - public void run() { + public void execute (double timestamp) { try { - mainLoop(this, frameTime); + mainLoop(); } catch (Throwable t) { error("GwtApplication", "exception: " + t.getMessage(), t); throw new RuntimeException(t); } + AnimationScheduler.get().requestAnimationFrame(this, graphics.canvas); } - }.schedule(1); + }, graphics.canvas); } - void mainLoop(Timer timer, int frameTime) { + void mainLoop() { graphics.update(); if (Gdx.graphics.getWidth() != lastWidth || Gdx.graphics.getHeight() != lastHeight) { GwtApplication.this.listener.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); @@ -170,17 +223,13 @@ public abstract class GwtApplication implements EntryPoint, Application { runnablesHelper.get(i).run(); } runnablesHelper.clear(); + graphics.frameId++; listener.render(); - input.justTouched = false; - - long now = System.currentTimeMillis(); - int diff = (int) (now - graphics.lastTimeStamp); - diff = frameTime - diff; - timer.schedule(diff > 5 ? diff : 5); + input.reset(); } - public Panel getRootPanel() { - throw new GdxRuntimeException("no panel!"); + public Panel getRootPanel () { + return root; } long loadStart = TimeUtils.nanoTime(); @@ -189,27 +238,53 @@ public abstract class GwtApplication implements EntryPoint, Application { return new Preloader(getPreloaderBaseURL()); } - public PreloaderCallback getPreloaderCallback() { - return null; + public PreloaderCallback getPreloaderCallback () { + final Panel preloaderPanel = new VerticalPanel(); + preloaderPanel.setStyleName("gdx-preloader"); + final Image logo = new Image(GWT.getModuleBaseURL() + "logo.png"); + logo.setStyleName("logo"); + preloaderPanel.add(logo); + final Panel meterPanel = new SimplePanel(); + meterPanel.setStyleName("gdx-meter"); + meterPanel.addStyleName("red"); + final InlineHTML meter = new InlineHTML(); + final Style meterStyle = meter.getElement().getStyle(); + meterStyle.setWidth(0, Unit.PCT); + meterPanel.add(meter); + preloaderPanel.add(meterPanel); + getRootPanel().add(preloaderPanel); + return new PreloaderCallback() { + + @Override + public void error (String file) { + System.out.println("error: " + file); + } + + @Override + public void update (PreloaderState state) { + meterStyle.setWidth(100f * state.getProgress(), Unit.PCT); + } + + }; } @Override - public Graphics getGraphics() { + public Graphics getGraphics () { return graphics; } @Override - public Audio getAudio() { + public Audio getAudio () { return Gdx.audio; } @Override - public Input getInput() { + public Input getInput () { return Gdx.input; } @Override - public Files getFiles() { + public Files getFiles () { return Gdx.files; } @@ -218,37 +293,107 @@ public abstract class GwtApplication implements EntryPoint, Application { return Gdx.net; } - @Override - public void log(String tag, String message) { - log.info("{} : {}", tag, message); + private void updateLogLabelSize () { + if (log != null) { + if (graphics != null) { + log.setSize(graphics.getWidth() + "px", "200px"); + } else { + log.setSize("400px", "200px"); // Should not happen at this point, use dummy value + } + } + } + + private void checkLogLabel () { + if (log == null) { + log = new TextArea(); + + // It's possible that log functions are called + // before the app is initialized. E.g. SoundManager can call log functions before the app is initialized. + // Since graphics is null, we're getting errors. The log size will be updated later, in case graphics was null + if (graphics != null) { + log.setSize(graphics.getWidth() + "px", "200px"); + } else { + log.setSize("400px", "200px"); // Dummy value + } + + log.setReadOnly(true); + root.add(log); + } } @Override - public void log(String tag, String message, Throwable exception) { - log.info("{} : {}\n{}", tag, exception, getStackTrace(exception)); + public void log (String tag, String message) { + if (logLevel >= LOG_INFO) { + checkLogLabel(); + log.setText(log.getText() + "\n" + tag + ": " + message); + log.setCursorPos(log.getText().length() - 1); + System.out.println(tag + ": " + message); + } } @Override - public void error(String tag, String message) { - log.error("{} : {}", tag, message); + public void log (String tag, String message, Throwable exception) { + if (logLevel >= LOG_INFO) { + checkLogLabel(); + log.setText(log.getText() + "\n" + tag + ": " + message + "\n" + getMessages(exception) + "\n"); + log.setCursorPos(log.getText().length() - 1); + System.out.println(tag + ": " + message + "\n" + exception.getMessage()); + System.out.println(getStackTrace(exception)); + } } @Override - public void error(String tag, String message, Throwable exception) { - log.error("{} : {}\n{}", tag, message, getStackTrace(exception)); + public void error (String tag, String message) { + if (logLevel >= LOG_ERROR) { + checkLogLabel(); + log.setText(log.getText() + "\n" + tag + ": " + message + "\n"); + log.setCursorPos(log.getText().length() - 1); + System.err.println(tag + ": " + message); + } } @Override - public void debug(String tag, String message) { - log.debug("{} : {}", tag, message); + public void error (String tag, String message, Throwable exception) { + if (logLevel >= LOG_ERROR) { + checkLogLabel(); + log.setText(log.getText() + "\n" + tag + ": " + message + "\n" + getMessages(exception) + "\n"); + log.setCursorPos(log.getText().length() - 1); + System.err.println(tag + ": " + message + "\n" + exception.getMessage() + "\n"); + System.out.println(getStackTrace(exception)); + } } @Override - public void debug(String tag, String message, Throwable exception) { - log.debug("{} : {}\n{}", tag, message, getStackTrace(exception)); + public void debug (String tag, String message) { + if (logLevel >= LOG_DEBUG) { + checkLogLabel(); + log.setText(log.getText() + "\n" + tag + ": " + message + "\n"); + log.setCursorPos(log.getText().length() - 1); + System.out.println(tag + ": " + message + "\n"); + } } - private String getStackTrace(Throwable e) { + @Override + public void debug (String tag, String message, Throwable exception) { + if (logLevel >= LOG_DEBUG) { + checkLogLabel(); + log.setText(log.getText() + "\n" + tag + ": " + message + "\n" + getMessages(exception) + "\n"); + log.setCursorPos(log.getText().length() - 1); + System.out.println(tag + ": " + message + "\n" + exception.getMessage()); + System.out.println(getStackTrace(exception)); + } + } + + private String getMessages (Throwable e) { + StringBuffer buffer = new StringBuffer(); + while (e != null) { + buffer.append(e.getMessage() + "\n"); + e = e.getCause(); + } + return buffer.toString(); + } + + private String getStackTrace (Throwable e) { StringBuffer buffer = new StringBuffer(); for (StackTraceElement trace : e.getStackTrace()) { buffer.append(trace.toString() + "\n"); @@ -257,36 +402,37 @@ public abstract class GwtApplication implements EntryPoint, Application { } @Override - public void setLogLevel(int logLevel) { + public void setLogLevel (int logLevel) { + this.logLevel = logLevel; } @Override public int getLogLevel() { - return LOG_DEBUG; + return logLevel; } @Override - public ApplicationType getType() { + public ApplicationType getType () { return ApplicationType.WebGL; } @Override - public int getVersion() { + public int getVersion () { return 0; } @Override - public long getJavaHeap() { + public long getJavaHeap () { return 0; } @Override - public long getNativeHeap() { + public long getNativeHeap () { return 0; } @Override - public Preferences getPreferences(String name) { + public Preferences getPreferences (String name) { Preferences pref = prefs.get(name); if (pref == null) { pref = new GwtPreferences(name); @@ -296,115 +442,151 @@ public abstract class GwtApplication implements EntryPoint, Application { } @Override - public Clipboard getClipboard() { - return new Clipboard() { - @Override - public String getContents() { - return null; - } - - @Override - public void setContents(String content) { - } - }; + public Clipboard getClipboard () { + return clipboard; } @Override - public void postRunnable(Runnable runnable) { + public void postRunnable (Runnable runnable) { runnables.add(runnable); } @Override - public void exit() { + public void exit () { } - /** - * Contains precomputed information on the user-agent. Useful for dealing - * with browser and OS behavioral differences. Kindly - * borrowed from PlayN - */ - public static AgentInfo agentInfo() { + /** Contains precomputed information on the user-agent. Useful for dealing with browser and OS behavioral differences. Kindly + * borrowed from PlayN */ + public static AgentInfo agentInfo () { return agentInfo; } - /** - * kindly borrowed from PlayN - **/ - private static native AgentInfo computeAgentInfo() /*-{ - var userAgent = navigator.userAgent.toLowerCase(); - return { - // browser type flags - isFirefox : userAgent.indexOf("firefox") != -1, - isChrome : userAgent.indexOf("chrome") != -1, - isSafari : userAgent.indexOf("safari") != -1, - isOpera : userAgent.indexOf("opera") != -1, - isIE : userAgent.indexOf("msie") != -1, - // OS type flags - isMacOS : userAgent.indexOf("mac") != -1, - isLinux : userAgent.indexOf("linux") != -1, - isWindows : userAgent.indexOf("win") != -1 - }; - }-*/; + /** kindly borrowed from PlayN **/ + private static native AgentInfo computeAgentInfo () /*-{ + var userAgent = navigator.userAgent.toLowerCase(); + return { + // browser type flags + isFirefox : userAgent.indexOf("firefox") != -1, + isChrome : userAgent.indexOf("chrome") != -1, + isSafari : userAgent.indexOf("safari") != -1, + isOpera : userAgent.indexOf("opera") != -1, + isIE : userAgent.indexOf("msie") != -1, + // OS type flags + isMacOS : userAgent.indexOf("mac") != -1, + isLinux : userAgent.indexOf("linux") != -1, + isWindows : userAgent.indexOf("win") != -1 + }; + }-*/; - /** - * Returned by {@link #agentInfo}. Kindly borrowed from PlayN. - */ + /** Returned by {@link #agentInfo}. Kindly borrowed from PlayN. */ public static class AgentInfo extends JavaScriptObject { - public final native boolean isFirefox() /*-{ - return this.isFirefox; - }-*/; + public final native boolean isFirefox () /*-{ + return this.isFirefox; + }-*/; - public final native boolean isChrome() /*-{ - return this.isChrome; - }-*/; + public final native boolean isChrome () /*-{ + return this.isChrome; + }-*/; - public final native boolean isSafari() /*-{ - return this.isSafari; - }-*/; + public final native boolean isSafari () /*-{ + return this.isSafari; + }-*/; - public final native boolean isOpera() /*-{ - return this.isOpera; - }-*/; + public final native boolean isOpera () /*-{ + return this.isOpera; + }-*/; - public final native boolean isIE() /*-{ - return this.isIE; - }-*/; + public final native boolean isIE () /*-{ + return this.isIE; + }-*/; - public final native boolean isMacOS() /*-{ - return this.isMacOS; - }-*/; + public final native boolean isMacOS () /*-{ + return this.isMacOS; + }-*/; - public final native boolean isLinux() /*-{ - return this.isLinux; - }-*/; + public final native boolean isLinux () /*-{ + return this.isLinux; + }-*/; - public final native boolean isWindows() /*-{ - return this.isWindows; - }-*/; + public final native boolean isWindows () /*-{ + return this.isWindows; + }-*/; - protected AgentInfo() { + protected AgentInfo () { } } - public String getBaseUrl() { + public String getBaseUrl () { return preloader.baseUrl; } - public Preloader getPreloader() { + public Preloader getPreloader () { return preloader; } + public CanvasElement getCanvasElement(){ + return graphics.canvas; + } + + public LoadingListener getLoadingListener () { + return loadingListener; + } + + public void setLoadingListener (LoadingListener loadingListener) { + this.loadingListener = loadingListener; + } + @Override - public void addLifecycleListener(LifecycleListener listener) { - synchronized (lifecycleListeners) { + public void addLifecycleListener (LifecycleListener listener) { + synchronized(lifecycleListeners) { lifecycleListeners.add(listener); } } @Override - public void removeLifecycleListener(LifecycleListener listener) { - synchronized (lifecycleListeners) { + public void removeLifecycleListener (LifecycleListener listener) { + synchronized(lifecycleListeners) { lifecycleListeners.removeValue(listener, true); } } + + native static public void consoleLog(String message) /*-{ + console.log( "GWT: " + message ); + }-*/; + + private native void addEventListeners () /*-{ + var self = this; + $doc.addEventListener('visibilitychange', function (e) { + self.@com.badlogic.gdx.backends.gwt.GwtApplication::onVisibilityChange(Z)($doc['hidden'] !== true); + }); + }-*/; + + private void onVisibilityChange (boolean visible) { + if (visible) { + for (LifecycleListener listener : lifecycleListeners) { + listener.resume(); + } + listener.resume(); + } else { + for (LifecycleListener listener : lifecycleListeners) { + listener.pause(); + } + listener.pause(); + } + } + + /** + * LoadingListener interface main purpose is to do some things before or after {@link GwtApplication#setupLoop()} + */ + public interface LoadingListener{ + /** + * Method called before the setup + */ + public void beforeSetup(); + + /** + * Method called after the setup + */ + public void afterSetup(); + } } diff --git a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtGraphics.java b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtGraphics.java index c62dd37c..429ffa29 100644 --- a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtGraphics.java +++ b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtGraphics.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2011 See libgdx AUTHORS file. - *

+ * Copyright 2011 See AUTHORS file. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,15 +16,20 @@ package com.badlogic.gdx.backends.gwt; +import com.badlogic.gdx.Application; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Graphics; +import com.badlogic.gdx.graphics.Cursor; +import com.badlogic.gdx.graphics.Cursor.SystemCursor; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL30; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.glutils.GLVersion; import com.badlogic.gdx.utils.GdxRuntimeException; import com.google.gwt.canvas.client.Canvas; import com.google.gwt.dom.client.CanvasElement; import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.dom.client.Style; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.webgl.client.WebGLContextAttributes; import com.google.gwt.webgl.client.WebGLRenderingContext; @@ -36,20 +41,39 @@ import org.slf4j.LoggerFactory; public class GwtGraphics implements Graphics { static final Logger log = LoggerFactory.getLogger(GwtGraphics.class); + /* Enum values from http://www.w3.org/TR/screen-orientation. Filtered based on what the browsers actually support. */ + public enum OrientationLockType { + LANDSCAPE("landscape"), PORTRAIT("portrait"), PORTRAIT_PRIMARY("portrait-primary"), PORTRAIT_SECONDARY( + "portrait-secondary"), LANDSCAPE_PRIMARY("landscape-primary"), LANDSCAPE_SECONDARY("landscape-secondary"); + + private final String name; + + private OrientationLockType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + ; + CanvasElement canvas; WebGLRenderingContext context; + GLVersion glVersion; GL20 gl; String extensions; float fps = 0; long lastTimeStamp = System.currentTimeMillis(); + long frameId = -1; float deltaTime = 0; float time = 0; int frames; GwtApplicationConfiguration config; - boolean inFullscreenMode = false; double pixelRatio; - public GwtGraphics(Panel root, final GwtApplicationConfiguration config) { + public GwtGraphics(Panel root, GwtApplicationConfiguration config) { this.pixelRatio = getDevicePixelRatioJSNI(); if (config.canvasId == null) { @@ -64,10 +88,9 @@ public class GwtGraphics implements Graphics { canvas.setWidth((int) (config.width * pixelRatio)); canvas.setHeight((int) (config.height * pixelRatio)); - canvas.getStyle().setWidth(config.width, Unit.PX); - canvas.getStyle().setHeight(config.height, Unit.PX); + canvas.getStyle().setWidth(config.width, Style.Unit.PX); + canvas.getStyle().setHeight(config.height, Style.Unit.PX); } - this.config = config; WebGLContextAttributes attributes = WebGLContextAttributes.create(); @@ -75,11 +98,11 @@ public class GwtGraphics implements Graphics { attributes.setStencil(config.stencil); attributes.setAlpha(false); attributes.setPremultipliedAlpha(false); + attributes.setPreserveDrawingBuffer(false); context = WebGLRenderingContext.getContext(canvas, attributes); if (context == null) throw new GdxRuntimeException("Could not create Canvas for " + attributes); - context.viewport(0, 0, config.width, config.height); // this actually *enables* the option to use std derivatives in shader.. @@ -92,6 +115,11 @@ public class GwtGraphics implements Graphics { } this.gl = config.useDebugGL ? new GwtGL20Debug(context) : new GdxGL(context); + + String versionString = gl.glGetString(GL20.GL_VERSION); + String vendorString = gl.glGetString(GL20.GL_VENDOR); + String rendererString = gl.glGetString(GL20.GL_RENDERER); + glVersion = new GLVersion(Application.ApplicationType.WebGL, versionString, vendorString, rendererString); } public static native double getDevicePixelRatioJSNI() /*-{ @@ -125,6 +153,21 @@ public class GwtGraphics implements Graphics { return canvas.getHeight(); } + @Override + public int getBackBufferWidth() { + return canvas.getWidth(); + } + + @Override + public int getBackBufferHeight() { + return canvas.getHeight(); + } + + @Override + public long getFrameId() { + return frameId; + } + @Override public float getDeltaTime() { return deltaTime; @@ -140,6 +183,11 @@ public class GwtGraphics implements Graphics { return GraphicsType.WebGL; } + @Override + public GLVersion getGLVersion() { + return glVersion; + } + @Override public float getPpiX() { return 96; @@ -162,13 +210,28 @@ public class GwtGraphics implements Graphics { @Override public boolean supportsDisplayModeChange() { - return true; + return supportsFullscreenJSNI(); } + private native boolean supportsFullscreenJSNI() /*-{ + if ("fullscreenEnabled" in $doc) { + return $doc.fullscreenEnabled; + } + if ("webkitFullscreenEnabled" in $doc) { + return $doc.webkitFullscreenEnabled; + } + if ("mozFullScreenEnabled" in $doc) { + return $doc.mozFullScreenEnabled; + } + if ("msFullscreenEnabled" in $doc) { + return $doc.msFullscreenEnabled; + } + return false; + }-*/; + @Override public DisplayMode[] getDisplayModes() { - return new DisplayMode[]{new DisplayMode(getScreenWidthJSNI(), getScreenHeightJSNI(), 60, - 8) { + return new DisplayMode[]{new DisplayMode(getScreenWidthJSNI(), getScreenHeightJSNI(), 60, 8) { }}; } @@ -181,6 +244,21 @@ public class GwtGraphics implements Graphics { }-*/; private native boolean isFullscreenJSNI() /*-{ + // Standards compliant check for fullscreen + if ("fullscreenElement" in $doc) { + return $doc.fullscreenElement != null; + } + // Vendor prefixed versions of standard check + if ("msFullscreenElement" in $doc) { + return $doc.msFullscreenElement != null; + } + if ("webkitFullscreenElement" in $doc) { + return $doc.webkitFullscreenElement != null; + } + if ("mozFullScreenElement" in $doc) { // Yes, with a capital 'S' + return $doc.mozFullScreenElement != null; + } + // Older, non-standard ways of checking for fullscreen if ("webkitIsFullScreen" in $doc) { return $doc.webkitIsFullScreen; } @@ -194,10 +272,28 @@ public class GwtGraphics implements Graphics { if (!isFullscreen()) { canvas.setWidth(config.width); canvas.setHeight(config.height); + if (config.fullscreenOrientation != null) unlockOrientation(); + } else { + /* We just managed to go full-screen. Check if the user has requested a specific orientation. */ + if (config.fullscreenOrientation != null) lockOrientation(config.fullscreenOrientation); } } private native boolean setFullscreenJSNI(GwtGraphics graphics, CanvasElement element) /*-{ + // Attempt to use the non-prefixed standard API (https://fullscreen.spec.whatwg.org) + if (element.requestFullscreen) { + element.width = $wnd.screen.width; + element.height = $wnd.screen.height; + element.requestFullscreen(); + $doc + .addEventListener( + "fullscreenchange", + function() { + graphics.@com.badlogic.gdx.backends.gwt.GwtGraphics::fullscreenChanged()(); + }, false); + return true; + } + // Attempt to the vendor specific variants of the API if (element.webkitRequestFullScreen) { element.width = $wnd.screen.width; element.height = $wnd.screen.height; @@ -222,46 +318,140 @@ public class GwtGraphics implements Graphics { }, false); return true; } + if (element.msRequestFullscreen) { + element.width = $wnd.screen.width; + element.height = $wnd.screen.height; + element.msRequestFullscreen(); + $doc + .addEventListener( + "msfullscreenchange", + function() { + graphics.@com.badlogic.gdx.backends.gwt.GwtGraphics::fullscreenChanged()(); + }, false); + return true; + } + return false; }-*/; private native void exitFullscreen() /*-{ + if ($doc.exitFullscreen) + $doc.exitFullscreen(); + if ($doc.msExitFullscreen) + $doc.msExitFullscreen(); if ($doc.webkitExitFullscreen) $doc.webkitExitFullscreen(); if ($doc.mozExitFullscreen) $doc.mozExitFullscreen(); + if ($doc.webkitCancelFullScreen) // Old WebKit + $doc.webkitCancelFullScreen(); }-*/; @Override - public DisplayMode getDesktopDisplayMode() { + public DisplayMode getDisplayMode() { return new DisplayMode(getScreenWidthJSNI(), getScreenHeightJSNI(), 60, 8) { }; } @Override - public boolean setDisplayMode(DisplayMode displayMode) { - if (displayMode.width != getScreenWidthJSNI() - && displayMode.height != getScreenHeightJSNI()) + public boolean setFullscreenMode(DisplayMode displayMode) { + if (displayMode.width != getScreenWidthJSNI() && displayMode.height != getScreenHeightJSNI()) return false; return setFullscreenJSNI(this, canvas); } @Override - public boolean setDisplayMode(int width, int height, boolean fullscreen) { - if (fullscreen) { - if (width != getScreenWidthJSNI() && height != getScreenHeightJSNI()) - return false; - return setFullscreenJSNI(this, canvas); - } else { - if (isFullscreenJSNI()) - exitFullscreen(); - canvas.setWidth(width); - canvas.setHeight(height); - canvas.getStyle().setWidth(width, Unit.PX); - canvas.getStyle().setHeight(height, Unit.PX); + public boolean setWindowedMode(int width, int height) { + if (isFullscreenJSNI()) exitFullscreen(); + canvas.setWidth(width); + canvas.setHeight(height); + return true; + } + + + @Override + public Monitor getPrimaryMonitor() { + return new GwtMonitor(0, 0, "Primary Monitor"); + } + + @Override + public Monitor getMonitor() { + return getPrimaryMonitor(); + } + + @Override + public Monitor[] getMonitors() { + return new Monitor[]{getPrimaryMonitor()}; + } + + @Override + public DisplayMode[] getDisplayModes(Monitor monitor) { + return getDisplayModes(); + } + + @Override + public DisplayMode getDisplayMode(Monitor monitor) { + return getDisplayMode(); + } + + /** + * Attempt to lock the orientation. Typically only supported when in full-screen mode. + * + * @param orientation the orientation to attempt locking + * @return did the locking succeed + */ + public boolean lockOrientation(OrientationLockType orientation) { + return lockOrientationJSNI(orientation.getName()); + } + + /** + * Attempt to unlock the orientation. + * + * @return did the unlocking succeed + */ + public boolean unlockOrientation() { + return unlockOrientationJSNI(); + } + + private native boolean lockOrientationJSNI(String orientationEnumValue) /*-{ + var screen = $wnd.screen; + + // Attempt to find the lockOrientation function + screen.gdxLockOrientation = screen.lockOrientation + || screen.mozLockOrientation || screen.msLockOrientation + || screen.webkitLockOrientation; + + if (screen.gdxLockOrientation) { + return screen.gdxLockOrientation(orientationEnumValue); + } + // Actually, the Chrome guys do things a little different for now + else if (screen.orientation && screen.orientation.lock) { + screen.orientation.lock(orientationEnumValue); + // The Chrome API is async, so we can't at this point tell if we succeeded return true; } - } + return false; + }-*/; + + private native boolean unlockOrientationJSNI() /*-{ + var screen = $wnd.screen; + + // Attempt to find the lockOrientation function + screen.gdxUnlockOrientation = screen.unlockOrientation + || screen.mozUnlockOrientation || screen.msUnlockOrientation + || screen.webkitUnlockOrientation; + + if (screen.gdxUnlockOrientation) { + return screen.gdxUnlockOrientation(); + } + // Actually, the Chrome guys do things a little different for now + else if (screen.orientation && screen.orientation.unlock) { + screen.orientation.unlock(); + // The Chrome API is async, so we can't at this point tell if we succeeded + return true; + } + return false; + }-*/; @Override public BufferFormat getBufferFormat() { @@ -269,10 +459,12 @@ public class GwtGraphics implements Graphics { } @Override - public boolean supportsExtension(String extension) { - if (extensions == null) - extensions = Gdx.gl.glGetString(GL20.GL_EXTENSIONS); - return extensions.contains(extension); + public boolean supportsExtension(String extensionName) { + // Contrary to regular OpenGL, WebGL extensions need to be explicitly enabled before they can be used. See + // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Using_Extensions + // Thus, it is not safe to use an extension just because context.getSupportedExtensions() tells you it is available. + // We need to call getExtension() to enable it. + return context.getExtension(extensionName) != null; } public void update() { @@ -292,6 +484,14 @@ public class GwtGraphics implements Graphics { public void setTitle(String title) { } + @Override + public void setUndecorated(boolean undecorated) { + } + + @Override + public void setResizable(boolean resizable) { + } + @Override public void setVSync(boolean vsync) { } @@ -335,8 +535,23 @@ public class GwtGraphics implements Graphics { } @Override - public long getFrameId() { - // TODO Auto-generated method stub - return 0; + public Cursor newCursor(Pixmap pixmap, int xHotspot, int yHotspot) { + return new GwtCursor(pixmap, xHotspot, yHotspot); + } + + @Override + public void setCursor(Cursor cursor) { + ((GwtApplication) Gdx.app).graphics.canvas.getStyle().setProperty("cursor", ((GwtCursor) cursor).cssCursorProperty); + } + + @Override + public void setSystemCursor(SystemCursor systemCursor) { + ((GwtApplication) Gdx.app).graphics.canvas.getStyle().setProperty("cursor", GwtCursor.getNameForSystemCursor(systemCursor)); + } + + static class GwtMonitor extends Monitor { + protected GwtMonitor(int virtualX, int virtualY, String name) { + super(virtualX, virtualY, name); + } } } diff --git a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtInput.java b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtInput.java index a5e7d110..15015515 100644 --- a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtInput.java +++ b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/backends/gwt/GwtInput.java @@ -1,12 +1,12 @@ /******************************************************************************* * Copyright 2011 See AUTHORS file. - *

+ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,28 +21,30 @@ import com.badlogic.gdx.Input; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.backends.gwt.widgets.TextInputDialogBox; import com.badlogic.gdx.backends.gwt.widgets.TextInputDialogBox.TextInputDialogListener; -import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.utils.IntMap; +import com.badlogic.gdx.utils.IntSet; import com.badlogic.gdx.utils.TimeUtils; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.dom.client.CanvasElement; -import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Touch; import com.google.gwt.event.dom.client.KeyCodes; -import java.util.HashSet; -import java.util.Set; - public class GwtInput implements Input { + static final int MAX_TOUCHES = 20; boolean justTouched = false; - private boolean[] touched = new boolean[20]; - private int[] touchX = new int[20]; - private int[] touchY = new int[20]; - private int[] deltaX = new int[20]; - private int[] deltaY = new int[20]; - Set pressedButtons = new HashSet(); - Set pressedKeys = new HashSet(); + private IntMap touchMap = new IntMap(20); + private boolean[] touched = new boolean[MAX_TOUCHES]; + private int[] touchX = new int[MAX_TOUCHES]; + private int[] touchY = new int[MAX_TOUCHES]; + private int[] deltaX = new int[MAX_TOUCHES]; + private int[] deltaY = new int[MAX_TOUCHES]; + IntSet pressedButtons = new IntSet(); + int pressedKeyCount = 0; + boolean[] pressedKeys = new boolean[256]; + boolean keyJustPressed = false; + boolean[] justPressedKeys = new boolean[256]; InputProcessor processor; char lastKeyCharPressed; float keyRepeatTimer; @@ -50,107 +52,154 @@ public class GwtInput implements Input { final CanvasElement canvas; boolean hasFocus = true; - public GwtInput(CanvasElement canvas) { + public GwtInput (CanvasElement canvas) { this.canvas = canvas; hookEvents(); } + void reset () { + justTouched = false; + if (keyJustPressed) { + keyJustPressed = false; + for (int i = 0; i < justPressedKeys.length; i++) { + justPressedKeys[i] = false; + } + } + } + @Override - public float getAccelerometerX() { + public float getAccelerometerX () { return 0; } @Override - public float getAccelerometerY() { + public float getAccelerometerY () { return 0; } @Override - public float getAccelerometerZ() { + public float getAccelerometerZ () { return 0; } @Override - public int getX() { + public float getGyroscopeX () { + // TODO Auto-generated method stub + return 0; + } + + @Override + public float getGyroscopeY () { + // TODO Auto-generated method stub + return 0; + } + + @Override + public float getGyroscopeZ () { + // TODO Auto-generated method stub + return 0; + } + + @Override + public int getX () { return touchX[0]; } @Override - public int getX(int pointer) { + public int getX (int pointer) { return touchX[pointer]; } @Override - public int getDeltaX() { + public int getDeltaX () { return deltaX[0]; } @Override - public int getDeltaX(int pointer) { + public int getDeltaX (int pointer) { return deltaX[pointer]; } @Override - public int getY() { + public int getY () { return touchY[0]; } @Override - public int getY(int pointer) { + public int getY (int pointer) { return touchY[pointer]; } @Override - public int getDeltaY() { + public int getDeltaY () { return deltaY[0]; } @Override - public int getDeltaY(int pointer) { + public int getDeltaY (int pointer) { return deltaY[pointer]; } @Override - public boolean isTouched() { - return touched[0]; + public boolean isTouched () { + for (int pointer = 0; pointer < MAX_TOUCHES; pointer++) { + if (touched[pointer]) { + return true; + } + } + return false; } @Override - public boolean justTouched() { + public boolean justTouched () { return justTouched; } @Override - public boolean isTouched(int pointer) { + public boolean isTouched (int pointer) { return touched[pointer]; } @Override - public boolean isButtonPressed(int button) { - return button == Buttons.LEFT && touched[0]; + public boolean isButtonPressed (int button) { + return pressedButtons.contains(button) && touched[0]; } @Override - public boolean isKeyPressed(int key) { - if (key == Keys.ANY_KEY) - return pressedKeys.size() > 0; - return pressedKeys.contains(key); + public boolean isKeyPressed (int key) { + if (key == Keys.ANY_KEY) { + return pressedKeyCount > 0; + } + if (key < 0 || key > 255) { + return false; + } + return pressedKeys[key]; } @Override - public void getTextInput(TextInputListener listener, String title, String text) { - TextInputDialogBox dialog = new TextInputDialogBox(title, text, null); + public boolean isKeyJustPressed (int key) { + if (key == Keys.ANY_KEY) { + return keyJustPressed; + } + if (key < 0 || key > 255) { + return false; + } + return justPressedKeys[key]; + } + + public void getTextInput (TextInputListener listener, String title, String text, String hint) { + TextInputDialogBox dialog = new TextInputDialogBox(title, text, hint); final TextInputListener capturedListener = listener; dialog.setListener(new TextInputDialogListener() { @Override - public void onPositive(String text) { + public void onPositive (String text) { if (capturedListener != null) { capturedListener.input(text); } } @Override - public void onNegative() { + public void onNegative () { if (capturedListener != null) { capturedListener.canceled(); } @@ -159,208 +208,174 @@ public class GwtInput implements Input { } @Override - public void getPlaceholderTextInput(TextInputListener listener, String title, String placeholder) { - TextInputDialogBox dialog = new TextInputDialogBox(title, null, placeholder); - final TextInputListener capturedListener = listener; - dialog.setListener(new TextInputDialogListener() { - @Override - public void onPositive(String text) { - if (capturedListener != null) { - capturedListener.input(text); - } - } - - @Override - public void onNegative() { - if (capturedListener != null) { - capturedListener.canceled(); - } - } - }); + public void setOnscreenKeyboardVisible (boolean visible) { } @Override - public void setOnscreenKeyboardVisible(boolean visible) { + public void vibrate (int milliseconds) { } @Override - public void vibrate(int milliseconds) { + public void vibrate (long[] pattern, int repeat) { } @Override - public void vibrate(long[] pattern, int repeat) { + public void cancelVibrate () { } @Override - public void cancelVibrate() { - } - - @Override - public float getAzimuth() { + public float getAzimuth () { return 0; } @Override - public float getPitch() { + public float getPitch () { return 0; } @Override - public float getRoll() { + public float getRoll () { return 0; } @Override - public void getRotationMatrix(float[] matrix) { + public void getRotationMatrix (float[] matrix) { } @Override - public long getCurrentEventTime() { + public long getCurrentEventTime () { return currentEventTimeStamp; } @Override - public void setCatchBackKey(boolean catchBack) { + public void setCatchBackKey (boolean catchBack) { } @Override - public void setCatchMenuKey(boolean catchMenu) { + public boolean isCatchBackKey () { + return false; } @Override - public void setInputProcessor(InputProcessor processor) { + public void setCatchMenuKey (boolean catchMenu) { + } + + @Override + public boolean isCatchMenuKey () { + return false; + } + + @Override + public void setInputProcessor (InputProcessor processor) { this.processor = processor; } @Override - public InputProcessor getInputProcessor() { + public InputProcessor getInputProcessor () { return processor; } @Override - public boolean isPeripheralAvailable(Peripheral peripheral) { - if (peripheral == Peripheral.Accelerometer) - return false; - if (peripheral == Peripheral.Compass) - return false; - if (peripheral == Peripheral.HardwareKeyboard) - return true; - if (peripheral == Peripheral.MultitouchScreen) - return isTouchScreen(); - if (peripheral == Peripheral.OnscreenKeyboard) - return false; - if (peripheral == Peripheral.Vibrator) - return false; + public boolean isPeripheralAvailable (Peripheral peripheral) { + if (peripheral == Peripheral.Accelerometer) return false; + if (peripheral == Peripheral.Compass) return false; + if (peripheral == Peripheral.HardwareKeyboard) return true; + if (peripheral == Peripheral.MultitouchScreen) return isTouchScreen(); + if (peripheral == Peripheral.OnscreenKeyboard) return false; + if (peripheral == Peripheral.Vibrator) return false; return false; } @Override - public int getRotation() { + public int getRotation () { return 0; } @Override - public Orientation getNativeOrientation() { + public Orientation getNativeOrientation () { return Orientation.Landscape; } - /** - * from https://github.com/toji/game-shim/blob/master/game-shim.js - * - * @return is Cursor catched - */ - private native boolean isCursorCatchedJSNI() /*-{ - if (!navigator.pointer) { - navigator.pointer = navigator.webkitPointer || navigator.mozPointer; - } - if (navigator.pointer) { - if (typeof (navigator.pointer.isLocked) === "boolean") { - // Chrome initially launched with this interface - return navigator.pointer.isLocked; - } else if (typeof (navigator.pointer.isLocked) === "function") { - // Some older builds might provide isLocked as a function - return navigator.pointer.isLocked(); - } else if (typeof (navigator.pointer.islocked) === "function") { - // For compatibility with early Firefox build - return navigator.pointer.islocked(); - } - } - return false; - }-*/; + /** from https://github.com/toji/game-shim/blob/master/game-shim.js + * @return is Cursor catched */ + private native boolean isCursorCatchedJSNI () /*-{ + if (!navigator.pointer) { + navigator.pointer = navigator.webkitPointer || navigator.mozPointer; + } + if (navigator.pointer) { + if (typeof (navigator.pointer.isLocked) === "boolean") { + // Chrome initially launched with this interface + return navigator.pointer.isLocked; + } else if (typeof (navigator.pointer.isLocked) === "function") { + // Some older builds might provide isLocked as a function + return navigator.pointer.isLocked(); + } else if (typeof (navigator.pointer.islocked) === "function") { + // For compatibility with early Firefox build + return navigator.pointer.islocked(); + } + } + return false; + }-*/; - /** - * from https://github.com/toji/game-shim/blob/master/game-shim.js - * - * @param element Canvas - */ - private native void setCursorCatchedJSNI(CanvasElement element) /*-{ - // Navigator pointer is not the right interface according to spec. - // Here for backwards compatibility only - if (!navigator.pointer) { - navigator.pointer = navigator.webkitPointer || navigator.mozPointer; - } - // element.requestPointerLock - if (!element.requestPointerLock) { - element.requestPointerLock = (function() { - return element.webkitRequestPointerLock - || element.mozRequestPointerLock || function() { - if (navigator.pointer) { - navigator.pointer.lock(element); - } - }; - })(); - } - element.requestPointerLock(); - }-*/; + /** from https://github.com/toji/game-shim/blob/master/game-shim.js + * @param element Canvas */ + private native void setCursorCatchedJSNI (CanvasElement element) /*-{ + // Navigator pointer is not the right interface according to spec. + // Here for backwards compatibility only + if (!navigator.pointer) { + navigator.pointer = navigator.webkitPointer || navigator.mozPointer; + } + // element.requestPointerLock + if (!element.requestPointerLock) { + element.requestPointerLock = (function() { + return element.webkitRequestPointerLock + || element.mozRequestPointerLock || function() { + if (navigator.pointer) { + navigator.pointer.lock(element); + } + }; + })(); + } + element.requestPointerLock(); + }-*/; - /** - * from https://github.com/toji/game-shim/blob/master/game-shim.js - */ - private native void exitCursorCatchedJSNI() /*-{ - if (!$doc.exitPointerLock) { - $doc.exitPointerLock = (function() { - return $doc.webkitExitPointerLock || $doc.mozExitPointerLock - || function() { - if (navigator.pointer) { - var elem = this; - navigator.pointer.unlock(); - } - }; - })(); - } - }-*/; + /** from https://github.com/toji/game-shim/blob/master/game-shim.js */ + private native void exitCursorCatchedJSNI () /*-{ + if (!$doc.exitPointerLock) { + $doc.exitPointerLock = (function() { + return $doc.webkitExitPointerLock || $doc.mozExitPointerLock + || function() { + if (navigator.pointer) { + var elem = this; + navigator.pointer.unlock(); + } + }; + })(); + } + }-*/; - /** - * from https://github.com/toji/game-shim/blob/master/game-shim.js - * + /** from https://github.com/toji/game-shim/blob/master/game-shim.js * @param event JavaScript Mouse Event - * @return movement in x direction - */ - private native float getMovementXJSNI(NativeEvent event) /*-{ - return event.movementX || event.webkitMovementX || 0; - }-*/; + * @return movement in x direction */ + private native float getMovementXJSNI (NativeEvent event) /*-{ + return event.movementX || event.webkitMovementX || 0; + }-*/; - /** - * from https://github.com/toji/game-shim/blob/master/game-shim.js - * + /** from https://github.com/toji/game-shim/blob/master/game-shim.js * @param event JavaScript Mouse Event - * @return movement in y direction - */ - private native float getMovementYJSNI(NativeEvent event) /*-{ - return event.movementY || event.webkitMovementY || 0; - }-*/; + * @return movement in y direction */ + private native float getMovementYJSNI (NativeEvent event) /*-{ + return event.movementY || event.webkitMovementY || 0; + }-*/; - private static native boolean isTouchScreen() /*-{ - return (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0)); - }-*/; + private static native boolean isTouchScreen () /*-{ + return (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0)); + }-*/; - /** - * works only for Chrome > Version 18 with enabled Mouse Lock enable in - * about:flags or start Chrome with the - * --enable-pointer-lock flag - */ + /** works only for Chrome > Version 18 with enabled Mouse Lock enable in about:flags or start Chrome with the + * --enable-pointer-lock flag */ @Override - public void setCursorCatched(boolean catched) { + public void setCursorCatched (boolean catched) { if (catched) setCursorCatchedJSNI(canvas); else @@ -368,89 +383,90 @@ public class GwtInput implements Input { } @Override - public boolean isCursorCatched() { + public boolean isCursorCatched () { return isCursorCatchedJSNI(); } @Override - public void setCursorPosition(int x, int y) { + public void setCursorPosition (int x, int y) { // FIXME?? } - @Override - public void setCursorImage(Pixmap pixmap, int xHotspot, int yHotspot) { - } - // kindly borrowed from our dear playn friends... - static native void addEventListener(JavaScriptObject target, String name, GwtInput handler, - boolean capture) /*-{ - target - .addEventListener( - name, - function(e) { - handler.@com.badlogic.gdx.backends.gwt.GwtInput::handleEvent(Lcom/google/gwt/dom/client/NativeEvent;)(e); - }, capture); - }-*/; + static native void addEventListener (JavaScriptObject target, String name, GwtInput handler, boolean capture) /*-{ + target + .addEventListener( + name, + function(e) { + handler.@com.badlogic.gdx.backends.gwt.GwtInput::handleEvent(Lcom/google/gwt/dom/client/NativeEvent;)(e); + }, capture); + }-*/; - private static native float getMouseWheelVelocity(NativeEvent evt) /*-{ - var delta = 0.0; - var agentInfo = @com.badlogic.gdx.backends.gwt.GwtApplication::agentInfo()(); + private static native float getMouseWheelVelocity (NativeEvent evt) /*-{ + var delta = 0.0; + var agentInfo = @com.badlogic.gdx.backends.gwt.GwtApplication::agentInfo()(); - if (agentInfo.isFirefox) { - if (agentInfo.isMacOS) { - delta = 1.0 * evt.detail; - } else { - delta = 1.0 * evt.detail / 3; - } - } else if (agentInfo.isOpera) { - if (agentInfo.isLinux) { - delta = -1.0 * evt.wheelDelta / 80; - } else { - // on mac - delta = -1.0 * evt.wheelDelta / 40; - } - } else if (agentInfo.isChrome || agentInfo.isSafari) { - delta = -1.0 * evt.wheelDelta / 120; - // handle touchpad for chrome - if (Math.abs(delta) < 1) { - if (agentInfo.isWindows) { - delta = -1.0 * evt.wheelDelta; - } else if (agentInfo.isMacOS) { - delta = -1.0 * evt.wheelDelta / 3; - } - } - } - return delta; - }-*/; + if (agentInfo.isFirefox) { + if (agentInfo.isMacOS) { + delta = 1.0 * evt.detail; + } else { + delta = 1.0 * evt.detail / 3; + } + } else if (agentInfo.isOpera) { + if (agentInfo.isLinux) { + delta = -1.0 * evt.wheelDelta / 80; + } else { + // on mac + delta = -1.0 * evt.wheelDelta / 40; + } + } else if (agentInfo.isChrome || agentInfo.isSafari) { + delta = -1.0 * evt.wheelDelta / 120; + // handle touchpad for chrome + if (Math.abs(delta) < 1) { + if (agentInfo.isWindows) { + delta = -1.0 * evt.wheelDelta; + } else if (agentInfo.isMacOS) { + delta = -1.0 * evt.wheelDelta / 3; + } + } + } + return delta; + }-*/; - /** - * Kindly borrowed from PlayN. - **/ - protected static native String getMouseWheelEvent() /*-{ - if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1) { - return "DOMMouseScroll"; - } else { - return "mousewheel"; - } - }-*/; + /** Kindly borrowed from PlayN. **/ + protected static native String getMouseWheelEvent () /*-{ + if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1) { + return "DOMMouseScroll"; + } else { + return "mousewheel"; + } + }-*/; - /** - * Kindly borrowed from PlayN. - **/ - protected static float getRelativeX(NativeEvent e, Element target) { - return e.getClientX() - target.getAbsoluteLeft() + target.getScrollLeft() - + target.getOwnerDocument().getScrollLeft(); + /** Kindly borrowed from PlayN. **/ + protected int getRelativeX (NativeEvent e, CanvasElement target) { + float xScaleRatio = target.getWidth() * 1f / target.getClientWidth(); // Correct for canvas CSS scaling + return Math.round(xScaleRatio + * (e.getClientX() - target.getAbsoluteLeft() + target.getScrollLeft() + target.getOwnerDocument().getScrollLeft())); } - /** - * Kindly borrowed from PlayN. - **/ - protected static float getRelativeY(NativeEvent e, Element target) { - return e.getClientY() - target.getAbsoluteTop() + target.getScrollTop() - + target.getOwnerDocument().getScrollTop(); + /** Kindly borrowed from PlayN. **/ + protected int getRelativeY (NativeEvent e, CanvasElement target) { + float yScaleRatio = target.getHeight() * 1f / target.getClientHeight(); // Correct for canvas CSS scaling + return Math.round(yScaleRatio + * (e.getClientY() - target.getAbsoluteTop() + target.getScrollTop() + target.getOwnerDocument().getScrollTop())); } - private void hookEvents() { + protected int getRelativeX (Touch touch, CanvasElement target) { + float xScaleRatio = target.getWidth() * 1f / target.getClientWidth(); // Correct for canvas CSS scaling + return Math.round(xScaleRatio * touch.getRelativeX(target)); + } + + protected int getRelativeY (Touch touch, CanvasElement target) { + float yScaleRatio = target.getHeight() * 1f / target.getClientHeight(); // Correct for canvas CSS scaling + return Math.round(yScaleRatio * touch.getRelativeY(target)); + } + + private void hookEvents () { addEventListener(canvas, "mousedown", this, true); // addEventListener(Document.get(), "mousedown", this, true); addEventListener(canvas, "mouseup", this, true); @@ -464,6 +480,7 @@ public class GwtInput implements Input { addEventListener(canvas, "keydown", this, false); addEventListener(canvas, "keyup", this, false); addEventListener(canvas, "keypress", this, false); + addEventListener(canvas, "touchstart", this, true); addEventListener(canvas, "touchmove", this, true); addEventListener(canvas, "touchcancel", this, true); @@ -471,23 +488,19 @@ public class GwtInput implements Input { } - private int getButton(int button) { - if (button == NativeEvent.BUTTON_LEFT) - return Buttons.LEFT; - if (button == NativeEvent.BUTTON_RIGHT) - return Buttons.RIGHT; - if (button == NativeEvent.BUTTON_MIDDLE) - return Buttons.MIDDLE; + private int getButton (int button) { + if (button == NativeEvent.BUTTON_LEFT) return Buttons.LEFT; + if (button == NativeEvent.BUTTON_RIGHT) return Buttons.RIGHT; + if (button == NativeEvent.BUTTON_MIDDLE) return Buttons.MIDDLE; return Buttons.LEFT; } - private void handleEvent(NativeEvent e) { + private void handleEvent (NativeEvent e) { if (e.getType().equals("mousedown")) { if (!e.getEventTarget().equals(canvas) || touched[0]) { - float mouseX = (int) getRelativeX(e, canvas); - float mouseY = (int) getRelativeY(e, canvas); - if (mouseX < 0 || mouseX > Gdx.graphics.getWidth() || mouseY < 0 - || mouseY > Gdx.graphics.getHeight()) { + float mouseX = getRelativeX(e, canvas); + float mouseY = getRelativeY(e, canvas); + if (mouseX < 0 || mouseX > Gdx.graphics.getWidth() || mouseY < 0 || mouseY > Gdx.graphics.getHeight()) { hasFocus = false; } return; @@ -502,25 +515,24 @@ public class GwtInput implements Input { this.touchX[0] += getMovementXJSNI(e); this.touchY[0] += getMovementYJSNI(e); } else { - this.touchX[0] = (int) getRelativeX(e, canvas); - this.touchY[0] = (int) getRelativeY(e, canvas); + this.touchX[0] = getRelativeX(e, canvas); + this.touchY[0] = getRelativeY(e, canvas); } this.currentEventTimeStamp = TimeUtils.nanoTime(); - if (processor != null) - processor.touchDown(touchX[0], touchY[0], 0, getButton(e.getButton())); + if (processor != null) processor.touchDown(touchX[0], touchY[0], 0, getButton(e.getButton())); } if (e.getType().equals("mousemove")) { if (isCursorCatched()) { - this.deltaX[0] = (int) getMovementXJSNI(e); - this.deltaY[0] = (int) getMovementYJSNI(e); + this.deltaX[0] = (int)getMovementXJSNI(e); + this.deltaY[0] = (int)getMovementYJSNI(e); this.touchX[0] += getMovementXJSNI(e); this.touchY[0] += getMovementYJSNI(e); } else { - this.deltaX[0] = (int) getRelativeX(e, canvas) - touchX[0]; - this.deltaY[0] = (int) getRelativeY(e, canvas) - touchY[0]; - this.touchX[0] = (int) getRelativeX(e, canvas); - this.touchY[0] = (int) getRelativeY(e, canvas); + this.deltaX[0] = getRelativeX(e, canvas) - touchX[0]; + this.deltaY[0] = getRelativeY(e, canvas) - touchY[0]; + this.touchX[0] = getRelativeX(e, canvas); + this.touchY[0] = getRelativeY(e, canvas); } this.currentEventTimeStamp = TimeUtils.nanoTime(); if (processor != null) { @@ -532,35 +544,33 @@ public class GwtInput implements Input { } if (e.getType().equals("mouseup")) { - if (!touched[0]) - return; + if (!touched[0]) return; this.pressedButtons.remove(getButton(e.getButton())); - this.touched[0] = pressedButtons.size() > 0; + this.touched[0] = pressedButtons.size > 0; if (isCursorCatched()) { - this.deltaX[0] = (int) getMovementXJSNI(e); - this.deltaY[0] = (int) getMovementYJSNI(e); + this.deltaX[0] = (int)getMovementXJSNI(e); + this.deltaY[0] = (int)getMovementYJSNI(e); this.touchX[0] += getMovementXJSNI(e); this.touchY[0] += getMovementYJSNI(e); } else { - this.deltaX[0] = (int) getRelativeX(e, canvas) - touchX[0]; - this.deltaY[0] = (int) getRelativeY(e, canvas) - touchY[0]; - this.touchX[0] = (int) getRelativeX(e, canvas); - this.touchY[0] = (int) getRelativeY(e, canvas); + this.deltaX[0] = getRelativeX(e, canvas) - touchX[0]; + this.deltaY[0] = getRelativeY(e, canvas) - touchY[0]; + this.touchX[0] = getRelativeX(e, canvas); + this.touchY[0] = getRelativeY(e, canvas); } this.currentEventTimeStamp = TimeUtils.nanoTime(); this.touched[0] = false; - if (processor != null) - processor.touchUp(touchX[0], touchY[0], 0, getButton(e.getButton())); + if (processor != null) processor.touchUp(touchX[0], touchY[0], 0, getButton(e.getButton())); } if (e.getType().equals(getMouseWheelEvent())) { if (processor != null) { - processor.scrolled((int) getMouseWheelVelocity(e)); + processor.scrolled((int)getMouseWheelVelocity(e)); } this.currentEventTimeStamp = TimeUtils.nanoTime(); e.preventDefault(); } if (e.getType().equals("keydown") && hasFocus) { - //System.out.println("keydown"); + // System.out.println("keydown"); int code = keyForCode(e.getKeyCode()); if (code == 67) { e.preventDefault(); @@ -569,23 +579,31 @@ public class GwtInput implements Input { processor.keyTyped('\b'); } } else { - if (this.pressedKeys.add(code) && processor != null) { - processor.keyDown(code); + if (!pressedKeys[code]) { + pressedKeyCount++; + pressedKeys[code] = true; + keyJustPressed = true; + justPressedKeys[code] = true; + if (processor != null) { + processor.keyDown(code); + } } } } if (e.getType().equals("keypress") && hasFocus) { - //System.out.println("keypress"); - char c = (char) e.getCharCode(); - if (processor != null) - processor.keyTyped(c); + // System.out.println("keypress"); + char c = (char)e.getCharCode(); + if (processor != null) processor.keyTyped(c); } if (e.getType().equals("keyup") && hasFocus) { - //System.out.println("keyup"); + // System.out.println("keyup"); int code = keyForCode(e.getKeyCode()); - this.pressedKeys.remove(code); + if (pressedKeys[code]) { + pressedKeyCount--; + pressedKeys[code] = false; + } if (processor != null) { processor.keyUp(code); } @@ -596,10 +614,12 @@ public class GwtInput implements Input { JsArray touches = e.getChangedTouches(); for (int i = 0, j = touches.length(); i < j; i++) { Touch touch = touches.get(i); - int touchId = touch.getIdentifier(); + int real = touch.getIdentifier(); + int touchId; + touchMap.put(real, touchId = getAvailablePointer()); touched[touchId] = true; - touchX[touchId] = touch.getRelativeX(canvas); - touchY[touchId] = touch.getRelativeY(canvas); + touchX[touchId] = getRelativeX(touch, canvas); + touchY[touchId] = getRelativeY(touch, canvas); deltaX[touchId] = 0; deltaY[touchId] = 0; if (processor != null) { @@ -613,11 +633,12 @@ public class GwtInput implements Input { JsArray touches = e.getChangedTouches(); for (int i = 0, j = touches.length(); i < j; i++) { Touch touch = touches.get(i); - int touchId = touch.getIdentifier(); - deltaX[touchId] = touch.getRelativeX(canvas) - touchX[touchId]; - deltaY[touchId] = touch.getRelativeY(canvas) - touchY[touchId]; - touchX[touchId] = touch.getRelativeX(canvas); - touchY[touchId] = touch.getRelativeY(canvas); + int real = touch.getIdentifier(); + int touchId = touchMap.get(real); + deltaX[touchId] = getRelativeX(touch, canvas) - touchX[touchId]; + deltaY[touchId] = getRelativeY(touch, canvas) - touchY[touchId]; + touchX[touchId] = getRelativeX(touch, canvas); + touchY[touchId] = getRelativeY(touch, canvas); if (processor != null) { processor.touchDragged(touchX[touchId], touchY[touchId], touchId); } @@ -629,12 +650,14 @@ public class GwtInput implements Input { JsArray touches = e.getChangedTouches(); for (int i = 0, j = touches.length(); i < j; i++) { Touch touch = touches.get(i); - int touchId = touch.getIdentifier(); + int real = touch.getIdentifier(); + int touchId = touchMap.get(real); + touchMap.remove(real); touched[touchId] = false; - deltaX[touchId] = touch.getRelativeX(canvas) - touchX[touchId]; - deltaY[touchId] = touch.getRelativeY(canvas) - touchY[touchId]; - touchX[touchId] = touch.getRelativeX(canvas); - touchY[touchId] = touch.getRelativeY(canvas); + deltaX[touchId] = getRelativeX(touch, canvas) - touchX[touchId]; + deltaY[touchId] = getRelativeY(touch, canvas) - touchY[touchId]; + touchX[touchId] = getRelativeX(touch, canvas); + touchY[touchId] = getRelativeY(touch, canvas); if (processor != null) { processor.touchUp(touchX[touchId], touchY[touchId], touchId, Buttons.LEFT); } @@ -646,12 +669,14 @@ public class GwtInput implements Input { JsArray touches = e.getChangedTouches(); for (int i = 0, j = touches.length(); i < j; i++) { Touch touch = touches.get(i); - int touchId = touch.getIdentifier(); + int real = touch.getIdentifier(); + int touchId = touchMap.get(real); + touchMap.remove(real); touched[touchId] = false; - deltaX[touchId] = touch.getRelativeX(canvas) - touchX[touchId]; - deltaY[touchId] = touch.getRelativeY(canvas) - touchY[touchId]; - touchX[touchId] = touch.getRelativeX(canvas); - touchY[touchId] = touch.getRelativeY(canvas); + deltaX[touchId] = getRelativeX(touch, canvas) - touchX[touchId]; + deltaY[touchId] = getRelativeY(touch, canvas) - touchY[touchId]; + touchX[touchId] = getRelativeX(touch, canvas); + touchY[touchId] = getRelativeY(touch, canvas); if (processor != null) { processor.touchUp(touchX[touchId], touchY[touchId], touchId, Buttons.LEFT); } @@ -659,13 +684,18 @@ public class GwtInput implements Input { this.currentEventTimeStamp = TimeUtils.nanoTime(); e.preventDefault(); } - // if(hasFocus) e.preventDefault(); +// if(hasFocus) e.preventDefault(); } - /** - * borrowed from PlayN, thanks guys - **/ - private static int keyForCode(int keyCode) { + private int getAvailablePointer () { + for (int i = 0; i < MAX_TOUCHES; i++) { + if (!touchMap.containsValue(i, false)) return i; + } + return -1; + } + + /** borrowed from PlayN, thanks guys **/ + private static int keyForCode (int keyCode) { switch (keyCode) { case KeyCodes.KEY_ALT: return Keys.ALT_LEFT; @@ -955,15 +985,4 @@ public class GwtInput implements Input { private static final int KEY_CLOSE_BRACKET = 221; private static final int KEY_SINGLE_QUOTE = 222; - @Override - public boolean isKeyJustPressed(int key) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean isCatchBackKey() { - // TODO Auto-generated method stub - return false; - } } diff --git a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/graphics/Pixmap.java b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/graphics/Pixmap.java index 6a6040fd..57893f49 100644 --- a/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/graphics/Pixmap.java +++ b/vtm-web/src/org/oscim/gdx/emu/com/badlogic/gdx/graphics/Pixmap.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2011 See libgdx AUTHORS file. - *

+ * Copyright 2011 See AUTHORS file. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

+ * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,6 +16,11 @@ package com.badlogic.gdx.graphics; +import java.nio.Buffer; +import java.nio.IntBuffer; +import java.util.HashMap; +import java.util.Map; + import com.badlogic.gdx.backends.gwt.GwtFileHandle; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.BufferUtils; @@ -28,38 +33,48 @@ import com.google.gwt.canvas.dom.client.Context2d.Composite; import com.google.gwt.dom.client.CanvasElement; import com.google.gwt.dom.client.ImageElement; -import java.nio.Buffer; -import java.nio.IntBuffer; -import java.util.HashMap; -import java.util.Map; - public class Pixmap implements Disposable { public static Map pixmaps = new HashMap(); static int nextId = 0; - /** - * Different pixel formats. + /** Different pixel formats. * - * @author mzechner - */ + * @author mzechner */ public enum Format { Alpha, Intensity, LuminanceAlpha, RGB565, RGBA4444, RGB888, RGBA8888; + + public static int toGlFormat (Format format) { + if (format == Alpha) return GL20.GL_ALPHA; + if (format == Intensity) return GL20.GL_ALPHA; + if (format == LuminanceAlpha) return GL20.GL_LUMINANCE_ALPHA; + if (format == RGB565) return GL20.GL_RGB; + if (format == RGB888) return GL20.GL_RGB; + if (format == RGBA4444) return GL20.GL_RGBA; + if (format == RGBA8888) return GL20.GL_RGBA; + throw new GdxRuntimeException("unknown format: " + format); + } + + public static int toGlType (Format format) { + if (format == Alpha) return GL20.GL_UNSIGNED_BYTE; + if (format == Intensity) return GL20.GL_UNSIGNED_BYTE; + if (format == LuminanceAlpha) return GL20.GL_UNSIGNED_BYTE; + if (format == RGB565) return GL20.GL_UNSIGNED_SHORT_5_6_5; + if (format == RGB888) return GL20.GL_UNSIGNED_BYTE; + if (format == RGBA4444) return GL20.GL_UNSIGNED_SHORT_4_4_4_4; + if (format == RGBA8888) return GL20.GL_UNSIGNED_BYTE; + throw new GdxRuntimeException("unknown format: " + format); + } } - /** - * Blending functions to be set with {@link Pixmap#setBlending}. - * - * @author mzechner - */ + /** Blending functions to be set with {@link Pixmap#setBlending}. + * @author mzechner */ public enum Blending { None, SourceOver } - /** - * Filters to be used with {@link Pixmap#drawPixmap(Pixmap, int, int, int, int, int, int, int, int)}. + /** Filters to be used with {@link Pixmap#drawPixmap(Pixmap, int, int, int, int, int, int, int, int)}. * - * @author mzechner - */ + * @author mzechner */ public enum Filter { NearestNeighbour, BiLinear } @@ -74,128 +89,139 @@ public class Pixmap implements Disposable { int r = 255, g = 255, b = 255; float a; String color = make(r, g, b, a); + static String clearColor = make(255, 255, 255, 1.0f); static Blending blending; CanvasPixelArray pixels; + private ImageElement imageElement; + + public Pixmap (FileHandle file) { + this(((GwtFileHandle)file).preloader.images.get(file.path())); + if (imageElement == null) throw new GdxRuntimeException("Couldn't load image '" + file.path() + "', file does not exist"); + } public Context2d getContext() { + ensureCanvasExists(); return context; } - public Pixmap(FileHandle file) { - GwtFileHandle gwtFile = (GwtFileHandle) file; - ImageElement img = gwtFile.preloader.images.get(file.path()); - if (img == null) - throw new GdxRuntimeException("Couldn't load image '" + file.path() + "', file does not exist"); - create(img.getWidth(), img.getHeight(), Format.RGBA8888); - context.setGlobalCompositeOperation(Composite.COPY); - context.drawImage(img, 0, 0); - context.setGlobalCompositeOperation(getComposite()); + private static Composite getComposite () { + return Composite.SOURCE_OVER; } - private static Composite getComposite() { - return blending == Blending.None ? Composite.COPY : Composite.SOURCE_OVER; + public Pixmap (ImageElement img) { + this(-1, -1, img); } - public Pixmap(ImageElement img) { - create(img.getWidth(), img.getHeight(), Format.RGBA8888); - context.drawImage(img, 0, 0); + public Pixmap (int width, int height, Format format) { + this(width, height, (ImageElement)null); } - public Pixmap(int width, int height, Format format) { - create(width, height, format); - } + private Pixmap(int width, int height, ImageElement imageElement) { + this.imageElement = imageElement; + this.width = imageElement != null ? imageElement.getWidth() : width; + this.height = imageElement != null ? imageElement.getHeight() : height; - private void create(int width, int height, Format format2) { - this.width = width; - this.height = height; - this.format = Format.RGBA8888; - canvas = Canvas.createIfSupported(); - canvas.getCanvasElement().setWidth(width); - canvas.getCanvasElement().setHeight(height); - context = canvas.getContext2d(); - context.setGlobalCompositeOperation(getComposite()); buffer = BufferUtils.newIntBuffer(1); id = nextId++; buffer.put(0, id); pixmaps.put(id, this); } - public static String make(int r2, int g2, int b2, float a2) { + private void create () { + canvas = Canvas.createIfSupported(); + canvas.getCanvasElement().setWidth(width); + canvas.getCanvasElement().setHeight(height); + context = canvas.getContext2d(); + context.setGlobalCompositeOperation(getComposite()); + } + + public static String make (int r2, int g2, int b2, float a2) { return "rgba(" + r2 + "," + g2 + "," + b2 + "," + a2 + ")"; } - /** - * Sets the type of {@link Blending} to be used for all operations. Default is {@link Blending#SourceOver}. - * - * @param blending the blending type - */ - public static void setBlending(Blending blending) { + /** Sets the type of {@link Blending} to be used for all operations. Default is {@link Blending#SourceOver}. + * @param blending the blending type */ + public static void setBlending (Blending blending) { Pixmap.blending = blending; Composite composite = getComposite(); for (Pixmap pixmap : pixmaps.values()) { + pixmap.ensureCanvasExists(); pixmap.context.setGlobalCompositeOperation(composite); } } - /** - * @return the currently set {@link Blending} - */ - public static Blending getBlending() { + /** @return the currently set {@link Blending} */ + public static Blending getBlending () { return blending; } - /** - * Sets the type of interpolation {@link Filter} to be used in conjunction with + /** Sets the type of interpolation {@link Filter} to be used in conjunction with * {@link Pixmap#drawPixmap(Pixmap, int, int, int, int, int, int, int, int)}. - * - * @param filter the filter. - */ - public static void setFilter(Filter filter) { + * @param filter the filter. */ + public static void setFilter (Filter filter) { } - public Format getFormat() { + public Format getFormat () { return format; } - public int getGLInternalFormat() { + public int getGLInternalFormat () { return GL20.GL_RGBA; } - public int getGLFormat() { + public int getGLFormat () { return GL20.GL_RGBA; } - public int getGLType() { + public int getGLType () { return GL20.GL_UNSIGNED_BYTE; } - public int getWidth() { + public int getWidth () { return width; } - public int getHeight() { + public int getHeight () { return height; } - public Buffer getPixels() { + public Buffer getPixels () { return buffer; } @Override - public void dispose() { + public void dispose () { pixmaps.remove(id); } - public CanvasElement getCanvasElement() { + public CanvasElement getCanvasElement () { + ensureCanvasExists(); return canvas.getCanvasElement(); } - /** - * Sets the color for the following drawing operations - * - * @param color the color, encoded as RGBA8888 - */ - public void setColor(int color) { + private void ensureCanvasExists () { + if (canvas == null) { + create(); + if (imageElement != null) { + context.setGlobalCompositeOperation(Composite.COPY); + context.drawImage(imageElement, 0, 0); + context.setGlobalCompositeOperation(getComposite()); + } + } + } + + public boolean canUseImageElement () { + return canvas == null && imageElement != null; + } + + public ImageElement getImageElement () { + return imageElement; + } + + /** Sets the color for the following drawing operations + * @param color the color, encoded as RGBA8888 */ + public void setColor (int color) { + ensureCanvasExists(); r = (color >>> 24) & 0xff; g = (color >>> 16) & 0xff; b = (color >>> 8) & 0xff; @@ -205,38 +231,34 @@ public class Pixmap implements Disposable { context.setStrokeStyle(this.color); } - /** - * Sets the color for the following drawing operations. + /** Sets the color for the following drawing operations. * * @param r The red component. * @param g The green component. * @param b The blue component. - * @param a The alpha component. - */ - public void setColor(float r, float g, float b, float a) { - this.r = (int) (r * 255); - this.g = (int) (g * 255); - this.b = (int) (b * 255); + * @param a The alpha component. */ + public void setColor (float r, float g, float b, float a) { + ensureCanvasExists(); + this.r = (int)(r * 255); + this.g = (int)(g * 255); + this.b = (int)(b * 255); this.a = a; color = make(this.r, this.g, this.b, this.a); context.setFillStyle(color); context.setStrokeStyle(this.color); } - /** - * Sets the color for the following drawing operations. - * - * @param color The color. - */ - public void setColor(Color color) { + /** Sets the color for the following drawing operations. + * @param color The color. */ + public void setColor (Color color) { setColor(color.r, color.g, color.b, color.a); } - /** - * Fills the complete bitmap with the currently set color. - */ - public void fill() { - context.fillRect(0, 0, getWidth(), getHeight()); + /** Fills the complete bitmap with the currently set color. */ + public void fill () { + ensureCanvasExists(); + context.clearRect(0, 0, getWidth(), getHeight()); + rectangle(0, 0, getWidth(), getHeight(), DrawType.FILL); } // /** @@ -246,153 +268,117 @@ public class Pixmap implements Disposable { // */ // public void setStrokeWidth (int width); - /** - * Draws a line between the given coordinates using the currently set color. + /** Draws a line between the given coordinates using the currently set color. * - * @param x The x-coodinate of the first point - * @param y The y-coordinate of the first point + * @param x The x-coodinate of the first point + * @param y The y-coordinate of the first point * @param x2 The x-coordinate of the first point - * @param y2 The y-coordinate of the first point - */ - public void drawLine(int x, int y, int x2, int y2) { - context.beginPath(); - context.moveTo(x, y); - context.lineTo(x2, y2); - context.stroke(); - context.closePath(); + * @param y2 The y-coordinate of the first point */ + public void drawLine (int x, int y, int x2, int y2) { + line(x, y, x2, y2, DrawType.STROKE); } - /** - * Draws a rectangle outline starting at x, y extending by width to the right and by height downwards (y-axis points downwards) + /** Draws a rectangle outline starting at x, y extending by width to the right and by height downwards (y-axis points downwards) * using the current color. * - * @param x The x coordinate - * @param y The y coordinate - * @param width The width in pixels - * @param height The height in pixels - */ - public void drawRectangle(int x, int y, int width, int height) { - context.beginPath(); - context.rect(x, y, width, height); - context.stroke(); - context.closePath(); + * @param x The x coordinate + * @param y The y coordinate + * @param width The width in pixels + * @param height The height in pixels */ + public void drawRectangle (int x, int y, int width, int height) { + rectangle(x, y, width, height, DrawType.STROKE); } - /** - * Draws an area form another Pixmap to this Pixmap. + /** Draws an area form another Pixmap to this Pixmap. * * @param pixmap The other Pixmap - * @param x The target x-coordinate (top left corner) - * @param y The target y-coordinate (top left corner) - */ - public void drawPixmap(Pixmap pixmap, int x, int y) { - context.drawImage(pixmap.getCanvasElement(), x, y); + * @param x The target x-coordinate (top left corner) + * @param y The target y-coordinate (top left corner) */ + public void drawPixmap (Pixmap pixmap, int x, int y) { + CanvasElement image = pixmap.getCanvasElement(); + image(image, 0, 0, image.getWidth(), image.getHeight(), x, y, image.getWidth(), image.getHeight()); } - /** - * Draws an area form another Pixmap to this Pixmap. + /** Draws an area form another Pixmap to this Pixmap. * - * @param pixmap The other Pixmap - * @param x The target x-coordinate (top left corner) - * @param y The target y-coordinate (top left corner) - * @param srcx The source x-coordinate (top left corner) - * @param srcy The source y-coordinate (top left corner); - * @param srcWidth The width of the area form the other Pixmap in pixels - * @param srcHeight The height of the area form the other Pixmap in pixles - */ - public void drawPixmap(Pixmap pixmap, int x, int y, int srcx, int srcy, int srcWidth, int srcHeight) { - context.drawImage(pixmap.getCanvasElement(), srcx, srcy, srcWidth, srcHeight, x, y, srcWidth, srcHeight); + * @param pixmap The other Pixmap + * @param x The target x-coordinate (top left corner) + * @param y The target y-coordinate (top left corner) + * @param srcx The source x-coordinate (top left corner) + * @param srcy The source y-coordinate (top left corner); + * @param srcWidth The width of the area form the other Pixmap in pixels + * @param srcHeight The height of the area form the other Pixmap in pixles */ + public void drawPixmap (Pixmap pixmap, int x, int y, int srcx, int srcy, int srcWidth, int srcHeight) { + CanvasElement image = pixmap.getCanvasElement(); + image(image, srcx, srcy, srcWidth, srcHeight, x, y, srcWidth, srcHeight); } - /** - * Draws an area form another Pixmap to this Pixmap. This will automatically scale and stretch the source image to the + /** Draws an area form another Pixmap to this Pixmap. This will automatically scale and stretch the source image to the * specified target rectangle. Use {@link Pixmap#setFilter(Filter)} to specify the type of filtering to be used (nearest * neighbour or bilinear). * - * @param pixmap The other Pixmap - * @param srcx The source x-coordinate (top left corner) - * @param srcy The source y-coordinate (top left corner); - * @param srcWidth The width of the area form the other Pixmap in pixels + * @param pixmap The other Pixmap + * @param srcx The source x-coordinate (top left corner) + * @param srcy The source y-coordinate (top left corner); + * @param srcWidth The width of the area form the other Pixmap in pixels * @param srcHeight The height of the area form the other Pixmap in pixles - * @param dstx The target x-coordinate (top left corner) - * @param dsty The target y-coordinate (top left corner) - * @param dstWidth The target width - * @param dstHeight the target height - */ - public void drawPixmap(Pixmap pixmap, int srcx, int srcy, int srcWidth, int srcHeight, int dstx, int dsty, int dstWidth, - int dstHeight) { - context.drawImage(pixmap.getCanvasElement(), srcx, srcy, srcWidth, srcHeight, dstx, dsty, dstWidth, dstHeight); + * @param dstx The target x-coordinate (top left corner) + * @param dsty The target y-coordinate (top left corner) + * @param dstWidth The target width + * @param dstHeight the target height */ + public void drawPixmap (Pixmap pixmap, int srcx, int srcy, int srcWidth, int srcHeight, int dstx, int dsty, int dstWidth, + int dstHeight) { + image(pixmap.getCanvasElement(), srcx, srcy, srcWidth, srcHeight, dstx, dsty, dstWidth, dstHeight); } - /** - * Fills a rectangle starting at x, y extending by width to the right and by height downwards (y-axis points downwards) using + /** Fills a rectangle starting at x, y extending by width to the right and by height downwards (y-axis points downwards) using * the current color. * - * @param x The x coordinate - * @param y The y coordinate - * @param width The width in pixels - * @param height The height in pixels - */ - public void fillRectangle(int x, int y, int width, int height) { - context.fillRect(x, y, width, height); + * @param x The x coordinate + * @param y The y coordinate + * @param width The width in pixels + * @param height The height in pixels */ + public void fillRectangle (int x, int y, int width, int height) { + rectangle(x, y, width, height, DrawType.FILL); } - /** - * Draws a circle outline with the center at x,y and a radius using the current color and stroke width. + /** Draws a circle outline with the center at x,y and a radius using the current color and stroke width. * - * @param x The x-coordinate of the center - * @param y The y-coordinate of the center - * @param radius The radius in pixels - */ - public void drawCircle(int x, int y, int radius) { - context.beginPath(); - context.arc(x, y, radius, 0, 2 * Math.PI, false); - context.stroke(); - context.closePath(); + * @param x The x-coordinate of the center + * @param y The y-coordinate of the center + * @param radius The radius in pixels */ + public void drawCircle (int x, int y, int radius) { + circle(x, y, radius, DrawType.STROKE); } - /** - * Fills a circle with the center at x,y and a radius using the current color. + /** Fills a circle with the center at x,y and a radius using the current color. * - * @param x The x-coordinate of the center - * @param y The y-coordinate of the center - * @param radius The radius in pixels - */ - public void fillCircle(int x, int y, int radius) { - context.beginPath(); - context.arc(x, y, radius, 0, 2 * Math.PI, false); - context.fill(); - context.closePath(); + * @param x The x-coordinate of the center + * @param y The y-coordinate of the center + * @param radius The radius in pixels */ + public void fillCircle (int x, int y, int radius) { + circle(x, y, radius, DrawType.FILL); } - /** - * Fills a triangle with vertices at x1,y1 and x2,y2 and x3,y3 using the current color. + /** Fills a triangle with vertices at x1,y1 and x2,y2 and x3,y3 using the current color. * * @param x1 The x-coordinate of vertex 1 * @param y1 The y-coordinate of vertex 1 * @param x2 The x-coordinate of vertex 2 * @param y2 The y-coordinate of vertex 2 * @param x3 The x-coordinate of vertex 3 - * @param y3 The y-coordinate of vertex 3 - */ - public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) { - context.beginPath(); - context.moveTo(x1, y1); - context.lineTo(x2, y2); - context.lineTo(x3, y3); - context.lineTo(x1, y1); - context.fill(); - context.closePath(); + * @param y3 The y-coordinate of vertex 3 */ + public void fillTriangle (int x1, int y1, int x2, int y2, int x3, int y3) { + triangle(x1, y1, x2, y2, x3, y3, DrawType.FILL); } - /** - * Returns the 32-bit RGBA8888 value of the pixel at x, y. For Alpha formats the RGB components will be one. + /** Returns the 32-bit RGBA8888 value of the pixel at x, y. For Alpha formats the RGB components will be one. * * @param x The x-coordinate * @param y The y-coordinate - * @return The pixel color in RGBA8888 format. - */ - public int getPixel(int x, int y) { + * @return The pixel color in RGBA8888 format. */ + public int getPixel (int x, int y) { + ensureCanvasExists(); if (pixels == null) pixels = context.getImageData(0, 0, width, height).getData(); int i = x * 4 + y * width * 4; int r = pixels.get(i + 0) & 0xff; @@ -402,26 +388,148 @@ public class Pixmap implements Disposable { return (r << 24) | (g << 16) | (b << 8) | (a); } - /** - * Draws a pixel at the given location with the current color. + /** Draws a pixel at the given location with the current color. + * + * @param x the x-coordinate + * @param y the y-coordinate */ + public void drawPixel (int x, int y) { + rectangle(x, y, 1, 1, DrawType.FILL); + } + + /** Draws a pixel at the given location with the given color. * * @param x the x-coordinate * @param y the y-coordinate - */ - public void drawPixel(int x, int y) { - context.fillRect(x, y, 1, 1); - } - - /** - * Draws a pixel at the given location with the given color. - * - * @param x the x-coordinate - * @param y the y-coordinate - * @param color the color in RGBA8888 format. - */ - public void drawPixel(int x, int y, int color) { + * @param color the color in RGBA8888 format. */ + public void drawPixel (int x, int y, int color) { setColor(color); drawPixel(x, y); } + private void circle (int x, int y, int radius, DrawType drawType) { + ensureCanvasExists(); + if (blending == Blending.None) { + context.setFillStyle(clearColor); + context.setStrokeStyle(clearColor); + context.setGlobalCompositeOperation("destination-out"); + context.beginPath(); + context.arc(x, y, radius, 0, 2 * Math.PI, false); + fillOrStrokePath(drawType); + context.closePath(); + context.setFillStyle(color); + context.setStrokeStyle(color); + context.setGlobalCompositeOperation(Composite.SOURCE_OVER); + } + context.beginPath(); + context.arc(x, y, radius, 0, 2 * Math.PI, false); + fillOrStrokePath(drawType); + context.closePath(); + pixels = null; + } + + private void line(int x, int y, int x2, int y2, DrawType drawType) { + ensureCanvasExists(); + if (blending == Blending.None) { + context.setFillStyle(clearColor); + context.setStrokeStyle(clearColor); + context.setGlobalCompositeOperation("destination-out"); + context.beginPath(); + context.moveTo(x, y); + context.lineTo(x2, y2); + fillOrStrokePath(drawType); + context.closePath(); + context.setFillStyle(color); + context.setStrokeStyle(color); + context.setGlobalCompositeOperation(Composite.SOURCE_OVER); + } + context.beginPath(); + context.moveTo(x, y); + context.lineTo(x2, y2); + fillOrStrokePath(drawType); + context.closePath(); + pixels = null; + } + + private void rectangle(int x, int y, int width, int height, DrawType drawType) { + ensureCanvasExists(); + if (blending == Blending.None) { + context.setFillStyle(clearColor); + context.setStrokeStyle(clearColor); + context.setGlobalCompositeOperation("destination-out"); + context.beginPath(); + context.rect(x, y, width, height); + fillOrStrokePath(drawType); + context.closePath(); + context.setFillStyle(color); + context.setStrokeStyle(color); + context.setGlobalCompositeOperation(Composite.SOURCE_OVER); + } + context.beginPath(); + context.rect(x, y, width, height); + fillOrStrokePath(drawType); + context.closePath(); + pixels = null; + } + + private void triangle(int x1, int y1, int x2, int y2, int x3, int y3, DrawType drawType) { + ensureCanvasExists(); + if (blending == Blending.None) { + context.setFillStyle(clearColor); + context.setStrokeStyle(clearColor); + context.setGlobalCompositeOperation("destination-out"); + context.beginPath(); + context.moveTo(x1,y1); + context.lineTo(x2,y2); + context.lineTo(x3,y3); + context.lineTo(x1,y1); + fillOrStrokePath(drawType); + context.closePath(); + context.setFillStyle(color); + context.setStrokeStyle(color); + context.setGlobalCompositeOperation(Composite.SOURCE_OVER); + } + context.beginPath(); + context.moveTo(x1,y1); + context.lineTo(x2,y2); + context.lineTo(x3,y3); + context.lineTo(x1,y1); + fillOrStrokePath(drawType); + context.closePath(); + pixels = null; + } + + private void image (CanvasElement image, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight) { + ensureCanvasExists(); + if (blending == Blending.None) { + context.setFillStyle(clearColor); + context.setStrokeStyle(clearColor); + context.setGlobalCompositeOperation("destination-out"); + context.beginPath(); + context.rect(dstX, dstY, dstWidth, dstHeight); + fillOrStrokePath(DrawType.FILL); + context.closePath(); + context.setFillStyle(color); + context.setStrokeStyle(color); + context.setGlobalCompositeOperation(Composite.SOURCE_OVER); + } + context.drawImage(image, srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight); + pixels = null; + } + + private void fillOrStrokePath(DrawType drawType) { + ensureCanvasExists(); + switch (drawType) { + case FILL: + context.fill(); + break; + case STROKE: + context.stroke(); + break; + } + } + + private enum DrawType { + FILL, STROKE + } + } diff --git a/vtm-web/src/org/oscim/gdx/emu/java/io/FileInputStream.java b/vtm-web/src/org/oscim/gdx/emu/java/io/FileInputStream.java new file mode 100644 index 00000000..e735a603 --- /dev/null +++ b/vtm-web/src/org/oscim/gdx/emu/java/io/FileInputStream.java @@ -0,0 +1,22 @@ +package java.io; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FileInputStream extends InputStream { + + static final Logger log = LoggerFactory.getLogger(FileInputStream.class); + + public FileInputStream(File f) { + + } + + public FileInputStream(String s) throws FileNotFoundException { + log.debug("FileInputStream {}", s); + } + + @Override + public int read() throws IOException { + return 0; + } +} diff --git a/vtm-web/src/org/oscim/gdx/resources/js/soundmanager2-nodebug-jsmin.js b/vtm-web/src/org/oscim/gdx/resources/js/soundmanager2-nodebug-jsmin.js new file mode 100755 index 00000000..d1614ed3 --- /dev/null +++ b/vtm-web/src/org/oscim/gdx/resources/js/soundmanager2-nodebug-jsmin.js @@ -0,0 +1,83 @@ +/** @license + * + * SoundManager 2: JavaScript Sound for the Web + * ---------------------------------------------- + * http://schillmania.com/projects/soundmanager2/ + * + * Copyright (c) 2007, Scott Schiller. All rights reserved. + * Code provided under the BSD License: + * http://schillmania.com/projects/soundmanager2/license.txt + * + * V2.97a.20150601 + */ +(function(h,g){function w(gb,w){function Z(b){return c.preferFlash&&A&&!c.ignoreFlash&&c.flash[b]!==g&&c.flash[b]}function r(b){return function(c){var d=this._s;return d&&d._a?b.call(this,c):null}}this.setupOptions={url:gb||null,flashVersion:8,debugMode:!0,debugFlash:!1,useConsole:!0,consoleOnly:!0,waitForWindowLoad:!1,bgColor:"#ffffff",useHighPerformance:!1,flashPollingInterval:null,html5PollingInterval:null,flashLoadTimeout:1E3,wmode:null,allowScriptAccess:"always",useFlashBlock:!1,useHTML5Audio:!0, +forceUseGlobalHTML5Audio:!1,ignoreMobileRestrictions:!1,html5Test:/^(probably|maybe)$/i,preferFlash:!1,noSWFCache:!1,idPrefix:"sound"};this.defaultOptions={autoLoad:!1,autoPlay:!1,from:null,loops:1,onid3:null,onload:null,whileloading:null,onplay:null,onpause:null,onresume:null,whileplaying:null,onposition:null,onstop:null,onfailure:null,onfinish:null,multiShot:!0,multiShotEvents:!1,position:null,pan:0,stream:!0,to:null,type:null,usePolicyFile:!1,volume:100};this.flash9Options={isMovieStar:null,usePeakData:!1, +useWaveformData:!1,useEQData:!1,onbufferchange:null,ondataerror:null};this.movieStarOptions={bufferTime:3,serverURL:null,onconnect:null,duration:null};this.audioFormats={mp3:{type:['audio/mpeg; codecs="mp3"',"audio/mpeg","audio/mp3","audio/MPA","audio/mpa-robust"],required:!0},mp4:{related:["aac","m4a","m4b"],type:['audio/mp4; codecs="mp4a.40.2"',"audio/aac","audio/x-m4a","audio/MP4A-LATM","audio/mpeg4-generic"],required:!1},ogg:{type:["audio/ogg; codecs=vorbis"],required:!1},opus:{type:["audio/ogg; codecs=opus", +"audio/opus"],required:!1},wav:{type:['audio/wav; codecs="1"',"audio/wav","audio/wave","audio/x-wav"],required:!1}};this.movieID="sm2-container";this.id=w||"sm2movie";this.debugID="soundmanager-debug";this.debugURLParam=/([#?&])debug=1/i;this.versionNumber="V2.97a.20150601";this.altURL=this.movieURL=this.version=null;this.enabled=this.swfLoaded=!1;this.oMC=null;this.sounds={};this.soundIDs=[];this.didFlashBlock=this.muted=!1;this.filePattern=null;this.filePatterns={flash8:/\.mp3(\?.*)?$/i,flash9:/\.mp3(\?.*)?$/i}; +this.features={buffering:!1,peakData:!1,waveformData:!1,eqData:!1,movieStar:!1};this.sandbox={};this.html5={usingFlash:null};this.flash={};this.ignoreFlash=this.html5Only=!1;var N,c=this,Oa=null,k=null,aa,u=navigator.userAgent,Pa=h.location.href.toString(),p=document,pa,Qa,qa,m,y=[],O=!1,P=!1,l=!1,B=!1,ra=!1,Q,x,sa,ba,ta,F,H,I,Ra,ua,va,ca,J,da,G,wa,R,xa,ea,K,Sa,ya,Ta,za,Ua,S=null,Aa=null,T,Ba,L,fa,ga,q,U=!1,Ca=!1,Va,Wa,Xa,ha=0,V=null,ia,W=[],X,v=null,Ya,ja,Y,D,ka,Da,Za,t,hb=Array.prototype.slice, +z=!1,Ea,A,Fa,$a,C,la,ab=0,Ga,Ha=u.match(/(ipad|iphone|ipod)/i),Ia=u.match(/android/i),E=u.match(/msie/i),ib=u.match(/webkit/i),ma=u.match(/safari/i)&&!u.match(/chrome/i),Ja=u.match(/opera/i),na=u.match(/(mobile|pre\/|xoom)/i)||Ha||Ia,bb=!Pa.match(/usehtml5audio/i)&&!Pa.match(/sm2\-ignorebadua/i)&&ma&&!u.match(/silk/i)&&u.match(/OS X 10_6_([3-7])/i),Ka=p.hasFocus!==g?p.hasFocus():null,oa=ma&&(p.hasFocus===g||!p.hasFocus()),cb=!oa,db=/(mp3|mp4|mpa|m4a|m4b)/i,La=p.location?p.location.protocol.match(/http/i): +null,jb=La?"":"http://",eb=/^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4||m4v|m4a|m4b|mp4v|3gp|3g2)\s*(?:$|;)/i,fb="mpeg4 aac flv mov mp4 m4v f4v m4a m4b mp4v 3gp 3g2".split(" "),kb=new RegExp("\\.("+fb.join("|")+")(\\?.*)?$","i");this.mimePattern=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.useAltURL=!La;var Ma;try{Ma=Audio!==g&&(Ja&&opera!==g&&10>opera.version()?new Audio(null):new Audio).canPlayType!==g}catch(lb){Ma=!1}this.hasHTML5=Ma;this.setup=function(b){var e=!c.url;b!==g&&l&&v&&c.ok(); +sa(b);if(!z)if(na){if(!c.setupOptions.ignoreMobileRestrictions||c.setupOptions.forceUseGlobalHTML5Audio)W.push(J.globalHTML5),z=!0}else c.setupOptions.forceUseGlobalHTML5Audio&&(W.push(J.globalHTML5),z=!0);if(!Ga&&na)if(c.setupOptions.ignoreMobileRestrictions)W.push(J.ignoreMobile);else if(c.setupOptions.useHTML5Audio=!0,c.setupOptions.preferFlash=!1,Ha)c.ignoreFlash=!0;else if(Ia&&!u.match(/android\s2\.3/i)||!Ia)z=!0;b&&(e&&R&&b.url!==g&&c.beginDelayedInit(),R||b.url===g||"complete"!==p.readyState|| +setTimeout(G,1));Ga=!0;return c};this.supported=this.ok=function(){return v?l&&!B:c.useHTML5Audio&&c.hasHTML5};this.getMovie=function(b){return aa(b)||p[b]||h[b]};this.createSound=function(b,e){function d(){a=fa(a);c.sounds[a.id]=new N(a);c.soundIDs.push(a.id);return c.sounds[a.id]}var a,f=null;if(!l||!c.ok())return!1;e!==g&&(b={id:b,url:e});a=x(b);a.url=ia(a.url);a.id===g&&(a.id=c.setupOptions.idPrefix+ab++);if(q(a.id,!0))return c.sounds[a.id];if(ja(a))f=d(),f._setup_html5(a);else{if(c.html5Only|| +c.html5.usingFlash&&a.url&&a.url.match(/data\:/i))return d();8a.instanceCount?(p(),f=a._setup_html5(),a.setPosition(a._iO.position),f.play()):(n=new Audio(a._iO.url),h=function(){t.remove(n,"ended",h);a._onfinish(a);ka(n);n=null},Na=function(){t.remove(n,"canplay",Na);try{n.currentTime= +a._iO.position/1E3}catch(b){}n.play()},t.add(n,"ended",h),a._iO.volume!==g&&(n.volume=Math.max(0,Math.min(1,a._iO.volume/100))),a.muted&&(n.muted=!0),a._iO.position?t.add(n,"canplay",Na):n.play()):(f=k._start(a.id,a._iO.loops||1,9===m?a.position:a.position/1E3,a._iO.multiShot||!1),9!==m||f||a._iO.onplayerror&&a._iO.onplayerror.apply(a))}return a};this.stop=function(b){var c=a._iO;1===a.playState&&(a._onbufferchange(0),a._resetOnPosition(0),a.paused=!1,a.isHTML5||(a.playState=0),y(),c.to&&a.clearOnPosition(c.to), +a.isHTML5?a._a&&(b=a.position,a.setPosition(0),a.position=b,a._a.pause(),a.playState=0,a._onTimer(),M()):(k._stop(a.id,b),c.serverURL&&a.unload()),a.instanceCount=0,a._iO={},c.onstop&&c.onstop.apply(a));return a};this.setAutoPlay=function(b){a._iO.autoPlay=b;a.isHTML5||(k._setAutoPlay(a.id,b),b&&(a.instanceCount||1!==a.readyState||a.instanceCount++))};this.getAutoPlay=function(){return a._iO.autoPlay};this.setPosition=function(b){b===g&&(b=0);var c=a.isHTML5?Math.max(b,0):Math.min(a.duration||a._iO.duration, +Math.max(b,0));a.position=c;b=a.position/1E3;a._resetOnPosition(a.position);a._iO.position=c;if(!a.isHTML5)b=9===m?a.position:b,a.readyState&&2!==a.readyState&&k._setPosition(a.id,b,a.paused||!a.playState,a._iO.multiShot);else if(a._a){if(a._html5_canplay){if(a._a.currentTime!==b)try{a._a.currentTime=b,(0===a.playState||a.paused)&&a._a.pause()}catch(e){}}else if(b)return a;a.paused&&a._onTimer(!0)}return a};this.pause=function(b){if(a.paused||0===a.playState&&1!==a.readyState)return a;a.paused=!0; +a.isHTML5?(a._setup_html5().pause(),M()):(b||b===g)&&k._pause(a.id,a._iO.multiShot);a._iO.onpause&&a._iO.onpause.apply(a);return a};this.resume=function(){var b=a._iO;if(!a.paused)return a;a.paused=!1;a.playState=1;a.isHTML5?(a._setup_html5().play(),p()):(b.isMovieStar&&!b.serverURL&&a.setPosition(a.position),k._pause(a.id,b.multiShot));!u&&b.onplay?(b.onplay.apply(a),u=!0):b.onresume&&b.onresume.apply(a);return a};this.togglePause=function(){if(0===a.playState)return a.play({position:9!==m||a.isHTML5? +a.position/1E3:a.position}),a;a.paused?a.resume():a.pause();return a};this.setPan=function(b,c){b===g&&(b=0);c===g&&(c=!1);a.isHTML5||k._setPan(a.id,b);a._iO.pan=b;c||(a.pan=b,a.options.pan=b);return a};this.setVolume=function(b,e){b===g&&(b=100);e===g&&(e=!1);a.isHTML5?a._a&&(c.muted&&!a.muted&&(a.muted=!0,a._a.muted=!0),a._a.volume=Math.max(0,Math.min(1,b/100))):k._setVolume(a.id,c.muted&&!a.muted||a.muted?0:b);a._iO.volume=b;e||(a.volume=b,a.options.volume=b);return a};this.mute=function(){a.muted= +!0;a.isHTML5?a._a&&(a._a.muted=!0):k._setVolume(a.id,0);return a};this.unmute=function(){a.muted=!1;var b=a._iO.volume!==g;a.isHTML5?a._a&&(a._a.muted=!1):k._setVolume(a.id,b?a._iO.volume:a.options.volume);return a};this.toggleMute=function(){return a.muted?a.unmute():a.mute()};this.onposition=this.onPosition=function(b,c,e){l.push({position:parseInt(b,10),method:c,scope:e!==g?e:a,fired:!1});return a};this.clearOnPosition=function(a,b){var c;a=parseInt(a,10);if(isNaN(a))return!1;for(c=0;c=b)return!1;for(--b;0<=b;b--)c=l[b],!c.fired&&a.position>=c.position&&(c.fired=!0,v++,c.method.apply(c.scope,[c.position]));return!0};this._resetOnPosition=function(a){var b,c;b=l.length;if(!b)return!1;for(--b;0<=b;b--)c=l[b],c.fired&&a<=c.position&&(c.fired=!1,v--);return!0};B=function(){var b=a._iO,c=b.from,e=b.to,d,f;f=function(){a.clearOnPosition(e,f); +a.stop()};d=function(){if(null!==e&&!isNaN(e))a.onPosition(e,f)};null===c||isNaN(c)||(b.position=c,b.multiShot=!1,d());return b};r=function(){var b,c=a._iO.onposition;if(c)for(b in c)if(c.hasOwnProperty(b))a.onPosition(parseInt(b,10),c[b])};y=function(){var b,c=a._iO.onposition;if(c)for(b in c)c.hasOwnProperty(b)&&a.clearOnPosition(parseInt(b,10))};p=function(){a.isHTML5&&Va(a)};M=function(){a.isHTML5&&Wa(a)};f=function(b){b||(l=[],v=0);u=!1;a._hasTimer=null;a._a=null;a._html5_canplay=!1;a.bytesLoaded= +null;a.bytesTotal=null;a.duration=a._iO&&a._iO.duration?a._iO.duration:null;a.durationEstimate=null;a.buffered=[];a.eqData=[];a.eqData.left=[];a.eqData.right=[];a.failures=0;a.isBuffering=!1;a.instanceOptions={};a.instanceCount=0;a.loaded=!1;a.metadata={};a.readyState=0;a.muted=!1;a.paused=!1;a.peakData={left:0,right:0};a.waveformData={left:[],right:[]};a.playState=0;a.position=null;a.id3={}};f();this._onTimer=function(b){var c,f=!1,g={};if(a._hasTimer||b)return a._a&&(b||(0opera.version()?new Audio(null):new Audio,c=a._a,c._called_load=!1,z&&(Oa=c);a.isHTML5=!0;a._a=c;c._s=a;n();a._apply_loop(c,b.loops);b.autoLoad||b.autoPlay?a.load():(c.autobuffer=!1,c.preload="auto");return c};n=function(){if(a._a._added_events)return!1; +var b;a._a._added_events=!0;for(b in C)C.hasOwnProperty(b)&&a._a&&a._a.addEventListener(b,C[b],!1);return!0};h=function(){var b;a._a._added_events=!1;for(b in C)C.hasOwnProperty(b)&&a._a&&a._a.removeEventListener(b,C[b],!1)};this._onload=function(b){var c=!!b||!a.isHTML5&&8===m&&a.duration;a.loaded=c;a.readyState=c?3:2;a._onbufferchange(0);a._iO.onload&&la(a,function(){a._iO.onload.apply(a,[c])});return!0};this._onbufferchange=function(b){if(0===a.playState||b&&a.isBuffering||!b&&!a.isBuffering)return!1; +a.isBuffering=1===b;a._iO.onbufferchange&&a._iO.onbufferchange.apply(a,[b]);return!0};this._onsuspend=function(){a._iO.onsuspend&&a._iO.onsuspend.apply(a);return!0};this._onfailure=function(b,c,e){a.failures++;if(a._iO.onfailure&&1===a.failures)a._iO.onfailure(b,c,e)};this._onwarning=function(b,c,e){if(a._iO.onwarning)a._iO.onwarning(b,c,e)};this._onfinish=function(){var b=a._iO.onfinish;a._onbufferchange(0);a._resetOnPosition(0);a.instanceCount&&(a.instanceCount--,a.instanceCount||(y(),a.playState= +0,a.paused=!1,a.instanceCount=0,a.instanceOptions={},a._iO={},M(),a.isHTML5&&(a.position=0)),(!a.instanceCount||a._iO.multiShotEvents)&&b&&la(a,function(){b.apply(a)}))};this._whileloading=function(b,c,e,d){var f=a._iO;a.bytesLoaded=b;a.bytesTotal=c;a.duration=Math.floor(e);a.bufferLength=d;a.durationEstimate=a.isHTML5||f.isMovieStar?a.duration:f.duration?a.duration>f.duration?a.duration:f.duration:parseInt(a.bytesTotal/a.bytesLoaded*a.duration,10);a.isHTML5||(a.buffered=[{start:0,end:a.duration}]); +(3!==a.readyState||a.isHTML5)&&f.whileloading&&f.whileloading.apply(a)};this._whileplaying=function(b,c,e,d,f){var n=a._iO;if(isNaN(b)||null===b)return!1;a.position=Math.max(0,b);a._processOnPosition();!a.isHTML5&&8opera.version()?new Audio(null):new Audio:null,d,a,f={},n,h;n=c.audioFormats;for(d in n)if(n.hasOwnProperty(d)&& +(a="audio/"+d,f[d]=b(n[d].type),f[a]=f[d],d.match(db)?(c.flash[d]=!0,c.flash[a]=!0):(c.flash[d]=!1,c.flash[a]=!1),n[d]&&n[d].related))for(h=n[d].related.length-1;0<=h;h--)f["audio/"+n[d].related[h]]=f[d],c.html5[n[d].related[h]]=f[d],c.flash[n[d].related[h]]=f[d];f.canPlayType=e?b:null;c.html5=x(c.html5,f);c.html5.usingFlash=Ya();v=c.html5.usingFlash;return!0};J={};T=function(){};fa=function(b){8===m&&1m&&(c.flashVersion=m=9);c.version=c.versionNumber+(c.html5Only?" (HTML5-only mode)":9===m?" (AS3/Flash 9)":" (AS2/Flash 8)");8'}if(O&&P)return!1;if(c.html5Only)return va(),c.oMC=aa(c.movieID),qa(),P=O=!0,!1;var a=e||c.url,f=c.altURL||a,h=xa(),k=L(),m=null,m=p.getElementsByTagName("html")[0],l,r,q,m=m&&m.dir&&m.dir.match(/rtl/i);b=b===g?c.id:b;va();c.url=Ua(La?a:f);e=c.url;c.wmode=!c.wmode&&c.useHighPerformance?"transparent":c.wmode; +null!==c.wmode&&(u.match(/msie 8/i)||!E&&!c.useHighPerformance)&&navigator.platform.match(/win32|win64/i)&&(W.push(J.spcWmode),c.wmode=null);h={name:b,id:b,src:e,quality:"high",allowScriptAccess:c.allowScriptAccess,bgcolor:c.bgColor,pluginspage:jb+"www.macromedia.com/go/getflashplayer",title:"JS/Flash audio component (SoundManager 2)",type:"application/x-shockwave-flash",wmode:c.wmode,hasPriority:"true"};c.debugFlash&&(h.FlashVars="debug=1");c.wmode||delete h.wmode;if(E)a=p.createElement("div"),r= +['',d("movie",e),d("AllowScriptAccess",c.allowScriptAccess),d("quality",h.quality),c.wmode?d("wmode",c.wmode):"",d("bgcolor",c.bgColor),d("hasPriority","true"),c.debugFlash?d("FlashVars",h.FlashVars):"",""].join("");else for(l in a=p.createElement("embed"),h)h.hasOwnProperty(l)&& +a.setAttribute(l,h[l]);ya();k=L();if(h=xa())if(c.oMC=aa(c.movieID)||p.createElement("div"),c.oMC.id)q=c.oMC.className,c.oMC.className=(q?q+" ":"movieContainer")+(k?" "+k:""),c.oMC.appendChild(a),E&&(l=c.oMC.appendChild(p.createElement("div")),l.className="sm2-object-box",l.innerHTML=r),P=!0;else{c.oMC.id=c.movieID;c.oMC.className="movieContainer "+k;l=k=null;c.useFlashBlock||(c.useHighPerformance?k={position:"fixed",width:"8px",height:"8px",bottom:"0px",left:"0px",overflow:"hidden"}:(k={position:"absolute", +width:"6px",height:"6px",top:"-9999px",left:"-9999px"},m&&(k.left=Math.abs(parseInt(k.left,10))+"px")));ib&&(c.oMC.style.zIndex=1E4);if(!c.debugFlash)for(q in k)k.hasOwnProperty(q)&&(c.oMC.style[q]=k[q]);try{E||c.oMC.appendChild(a),h.appendChild(c.oMC),E&&(l=c.oMC.appendChild(p.createElement("div")),l.className="sm2-object-box",l.innerHTML=r),P=!0}catch(t){throw Error(T("domError")+" \n"+t.toString());}}return O=!0};da=function(){if(c.html5Only)return ea(),!1;if(k||!c.url)return!1;k=c.getMovie(c.id); +k||(S?(E?c.oMC.innerHTML=Aa:c.oMC.appendChild(S),S=null,O=!0):ea(c.id,c.url),k=c.getMovie(c.id));"function"===typeof c.oninitmovie&&setTimeout(c.oninitmovie,1);return!0};I=function(){setTimeout(Ra,1E3)};ua=function(){h.setTimeout(function(){c.setup({preferFlash:!1}).reboot();c.didFlashBlock=!0;c.beginDelayedInit()},1)};Ra=function(){var b,e=!1;if(!c.url||U)return!1;U=!0;t.remove(h,"load",I);if(A&&oa&&!Ka)return!1;l||(b=c.getMoviePercent(),0b&&(e=!0));setTimeout(function(){b=c.getMoviePercent(); +if(e)return U=!1,h.setTimeout(I,1),!1;!l&&cb&&(null===b?c.useFlashBlock||0===c.flashLoadTimeout?c.useFlashBlock&&Ba():!c.useFlashBlock&&X?ua():F({type:"ontimeout",ignoreInit:!0,error:{type:"INIT_FLASHBLOCK"}}):0!==c.flashLoadTimeout&&(!c.useFlashBlock&&X?ua():za(!0)))},c.flashLoadTimeout)};ca=function(){if(Ka||!oa)return t.remove(h,"focus",ca),!0;Ka=cb=!0;U=!1;I();t.remove(h,"focus",ca);return!0};Q=function(b){if(l)return!1;if(c.html5Only)return l=!0,H(),!0;var e=!0,d;c.useFlashBlock&&c.flashLoadTimeout&& +!c.getMoviePercent()||(l=!0);d={type:!A&&v?"NO_FLASH":"INIT_TIMEOUT"};if(B||b)c.useFlashBlock&&c.oMC&&(c.oMC.className=L()+" "+(null===c.getMoviePercent()?"swf_timedout":"swf_error")),F({type:"ontimeout",error:d,ignoreInit:!0}),K(d),e=!1;B||(c.waitForWindowLoad&&!ra?t.add(h,"load",H):H());return e};Qa=function(){var b,e=c.setupOptions;for(b in e)e.hasOwnProperty(b)&&(c[b]===g?c[b]=e[b]:c[b]!==e[b]&&(c.setupOptions[b]=c[b]))};qa=function(){if(l)return!1;if(c.html5Only)return l||(t.remove(h,"load", +c.beginDelayedInit),c.enabled=!0,Q()),!0;da();try{k._externalInterfaceTest(!1),Sa(!0,c.flashPollingInterval||(c.useHighPerformance?10:50)),c.debugMode||k._disableDebug(),c.enabled=!0,c.html5Only||t.add(h,"unload",pa)}catch(b){return K({type:"JS_TO_FLASH_EXCEPTION",fatal:!0}),za(!0),Q(),!1}Q();t.remove(h,"load",c.beginDelayedInit);return!0};G=function(){if(R)return!1;R=!0;Qa();ya();!A&&c.hasHTML5&&c.setup({useHTML5Audio:!0,preferFlash:!1});Za();!A&&v&&(W.push(J.needFlash),c.setup({flashLoadTimeout:1})); +p.removeEventListener&&p.removeEventListener("DOMContentLoaded",G,!1);da();return!0};Da=function(){"complete"===p.readyState&&(G(),p.detachEvent("onreadystatechange",Da));return!0};wa=function(){ra=!0;G();t.remove(h,"load",wa)};Fa();t.add(h,"focus",ca);t.add(h,"load",I);t.add(h,"load",wa);p.addEventListener?p.addEventListener("DOMContentLoaded",G,!1):p.attachEvent?p.attachEvent("onreadystatechange",Da):K({type:"NO_DOM2_EVENTS",fatal:!0})}if(!h||!h.document)throw Error("SoundManager requires a browser with window and document objects."); +var N=null;h.SM2_DEFER!==g&&SM2_DEFER||(N=new w);"object"===typeof module&&module&&"object"===typeof module.exports?(module.exports.SoundManager=w,module.exports.soundManager=N):"function"===typeof define&&define.amd&&define(function(){return{constructor:w,getInstance:function(g){!h.soundManager&&g instanceof Function&&(g=g(w),g instanceof w&&(h.soundManager=g));return h.soundManager}}});h.SoundManager=w;h.soundManager=N})(window); \ No newline at end of file