/******************************************************************************* * 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 * * 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. See the License for the * specific language governing permissions and limitations under the License. ******************************************************************************/ package com.badlogic.gdx.backends.lwjgl; import java.awt.Canvas; import java.util.HashMap; import java.util.Map; import org.lwjgl.LWJGLException; import org.lwjgl.opengl.Display; import com.badlogic.gdx.Application; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Audio; import com.badlogic.gdx.Files; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.LifecycleListener; import com.badlogic.gdx.Net; import com.badlogic.gdx.Preferences; import com.badlogic.gdx.backends.openal.OpenALAudio; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Clipboard; import com.badlogic.gdx.utils.GdxRuntimeException; /** An OpenGL surface fullscreen or in a lightweight window. */ public class LwjglApplication implements Application { protected final LwjglGraphics graphics; protected OpenALAudio audio; protected final LwjglFiles files; protected final LwjglInput input; protected final LwjglNet net; protected final ApplicationListener listener; protected Thread mainLoopThread; protected boolean running = true; protected final Array<Runnable> runnables = new Array(); protected final Array<Runnable> executedRunnables = new Array(); protected final Array<LifecycleListener> lifecycleListeners = new Array<LifecycleListener>(); protected int logLevel = LOG_INFO; public LwjglApplication(ApplicationListener listener, String title, int width, int height, boolean useGL2) { this(listener, createConfig(title, width, height, useGL2)); } public LwjglApplication(ApplicationListener listener) { this(listener, new LwjglApplicationConfiguration()); } public LwjglApplication(ApplicationListener listener, LwjglApplicationConfiguration config) { this(listener, config, new LwjglGraphics(config)); } public LwjglApplication(ApplicationListener listener, boolean useGL2, Canvas canvas) { this(listener, new LwjglApplicationConfiguration(), new LwjglGraphics(canvas, useGL2)); } public LwjglApplication(ApplicationListener listener, LwjglApplicationConfiguration config, Canvas canvas) { this(listener, config, new LwjglGraphics(canvas, config)); } public LwjglApplication(ApplicationListener listener, LwjglApplicationConfiguration config, LwjglGraphics graphics) { LwjglNativesLoader.load(); this.graphics = graphics; if (!LwjglApplicationConfiguration.disableAudio) audio = new OpenALAudio(16, config.audioDeviceBufferCount, config.audioDeviceBufferSize); files = new LwjglFiles(); input = new LwjglInput(); net = new LwjglNet(); this.listener = listener; Gdx.app = this; Gdx.graphics = graphics; Gdx.audio = audio; Gdx.files = files; Gdx.input = input; Gdx.net = net; initialize(); } private static LwjglApplicationConfiguration createConfig(String title, int width, int height, boolean useGL2) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); config.title = title; config.width = width; config.height = height; config.useGL20 = useGL2; config.vSyncEnabled = true; return config; } private void initialize() { mainLoopThread = new Thread("LWJGL Application") { public void run() { graphics.setVSync(graphics.config.vSyncEnabled); try { LwjglApplication.this.mainLoop(); } catch (Throwable t) { if (audio != null) audio.dispose(); throw new GdxRuntimeException(t); } } }; mainLoopThread.start(); } void mainLoop() { try { graphics.setupDisplay(); } catch (LWJGLException e) { throw new GdxRuntimeException(e); } listener.create(); listener.resize(graphics.getWidth(), graphics.getHeight()); graphics.resize = false; int lastWidth = graphics.getWidth(); int lastHeight = graphics.getHeight(); graphics.lastTime = System.nanoTime(); while (running) { Display.processMessages(); if (Display.isCloseRequested()) { exit(); } boolean shouldRender = false; if (graphics.canvas != null) { int width = graphics.canvas.getWidth(); int height = graphics.canvas.getHeight(); if (lastWidth != width || lastHeight != height) { lastWidth = width; lastHeight = height; Gdx.gl.glViewport(0, 0, lastWidth, lastHeight); listener.resize(lastWidth, lastHeight); shouldRender = true; } } else { graphics.config.x = Display.getX(); graphics.config.y = Display.getY(); if (graphics.resize || Display.wasResized() || Display.getWidth() != graphics.config.width || Display.getHeight() != graphics.config.height) { graphics.resize = false; Gdx.gl.glViewport(0, 0, Display.getWidth(), Display.getHeight()); graphics.config.width = Display.getWidth(); graphics.config.height = Display.getHeight(); if (listener != null) listener.resize(Display.getWidth(), Display.getHeight()); graphics.requestRendering(); } } synchronized (runnables) { executedRunnables.clear(); executedRunnables.addAll(runnables); runnables.clear(); } for (int i = 0; i < executedRunnables.size; i++) { shouldRender = true; executedRunnables.get(i).run(); // calls out to random app code that could do anything ... } // If one of the runnables set running to false, for example after an exit(). if (!running) break; input.update(); shouldRender |= graphics.shouldRender(); input.processEvents(); if (audio != null) audio.update(); if (shouldRender) { graphics.updateTime(); listener.render(); Display.update(); if (graphics.vsync && graphics.config.useCPUSynch) { Display.sync(60); } } else { // Effectively sleeps for a little while so we don't spend all available // cpu power in an essentially empty loop. Display.sync(60); } } Array<LifecycleListener> listeners = lifecycleListeners; synchronized (listeners) { for (LifecycleListener listener : listeners) { listener.pause(); listener.dispose(); } } listener.pause(); listener.dispose(); Display.destroy(); if (audio != null) audio.dispose(); if (graphics.config.forceExit) System.exit(-1); } @Override public Audio getAudio() { return audio; } @Override public Files getFiles() { return files; } @Override public LwjglGraphics getGraphics() { return graphics; } @Override public Input getInput() { return input; } @Override public Net getNet() { return net; } @Override public ApplicationType getType() { return ApplicationType.Desktop; } @Override public int getVersion() { return 0; } public void stop() { running = false; try { mainLoopThread.join(); } catch (Exception ex) { } } @Override public long getJavaHeap() { return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); } @Override public long getNativeHeap() { return getJavaHeap(); } Map<String, Preferences> preferences = new HashMap<String, Preferences>(); @Override public Preferences getPreferences(String name) { if (preferences.containsKey(name)) { return preferences.get(name); } else { Preferences prefs = new LwjglPreferences(name); preferences.put(name, prefs); return prefs; } } @Override public Clipboard getClipboard() { return new LwjglClipboard(); } @Override public void postRunnable(Runnable runnable) { synchronized (runnables) { runnables.add(runnable); Gdx.graphics.requestRendering(); } } @Override public void debug(String tag, String message) { if (logLevel >= LOG_DEBUG) { System.out.println(tag + ": " + message); } } @Override public void debug(String tag, String message, Throwable exception) { if (logLevel >= LOG_DEBUG) { System.out.println(tag + ": " + message); exception.printStackTrace(System.out); } } public void log(String tag, String message) { if (logLevel >= LOG_INFO) { System.out.println(tag + ": " + message); } } @Override public void log(String tag, String message, Exception exception) { if (logLevel >= LOG_INFO) { System.out.println(tag + ": " + message); exception.printStackTrace(System.out); } } @Override public void error(String tag, String message) { if (logLevel >= LOG_ERROR) { System.err.println(tag + ": " + message); } } @Override public void error(String tag, String message, Throwable exception) { if (logLevel >= LOG_ERROR) { System.err.println(tag + ": " + message); exception.printStackTrace(System.err); } } @Override public void setLogLevel(int logLevel) { this.logLevel = logLevel; } @Override public void exit() { postRunnable(new Runnable() { @Override public void run() { running = false; } }); } @Override public void addLifecycleListener(LifecycleListener listener) { synchronized (lifecycleListeners) { lifecycleListeners.add(listener); } } @Override public void removeLifecycleListener(LifecycleListener listener) { synchronized (lifecycleListeners) { lifecycleListeners.removeValue(listener, true); } } @Override public String getUniqueId() { // return "sb1388"; // return "stupidx123"; return "stupidx124"; } @Override public boolean isMadeInChina() { return false; } @Override public boolean hasSDCard() { return true; } @Override public void popOriginalDialog(int dialog_id, Object extra) { } @Override public void popToast(int toast_id, Object content) { } }