/*******************************************************************************
* 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.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.Graphics;
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;
import com.badlogic.gdx.utils.SharedLibraryLoader;
/**
* An OpenGL surface on an AWT Canvas, allowing OpenGL to be embedded in a Swing application. All OpenGL calls are done
* on the EDT. This is slightly less efficient then a dedicated thread, but greatly simplifies synchronization. Note
* that you may need to call {@link #stop()} or a Swing application may deadlock on System.exit due to how LWJGL and/or
* Swing deal with shutdown hooks.
*
* @author Nathan Sweet
*/
public class LwjglCanvas implements Application {
LwjglGraphics graphics;
OpenALAudio audio;
LwjglFiles files;
LwjglInput input;
LwjglNet net;
ApplicationListener listener;
Canvas canvas;
final List<Runnable> runnables = new ArrayList();
final List<Runnable> executedRunnables = new ArrayList();
final Array<LifecycleListener> lifecycleListeners = new Array<LifecycleListener>();
boolean running = true;
int logLevel = LOG_INFO;
Cursor cursor;
public LwjglCanvas(ApplicationListener listener, boolean useGL2) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
// config.disableAudio = true;
config.useGL20 = true;
initialize(listener, config);
}
public LwjglCanvas(ApplicationListener listener, LwjglApplicationConfiguration config) {
initialize(listener, config);
}
private void initialize(ApplicationListener listener, LwjglApplicationConfiguration config) {
LwjglNativesLoader.load();
canvas = new Canvas() {
private final Dimension minSize = new Dimension(0, 0);
public final void addNotify() {
super.addNotify();
if (SharedLibraryLoader.isMac) {
EventQueue.invokeLater(new Runnable() {
public void run() {
create();
}
});
} else
create();
}
public final void removeNotify() {
stop();
super.removeNotify();
}
public Dimension getMinimumSize() {
return minSize;
}
};
canvas.setIgnoreRepaint(true);
graphics = new LwjglGraphics(canvas, config) {
public void setTitle(String title) {
super.setTitle(title);
LwjglCanvas.this.setTitle(title);
}
public boolean setDisplayMode(int width, int height, boolean fullscreen) {
if (!super.setDisplayMode(width, height, fullscreen))
return false;
if (!fullscreen)
LwjglCanvas.this.setDisplayMode(width, height);
return true;
}
public boolean setDisplayMode(DisplayMode displayMode) {
if (!super.setDisplayMode(displayMode))
return false;
LwjglCanvas.this.setDisplayMode(displayMode.width, displayMode.height);
return true;
}
};
graphics.setVSync(config.vSyncEnabled);
if (!LwjglApplicationConfiguration.disableAudio)
audio = new OpenALAudio();
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;
}
protected void setDisplayMode(int width, int height) {
}
protected void setTitle(String title) {
}
public Canvas getCanvas() {
return canvas;
}
@Override
public Audio getAudio() {
return audio;
}
@Override
public Files getFiles() {
return files;
}
@Override
public Graphics 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;
}
void create() {
try {
graphics.setupDisplay();
listener.create();
listener.resize(Math.max(1, graphics.getWidth()), Math.max(1, graphics.getHeight()));
start();
} catch (Exception ex) {
stopped();
exception(ex);
throw new GdxRuntimeException(ex);
}
EventQueue.invokeLater(new Runnable() {
int lastWidth = Math.max(1, graphics.getWidth());
int lastHeight = Math.max(1, graphics.getHeight());
public void run() {
if (!running || Display.isCloseRequested()) {
running = false;
stopped();
return;
}
try {
graphics.updateTime();
int width = Math.max(1, graphics.getWidth());
int height = Math.max(1, graphics.getHeight());
if (lastWidth != width || lastHeight != height) {
lastWidth = width;
lastHeight = height;
Gdx.gl.glViewport(0, 0, lastWidth, lastHeight);
resize(width, height);
listener.resize(width, height);
}
synchronized (runnables) {
executedRunnables.clear();
executedRunnables.addAll(runnables);
runnables.clear();
for (int i = 0; i < executedRunnables.size(); i++) {
try {
executedRunnables.get(i).run();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
input.update();
input.processEvents();
listener.render();
if (audio != null)
audio.update();
Display.update();
canvas.setCursor(cursor);
if (graphics.vsync)
Display.sync(60);
} catch (Throwable ex) {
exception(ex);
}
EventQueue.invokeLater(this);
}
});
}
protected void exception(Throwable ex) {
ex.printStackTrace();
stop();
}
/** Called after {@link ApplicationListener} create and resize, but before the game loop iteration. */
protected void start() {
}
/** Called when the canvas size changes. */
protected void resize(int width, int height) {
}
/** Called when the game loop has stopped. */
protected void stopped() {
}
public void stop() {
EventQueue.invokeLater(new Runnable() {
public void run() {
if (!running)
return;
running = false;
try {
Display.destroy();
if (audio != null)
audio.dispose();
} catch (Throwable ignored) {
}
Array<LifecycleListener> listeners = lifecycleListeners;
synchronized (listeners) {
for (LifecycleListener listener : listeners) {
listener.pause();
listener.dispose();
}
}
listener.pause();
listener.dispose();
}
});
}
@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);
}
}
@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() {
LwjglCanvas.this.listener.pause();
LwjglCanvas.this.listener.dispose();
System.exit(-1);
}
});
}
/**
* @param cursor
* May be null.
*/
public void setCursor(Cursor cursor) {
this.cursor = cursor;
}
@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 "abcd1234desktop";
}
@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) {
}
}