/* [LGPL] Copyright 2010, 2011, 2012 Gima, Irah
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ae.gl.core;
import java.nio.ByteBuffer;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import ae.gl.GLMousePoint;
import ae.gl.GLValues;
import ae.routines.ListenerManager;
import ae.routines.S;
import ae.thread.DrainableExecutorService;
public abstract class GLCore {
private boolean requestClose;
private boolean lastFocusedState;
private String windowTitle;
private ByteBuffer[] windowIcon;
public ListenerManager<GLKeyboardListener> keyboardListeners;
public ListenerManager<GLMouseListener> mouseListeners;
private GLMousePoint mousePoint;
private final DrainableExecutorService drainableExecutorService;
public GLCore() {
requestClose = false;
lastFocusedState = true;
windowTitle = "Untitled";
windowIcon = null;
keyboardListeners = new ListenerManager<>();
mouseListeners = new ListenerManager<>();
mousePoint = new GLMousePoint();
drainableExecutorService = new DrainableExecutorService();
}
public DrainableExecutorService getExecutorService() {
return drainableExecutorService;
}
public void startGL(String title) {
windowTitle = title;
startGL();
}
public void startGL(String title, ByteBuffer[] icon) {
windowTitle = title;
windowIcon = icon;
startGL();
}
public void startGL() {
requestClose = false;
lastFocusedState = true;
Keyboard.enableRepeatEvents(false);
Display.setTitle(windowTitle);
Display.setIcon(windowIcon);
contemplateDisplayMode();
GLValues.screenWidth = Display.getWidth();
GLValues.screenHeight = Display.getHeight();
GLValues.calculateRatios();
if (glInit()) {
while (internalLoop()) {
// fps cap?
// fap cap?
}
glTerminate();
}
Display.destroy();
}
public void requestClose() {
requestClose = true;
}
/**
* Sleep at most the specified amount milliseconds.
*/
public void sleep(long millis) {
try {
Thread.sleep(millis);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
public void swapBuffers() {
try {
Display.swapBuffers();
}
catch (LWJGLException e) {
e.printStackTrace();
}
}
private void contemplateDisplayMode() {
DisplayModePack displayModePack;
try {
// request subclass to pick a display mode
displayModePack = glPickDisplayMode();
if (displayModePack == null) {
// subclass specifically requested to let the user choose
displayModeChooserDialog();
return;
}
}
catch (Exception e) {
throw new Error("User class failed to pick a display mode.", e);
}
try {
// try to use the returned display mode
useDisplayModePack(displayModePack);
return;
}
catch (LWJGLException e) {
S.eprintf("Requested display mode could not be set. Offering the user a choice to select one of the available display modes.", e);
}
// let the user choose a display mode
displayModeChooserDialog();
}
private void displayModeChooserDialog() {
DisplayModePack dmpUserChosen = DisplayModeChooserDialog.dialogChooseDisplayMode();
try {
useDisplayModePack(dmpUserChosen);
}
catch (LWJGLException e) {
throw new Error("No display mode could not be set. Exiting.");
}
}
private void useDisplayModePack(DisplayModePack displayModePack) throws LWJGLException {
if (displayModePack == null) throw new NullPointerException("DisplayModePack must not be null.");
Display.setDisplayMode(displayModePack.getDisplayMode());
Display.setFullscreen(displayModePack.isFullscreen());
// GLValues.screenWidth = displayModePack.getDisplayMode().getWidth();
// GLValues.screenHeight = displayModePack.getDisplayMode().getHeight();
// GLValues.calculateRatios();
if (displayModePack.getPixelFormat() == null) {
Display.create();
}
else {
Display.create(displayModePack.getPixelFormat());
}
}
private boolean internalLoop() {
handleKeyboardEvents();
handleMouseEvents();
handleFocusChange();
glLoop();
Display.processMessages();
drainableExecutorService.executePending();
return (!(Display.isCloseRequested() || requestClose));
}
private void handleFocusChange() {
boolean isFocused = Display.isActive();
if (lastFocusedState != isFocused) {
glFocusChanged(isFocused);
lastFocusedState = isFocused;
}
}
private void handleKeyboardEvents() {
while (Keyboard.next()) {
if (Keyboard.getEventKeyState() == true) {
// key changed to down
for (GLKeyboardListener listener : keyboardListeners) {
listener.glKeyDown(Keyboard.getEventKey());
}
}
else {
// key changed to up
for (GLKeyboardListener listener : keyboardListeners) {
listener.glKeyUp(Keyboard.getEventKey());
}
}
} // while
}
private void handleMouseEvents() {
while (Mouse.next()) {
if ((Mouse.getDX() != Mouse.getX()) || (Mouse.getDY() != Mouse.getY())) {
// mouse has moved
float x = (float) Mouse.getX() / (float) Display.getDisplayMode().getWidth();
float y = (float) Mouse.getY() / (float) Display.getDisplayMode().getHeight();
// lwjgl is having a blast at making left-bottom 0,0 "because opengl"
y = 1-y;
mousePoint.getPoint2D().setXY(x, y);
mousePoint.getDelta2D().setXY(Mouse.getDX(), Mouse.getDY());
//TODO: 3D point get here
float xr = GLValues.cameraPositionX + (0.5f-((float)Mouse.getX()/GLValues.screenWidth))*(GLValues.glWidth/GLValues.glHeight)*2*GLValues.cameraPositionZ;
float yr = GLValues.cameraPositionY - (0.5f-((float)Mouse.getY()/GLValues.screenHeight))*2*GLValues.cameraPositionZ;
float zr = -1;
mousePoint.getPoint3D().setXYZ(xr, yr, zr);
for (GLMouseListener listener : mouseListeners) {
listener.glMouseMoved(mousePoint);
}
}
if (Mouse.getEventButton() == -1) {
// no buttons changed
continue;
}
if (Mouse.getEventButtonState() == true) {
// button changed to down
for (GLMouseListener listener : mouseListeners) {
listener.glMouseButtonDown(mousePoint, Mouse.getEventButton());
}
}
else {
// button changed to up
for (GLMouseListener listener : mouseListeners) {
listener.glMouseButtonUp(mousePoint, Mouse.getEventButton());
}
}
} // while
}
public abstract boolean glInit();
public abstract DisplayModePack glPickDisplayMode() throws Exception;
public abstract void glLoop();
public abstract void glFocusChanged(boolean isFocused);
public abstract void glTerminate();
}