private void refresh() { long currTimeStamp = System.currentTimeMillis(); deltaTime = (currTimeStamp - lastTimeStamp) / 1000.0; lastTimeStamp = currTimeStamp; time += deltaTime; frames++; if (time > 1) { this.fps = frames; time = 0; frames = 0; } }
public class GwtRenderingContext implements ResizeHandler, RenderingContext, AnimationScheduler.AnimationCallback { /** The ID of the pending animation request. */ private AnimationScheduler.AnimationHandle animationHandle; Panel root; CanvasElement canvas; WebGLRenderingContext context; GLRenderer renderer; GL20 gl; GwtInput input; Animation listener; List<AnimationReadyListener> animationReadyListener = new ArrayList<>(); int lastWidth; int lastHeight; double fps = 0; long lastTimeStamp = System.currentTimeMillis(); long frameId = -1; double deltaTime = 0; double time = 0; int frames; GwtAppConfiguration config; public GwtRenderingContext(Panel root, GwtAppConfiguration config) throws ParallaxRuntimeException { this.root = root; root.clear(); Canvas canvasWidget = Canvas.createIfSupported(); if (canvasWidget == null) throw new ParallaxRuntimeException("Canvas not supported"); int width = root.getOffsetWidth(); int height = root.getOffsetHeight(); if (width == 0 || height == 0) new ParallaxRuntimeException("Width or Height of the Panel is 0"); lastWidth = width; lastHeight = height; canvas = canvasWidget.getCanvasElement(); root.add(canvasWidget); canvas.setWidth(width); canvas.setHeight(height); this.config = config; WebGLContextAttributes attributes = WebGLContextAttributes.create(); attributes.setAntialias(config.antialiasing); attributes.setStencil(config.stencil); attributes.setAlpha(config.alpha); attributes.setPremultipliedAlpha(config.premultipliedAlpha); attributes.setPreserveDrawingBuffer(config.preserveDrawingBuffer); context = WebGLRenderingContext.getContext(canvas, attributes); context.viewport(0, 0, width, height); gl = new GwtGL20(context); renderer = new GLRenderer(gl, width, height); input = new GwtInput(canvas); addEventListeners(); Window.addResizeHandler(this); } @Override public void setAnimation(Animation animation) { this.listener = animation; // tell listener about app creation try { renderer.setDefaultGLState(); if (listener instanceof InputHandler) input.setInputHandler((InputHandler) listener); listener.onStart(this); listener.onResize(this); for (AnimationReadyListener ready : animationReadyListener) ready.onAnimationReady(listener); } catch (Throwable t) { Log.error("GwtRendering: exception: " + t.getMessage(), t); t.printStackTrace(); throw new ParallaxRuntimeException(t); } run(); } private void refresh() { long currTimeStamp = System.currentTimeMillis(); deltaTime = (currTimeStamp - lastTimeStamp) / 1000.0; lastTimeStamp = currTimeStamp; time += deltaTime; frames++; if (time > 1) { this.fps = frames; time = 0; frames = 0; } } @Override public void execute(double timestamp) { try { mainLoop(); } catch (Throwable t) { Log.error("GwtApplication: exception: " + t.getMessage(), t); throw new ParallaxRuntimeException(t); } animationHandle = AnimationScheduler.get().requestAnimationFrame(this, canvas); } private void mainLoop() { refresh(); frameId++; this.listener.onUpdate(this); } @Override public void onResize(ResizeEvent resizeEvent) { Scheduler.get() .scheduleDeferred( new Scheduler.ScheduledCommand() { @Override public void execute() { lastWidth = getWidth(); lastHeight = getHeight(); if (lastWidth > 0 && lastHeight > 0) { if (!GwtRenderingContext.this.isRun()) GwtRenderingContext.this.run(); ViewportResizeBus.onViewportResize(lastWidth, lastHeight); GwtRenderingContext.this.canvas.setWidth(lastWidth); GwtRenderingContext.this.canvas.setHeight(lastHeight); GwtRenderingContext.this.renderer.setSize(lastWidth, lastHeight); GwtRenderingContext.this.listener.onResize(GwtRenderingContext.this); } else { GwtRenderingContext.this.stop(); } } }); } @Override public void stop() { // Cancel the animation request. if (this.animationHandle != null) { this.animationHandle.cancel(); this.animationHandle = null; } } @Override public void run() { stop(); // Execute the first callback. AnimationScheduler.get().requestAnimationFrame(this, this.canvas); } @Override public boolean isRun() { return (this.animationHandle != null); } private native void addEventListeners() /*-{ var self = this; $doc.addEventListener('visibilitychange', function (e) { [email protected]::onVisibilityChange(Z)($doc['hidden'] !== true); }); }-*/; private void onVisibilityChange(boolean visible) { if (visible) { run(); } else { stop(); } } @Override public void addAnimationReadyListener(AnimationReadyListener animationReadyListener) { this.animationReadyListener.add(animationReadyListener); } public WebGLRenderingContext getContext() { return context; } @Override public GLRenderer getRenderer() { return renderer; } @Override public Input getInput() { return input; } @Override public GL20 getGL20() { return gl; } @Override public int getWidth() { return root.getOffsetWidth(); } @Override public int getHeight() { return root.getOffsetHeight(); } @Override public long getFrameId() { return frameId; } @Override public double getDeltaTime() { return deltaTime; } @Override public int getFramesPerSecond() { return (int) fps; } @Override public float getPpiX() { return 96; } @Override public float getPpiY() { return 96; } @Override public float getDensity() { return 96.0f / 160; } @Override public double getRawDeltaTime() { return getDeltaTime(); } @Override public boolean supportsDisplayModeChange() { 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; }-*/; private native int getScreenWidthJSNI() /*-{ return $wnd.screen.width; }-*/; private native int getScreenHeightJSNI() /*-{ return $wnd.screen.height; }-*/; 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(); }-*/; private void fullscreenChanged() { if (!isFullscreen()) { renderer.setSize(lastWidth, lastHeight); } } @Override public void setFullscreen() { if (isFullscreenJSNI()) exitFullscreen(); else setFullscreenJSNI(this, canvas); } private native boolean setFullscreenJSNI( GwtRenderingContext 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.@org.parallax3d.parallax.platforms.gwt.GwtRenderingContext::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; element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); $doc.addEventListener( "webkitfullscreenchange", function () { graphics.@org.parallax3d.parallax.platforms.gwt.GwtRenderingContext::fullscreenChanged()(); }, false); return true; } if (element.mozRequestFullScreen) { element.width = $wnd.screen.width; element.height = $wnd.screen.height; element.mozRequestFullScreen(); $doc.addEventListener( "mozfullscreenchange", function () { graphics.@org.parallax3d.parallax.platforms.gwt.GwtRenderingContext::fullscreenChanged()(); }, false); return true; } if (element.msRequestFullscreen) { element.width = $wnd.screen.width; element.height = $wnd.screen.height; element.msRequestFullscreen(); $doc.addEventListener( "msfullscreenchange", function () { graphics.@org.parallax3d.parallax.platforms.gwt.GwtRenderingContext::fullscreenChanged()(); }, false); return true; } return false; }-*/; @Override public boolean isFullscreen() { return isFullscreenJSNI(); } 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; } if ("mozFullScreen" in $doc) { return $doc.mozFullScreen; } return false }-*/; }