aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/render/opengl
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-06-28 19:06:14 +0200
committerSven Gothel <[email protected]>2013-06-28 19:06:14 +0200
commit54bbd1a726e73841f0bd4cc79e5b12e83a88ba18 (patch)
tree6e71430ad8217e1fce810b5310ec0b5b2766340c /src/jake2/render/opengl
parent28ed823b1a804145b4dd741807a83570abc139e1 (diff)
Add Applet Feature incl. required fixes.
- Jake2Applet - Reenable JavaScript Bridge to resize Applet - Pass through 4:3 aspect custom video mode (Jake2 args) - Pass through applet parameter 'jake_args' (Jake2 args) - OSX Hack: Re-create Game at init, otherwise flickering appears (??) - Fix VID.init: Set vid_ref.modifier = true, otherwise not guaranteed VID creation - BeginFrame, R_BeginFrame, beginFrame, activateGLContext: Return 'true', if ctx is available, otherwise false to skip frame. - NEWTWin: - Applet mode (in Applet container): Always release GL ctx - Use GLAnimatorControl impl, to state whether we are animating or not and to tell us, whether we have to release the GL ctx. - Add HOME -> Reparent feature for Applets - Workaround for NEWT/Windows Bug 798 - NEWT Key Handling: - Ignore auto-repeat - Workaround for NEWT/Windows Bug 798 - Add HTML page - normal - debug mode
Diffstat (limited to 'src/jake2/render/opengl')
-rw-r--r--src/jake2/render/opengl/GLDriver.java3
-rw-r--r--src/jake2/render/opengl/JoglDummyDriver.java11
-rw-r--r--src/jake2/render/opengl/JoglES1Driver.java11
-rw-r--r--src/jake2/render/opengl/JoglES2Driver.java10
-rw-r--r--src/jake2/render/opengl/JoglGL2Driver.java12
-rw-r--r--src/jake2/render/opengl/NEWTWin.java368
6 files changed, 338 insertions, 77 deletions
diff --git a/src/jake2/render/opengl/GLDriver.java b/src/jake2/render/opengl/GLDriver.java
index 7f86430..9d82593 100644
--- a/src/jake2/render/opengl/GLDriver.java
+++ b/src/jake2/render/opengl/GLDriver.java
@@ -16,7 +16,8 @@ public interface GLDriver {
void shutdown();
- void beginFrame(float camera_separation);
+ /** @return true if successful, otherwise false. */
+ boolean beginFrame(float camera_separation);
/** Performs <code>swapBuffers()</code>, ticks the fps counter and performs <code>QUIT</code> if requested. */
void endFrame();
diff --git a/src/jake2/render/opengl/JoglDummyDriver.java b/src/jake2/render/opengl/JoglDummyDriver.java
index e962c37..4ba98a0 100644
--- a/src/jake2/render/opengl/JoglDummyDriver.java
+++ b/src/jake2/render/opengl/JoglDummyDriver.java
@@ -97,8 +97,9 @@ public abstract class JoglDummyDriver extends DummyGL implements GLDriver {
return true;
}
- public void beginFrame(float camera_separation) {
- activateGLContext();
+ @Override
+ public boolean beginFrame(float camera_separation) {
+ return activateGLContext(false);
}
public void endFrame() {
@@ -126,12 +127,12 @@ public abstract class JoglDummyDriver extends DummyGL implements GLDriver {
callback.execute();
}
- protected final void activateGLContext() {
- newtWin.activateGLContext();
+ protected final boolean activateGLContext(boolean force) {
+ return newtWin.activateGLContext(false);
}
protected final void deactivateGLContext() {
- newtWin.activateGLContext();
+ newtWin.deactivateGLContext();
}
// --------------------------------------------------------------------------
diff --git a/src/jake2/render/opengl/JoglES1Driver.java b/src/jake2/render/opengl/JoglES1Driver.java
index 6f138cd..d798c72 100644
--- a/src/jake2/render/opengl/JoglES1Driver.java
+++ b/src/jake2/render/opengl/JoglES1Driver.java
@@ -108,8 +108,9 @@ public abstract class JoglES1Driver extends JoglGL2ES1 implements GLDriver {
return true;
}
- public void beginFrame(float camera_separation) {
- newtWin.activateGLContext();
+ @Override
+ public boolean beginFrame(float camera_separation) {
+ return activateGLContext(false);
}
public void endFrame() {
@@ -136,12 +137,12 @@ public abstract class JoglES1Driver extends JoglGL2ES1 implements GLDriver {
callback.execute();
}
- protected final void activateGLContext() {
- newtWin.activateGLContext();
+ protected final boolean activateGLContext(boolean force) {
+ return newtWin.activateGLContext(force);
}
protected final void deactivateGLContext() {
- newtWin.activateGLContext();
+ newtWin.deactivateGLContext();
}
// --------------------------------------------------------------------------
diff --git a/src/jake2/render/opengl/JoglES2Driver.java b/src/jake2/render/opengl/JoglES2Driver.java
index 08c95b9..f18a9cb 100644
--- a/src/jake2/render/opengl/JoglES2Driver.java
+++ b/src/jake2/render/opengl/JoglES2Driver.java
@@ -113,8 +113,8 @@ public abstract class JoglES2Driver extends JoglGL2ES1 implements GLDriver {
return true;
}
- public void beginFrame(float camera_separation) {
- activateGLContext();
+ public boolean beginFrame(float camera_separation) {
+ return activateGLContext(false);
}
public void endFrame() {
@@ -141,12 +141,12 @@ public abstract class JoglES2Driver extends JoglGL2ES1 implements GLDriver {
callback.execute();
}
- protected final void activateGLContext() {
- newtWin.activateGLContext();
+ protected final boolean activateGLContext(boolean force) {
+ return newtWin.activateGLContext(force);
}
protected final void deactivateGLContext() {
- newtWin.activateGLContext();
+ newtWin.deactivateGLContext();
}
// --------------------------------------------------------------------------
diff --git a/src/jake2/render/opengl/JoglGL2Driver.java b/src/jake2/render/opengl/JoglGL2Driver.java
index 0c95680..32195cb 100644
--- a/src/jake2/render/opengl/JoglGL2Driver.java
+++ b/src/jake2/render/opengl/JoglGL2Driver.java
@@ -27,6 +27,7 @@ package jake2.render.opengl;
import java.util.List;
+import jake2.client.VID;
import jake2.game.cvar_t;
import jake2.qcommon.Cvar;
import jake2.qcommon.xcommand_t;
@@ -109,8 +110,9 @@ public abstract class JoglGL2Driver extends JoglGL2ES1 implements GLDriver {
return true;
}
- public void beginFrame(float camera_separation) {
- activateGLContext();
+ @Override
+ public boolean beginFrame(float camera_separation) {
+ return activateGLContext(false);
}
public void endFrame() {
@@ -137,12 +139,12 @@ public abstract class JoglGL2Driver extends JoglGL2ES1 implements GLDriver {
callback.execute();
}
- protected final void activateGLContext() {
- newtWin.activateGLContext();
+ protected final boolean activateGLContext(boolean force) {
+ return newtWin.activateGLContext(force);
}
protected final void deactivateGLContext() {
- newtWin.activateGLContext();
+ newtWin.deactivateGLContext();
}
// --------------------------------------------------------------------------
diff --git a/src/jake2/render/opengl/NEWTWin.java b/src/jake2/render/opengl/NEWTWin.java
index ff7b949..df47bb1 100644
--- a/src/jake2/render/opengl/NEWTWin.java
+++ b/src/jake2/render/opengl/NEWTWin.java
@@ -15,6 +15,7 @@ import jake2.qcommon.Cvar;
import jake2.render.Base;
import jake2.sys.NEWTKBD;
+import java.io.PrintStream;
import java.util.List;
import javax.media.nativewindow.CapabilitiesChooser;
@@ -22,26 +23,34 @@ import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode;
import javax.media.nativewindow.util.Dimension;
import javax.media.nativewindow.util.DimensionImmutable;
import javax.media.nativewindow.util.SurfaceSize;
-import javax.media.opengl.GLCapabilities;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLProfile;
+import javax.media.opengl.*;
import jogamp.opengl.FPSCounterImpl;
import com.jogamp.common.os.Platform;
import com.jogamp.newt.*;
-import com.jogamp.newt.event.WindowAdapter;
-import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.awt.NewtCanvasAWT;
+import com.jogamp.newt.event.*;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.newt.util.MonitorModeUtil;
import com.jogamp.opengl.GenericGLCapabilitiesChooser;
public class NEWTWin {
+ final static boolean DEBUG = false;
+ /** Required due to AWT lock of surface, if Applet! */
+ final static boolean FORCE_RELEASE_CTX_VAL = true;
+
MonitorMode oldDisplayMode = null;
volatile Screen screen = null;
volatile GLWindow window = null;
+ volatile GameAnimatorControl animCtrl = null;
+ /** Encapsulateed AWT dependency */
+ volatile Object newtCanvasObject = null;
+ boolean forceReleaseCtx = false;
volatile boolean shouldQuit = false;
- final FPSCounterImpl fpsCounter = new FPSCounterImpl();
+ volatile boolean shouldPause = false;
+ volatile boolean shouldReparent = false;
+ volatile boolean isAnimating = false;
public List<MonitorMode> getModeList() {
if( null != window ) {
@@ -79,12 +88,10 @@ public class NEWTWin {
* @param dim
* @param mode
* @param fullscreen
- * @param driverName TODO
+ * @param driverName
* @return enum Base.rserr_t
*/
public int setMode(GLProfile glp, Dimension dim, int mode, boolean fullscreen, String driverName) {
- final boolean isARM = Platform.CPUFamily.ARM == Platform.getCPUFamily();
-
final Dimension newDim = new Dimension();
VID.Printf(Defines.PRINT_ALL, "Initializing OpenGL display for profile "+glp+"\n");
@@ -120,7 +127,9 @@ public class NEWTWin {
chooser = new GenericGLCapabilitiesChooser(); // don't trust native GL-TK chooser
}
}
+
window = GLWindow.create(screen, caps);
+ window.setAutoSwapBufferMode(false);
window.setDefaultCloseOperation(WindowClosingMode.DO_NOTHING_ON_CLOSE); // we do handle QUIT on our own, no GLWindow.display() called.
window.setCapabilitiesChooser(chooser);
window.addWindowListener(new WindowAdapter() {
@@ -133,6 +142,9 @@ public class NEWTWin {
}
});
window.setTitle("Jake2 ("+driverName+"-newt-"+glp.getName().toLowerCase()+")");
+
+ animCtrl = new GameAnimatorControl();
+ window.setAnimator(animCtrl);
final MonitorDevice mainMonitor = window.getMainMonitor();
@@ -146,88 +158,170 @@ public class NEWTWin {
window.addWindowListener(NEWTKBD.listener);
window.addKeyListener(NEWTKBD.listener);
window.addMouseListener(NEWTKBD.listener);
-
- if (fullscreen) {
- MonitorMode mm = findDisplayMode(newDim);
- final DimensionImmutable smDim = mm.getSurfaceSize().getResolution();
- newDim.setWidth( smDim.getWidth() );
- newDim.setHeight( smDim.getHeight() );
- mainMonitor.setCurrentMode(mm);
- window.setFullscreen(true);
- } else {
- window.setSize(newDim.getWidth(), newDim.getHeight());
- if (Globals.appletMode) {
- // Notify the size listener about the change
- final SizeChangeListener listener = Globals.sizeChangeListener;
- if (listener != null) {
- listener.sizeChanged(newDim.getWidth(), newDim.getHeight());
- }
+ window.setSize(newDim.getWidth(), newDim.getHeight());
+
+ isAnimating = true; // no display() invocation on other thread!
+
+ if( !fullscreen && Globals.appletMode ) {
+ forceReleaseCtx = FORCE_RELEASE_CTX_VAL;
+
+ // Notify the size listener about the change
+ final SizeChangeListener listener = Globals.sizeChangeListener;
+ if (listener != null) {
+ listener.sizeChanged(newDim.getWidth(), newDim.getHeight());
}
- }
- window.setVisible(true);
-
- if (!Globals.appletMode) {
- while ( !window.isNativeValid()|| !window.isRealized() ) {
+ window.addKeyListener( new ReparentKeyListener() );
+
+ final NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(window);
+ final java.applet.Applet applet = (java.applet.Applet) Globals.applet;
+ final Runnable appletAddAction = new Runnable() {
+ public void run() {
+ applet.add(newtCanvasAWT, java.awt.BorderLayout.CENTER);
+ applet.validate();
+ newtCanvasAWT.setFocusable(true);
+ newtCanvasAWT.requestFocus();
+ if( Platform.OSType.MACOS == Platform.getOSType() && newtCanvasAWT.isOffscreenLayerSurfaceEnabled() ) {
+ System.err.println("XXX Relayout");
+ // force relayout
+ final int cW = newtCanvasAWT.getWidth();
+ final int cH = newtCanvasAWT.getHeight();
+ newtCanvasAWT.setSize(cW+1, cH+1);
+ newtCanvasAWT.setSize(cW, cH);
+ }
+ } };
+ if( java.awt.EventQueue.isDispatchThread() ) {
+ System.err.println("XXX Adding on AWT EDT - same thread");
+ appletAddAction.run();
+ } else {
+ System.err.println("XXX Adding on AWT EDT - off thread");
+ try {
+ java.awt.EventQueue.invokeAndWait(appletAddAction);
+ } catch (Exception e) {
+ throw new RuntimeException("NEWT Exception during NewtCanvasAWT on AWT-EDT", e);
+ }
+ }
+ newtCanvasObject = newtCanvasAWT;
+ int w=0;
+ while ( w<10 && !window.isNativeValid()|| !window.isRealized() ) {
+ w++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
+ System.err.println("XXX waited = "+w+" * 100 ms");
+ } else {
+ forceReleaseCtx = false;
+ newtCanvasObject = null;
+
+ if (fullscreen) {
+ MonitorMode mm = findDisplayMode(newDim);
+ final DimensionImmutable smDim = mm.getSurfaceSize().getResolution();
+ newDim.setWidth( smDim.getWidth() );
+ newDim.setHeight( smDim.getHeight() );
+ mainMonitor.setCurrentMode(mm);
+ VID.Printf(Defines.PRINT_ALL, "...MonitorMode "+mm+'\n');
+ window.setFullscreen(true);
+ }
+
+ window.setVisible(true);
+ window.requestFocus();
+ }
+ if( !window.isNativeValid()|| !window.isRealized() ) {
+ throw new RuntimeException("NEWT window didn't not realize: "+window);
+ }
+ window.display(); // force GL creation
+ final GLContext ctx = window.getContext();
+ if( !ctx.isCreated() ) {
+ System.err.println("Warning: GL context not created: "+ctx);
+ }
+ if( ctx.isCurrent() ) {
+ throw new RuntimeException("NEWT GL context still current: "+ctx);
}
- window.requestFocus();
- window.display(); // force GL resource validation
- window.setAutoSwapBufferMode(false);
VID.Printf(Defines.PRINT_ALL, "...reques GLCaps "+window.getRequestedCapabilities()+'\n');
VID.Printf(Defines.PRINT_ALL, "...chosen GLCaps "+window.getChosenGLCapabilities()+'\n');
VID.Printf(Defines.PRINT_ALL, "...size "+window.getWidth()+" x "+window.getHeight()+'\n');
- fpsCounter.setUpdateFPSFrames(isARM ? 60 : 4*60, System.err);
// propagateNewSize("init");
- activateGLContext();
+ activateGLContext(true);
return Base.rserr_ok;
}
private void propagateNewSize() {
- final int width = window.getWidth();
- final int height = window.getHeight();
- final int _width;
- final int mask = ~0x03;
- if ((width & 0x03) != 0) {
- _width = ( width & mask ) + 4;
- } else {
- _width = width;
+ if( null != window ) {
+ final int width = window.getWidth();
+ final int height = window.getHeight();
+ final int _width;
+ final int mask = ~0x03;
+ if ((width & 0x03) != 0) {
+ _width = ( width & mask ) + 4;
+ } else {
+ _width = width;
+ }
+ VID.Printf(Defines.PRINT_ALL, "Resize: " + width + " x " + height + ", masked " + _width + "x" + height + "\n");
+
+ Base.setVid(_width, height);
+ // let the sound and input subsystems know about the new window
+ VID.NewWindow(_width, height);
}
- VID.Printf(Defines.PRINT_ALL, "Resize: " + width + " x " + height + ", masked " + _width + "x" + height + "\n");
-
- Base.setVid(_width, height);
- // let the sound and input subsystems know about the new window
- VID.NewWindow(_width, height);
}
- protected final void activateGLContext() {
- final GLContext ctx = window.getContext();
- if ( null != ctx && GLContext.getCurrent() != ctx ) {
- ctx.makeCurrent();
+ protected final boolean activateGLContext(boolean force) {
+ boolean ctxCurrent = false;
+ if( force || !shouldPause ) {
+ final GLContext ctx = window.getContext();
+ if ( null != ctx && GLContext.getCurrent() != ctx ) {
+ if( DEBUG ) {
+ System.err.println("GLCtx Current pause "+shouldPause+": "+Thread.currentThread().getName());
+ }
+ ctxCurrent = GLContext.CONTEXT_NOT_CURRENT < ctx.makeCurrent();
+ } else {
+ ctxCurrent = true;
+ }
+ isAnimating = ctxCurrent;
}
+ return ctxCurrent;
}
protected final void deactivateGLContext() {
final GLContext ctx = window.getContext();
if ( null != ctx && GLContext.getCurrent() == ctx) {
+ if( DEBUG ) {
+ System.err.println("GLCtx Release pause "+shouldPause+": "+Thread.currentThread().getName());
+ }
ctx.release();
}
}
- /** Performs {@link GLWindow#swapBuffers()}, ticks the fps counter and performs <code>QUIT</code> if requested. */
+ /**
+ * Performs {@link GLWindow#swapBuffers()}, ticks the fps counter and performs <code>QUIT</code> if requested.
+ */
public final void endFrame() {
window.swapBuffers();
- fpsCounter.tickFPS();
+ animCtrl.fpsCounter.tickFPS();
if( shouldQuit ) {
deactivateGLContext();
Cbuf.ExecuteText(Defines.EXEC_APPEND, "quit");
+ } else if( shouldReparent ) {
+ shouldReparent = false;
+ deactivateGLContext();
+ if( null != newtCanvasObject && null != window ) {
+ isAnimating = false; // don't let GLDrawableHelper.invoke(..) defer the GLRunnable (preserving GLState that is on OSX/CALayer)
+ final NewtCanvasAWT newtCanvasAWT = (NewtCanvasAWT) newtCanvasObject;
+ if(null == window.getParent()) {
+ forceReleaseCtx = FORCE_RELEASE_CTX_VAL; // Applet
+ window.reparentWindow( newtCanvasAWT.getNativeWindow() );
+ } else {
+ window.reparentWindow(null);
+ forceReleaseCtx = false;
+ }
+ }
+ } else if( forceReleaseCtx || shouldPause ) {
+ deactivateGLContext();
}
}
+
/** Performs <code>QUIT</code> if requested. */
public final void checkQuit() {
if( shouldQuit ) {
@@ -245,12 +339,174 @@ public class NEWTWin {
deactivateGLContext();
final GLWindow _window = window;
window = null;
- _window.destroy(); // same thing
+ _window.destroy();
+ if( null != Globals.applet && null != newtCanvasObject ) {
+ final java.applet.Applet applet = (java.applet.Applet) Globals.applet;
+ final NewtCanvasAWT newtCanvasAWT = (NewtCanvasAWT) newtCanvasObject;
+ final Runnable appletRemoveAction = new Runnable() {
+ public void run() {
+ applet.remove(newtCanvasAWT);
+ applet.validate();
+ } };
+ if( java.awt.EventQueue.isDispatchThread() ) {
+ appletRemoveAction.run();
+ } else {
+ try {
+ java.awt.EventQueue.invokeAndWait(appletRemoveAction);
+ } catch (Throwable e) {
+ System.err.println("Catched "+e.getClass().getName()+": "+e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ newtCanvasAWT.setNEWTChild(null);
+ newtCanvasObject = null;
+ }
}
if( withScreen && null != screen ) {
- screen.destroy();
+ try {
+ screen.destroy();
+ } catch (Throwable e) {
+ System.err.println("Catched "+e.getClass().getName()+": "+e.getMessage());
+ e.printStackTrace();
+ }
screen = null;
}
}
+ class GameAnimatorControl implements GLAnimatorControl {
+ final FPSCounterImpl fpsCounter;
+ final Thread thread;
+
+ GameAnimatorControl() {
+ final boolean isARM = Platform.CPUFamily.ARM == Platform.getCPUFamily();
+ fpsCounter = new FPSCounterImpl();
+ fpsCounter.setUpdateFPSFrames(isARM ? 60 : 4*60, System.err);
+ thread = Thread.currentThread();
+ }
+
+ @Override
+ public final boolean start() {
+ return false;
+ }
+
+ @Override
+ public final boolean stop() {
+ shouldQuit = true;
+ return true;
+ }
+
+ @Override
+ public final boolean pause() {
+ if( DEBUG ) {
+ System.err.println("GLCtx Pause Anim: "+Thread.currentThread().getName());
+ Thread.dumpStack();
+ }
+ shouldPause = true;
+ return true;
+ }
+
+ @Override
+ public final boolean resume() {
+ shouldPause = false;
+ return true;
+ }
+
+ @Override
+ public final boolean isStarted() {
+ return null != window;
+ }
+
+ @Override
+ public final boolean isAnimating() {
+ return isAnimating; // null != window && !shouldPause;
+ }
+
+ @Override
+ public final boolean isPaused() {
+ return null == window || shouldPause;
+ }
+
+ @Override
+ public final Thread getThread() {
+ return thread;
+ }
+
+ @Override
+ public final void add(GLAutoDrawable drawable) {}
+
+ @Override
+ public final void remove(GLAutoDrawable drawable) {}
+
+ @Override
+ public final void setUpdateFPSFrames(int frames, PrintStream out) {
+ fpsCounter.setUpdateFPSFrames(frames, out);
+ }
+
+ @Override
+ public final void resetFPSCounter() {
+ fpsCounter.resetFPSCounter();
+ }
+
+ @Override
+ public final int getUpdateFPSFrames() {
+ return fpsCounter.getUpdateFPSFrames();
+ }
+
+ @Override
+ public final long getFPSStartTime() {
+ return fpsCounter.getFPSStartTime();
+ }
+
+ @Override
+ public final long getLastFPSUpdateTime() {
+ return fpsCounter.getLastFPSUpdateTime();
+ }
+
+ @Override
+ public final long getLastFPSPeriod() {
+ return fpsCounter.getLastFPSPeriod();
+ }
+
+ @Override
+ public final float getLastFPS() {
+ return fpsCounter.getLastFPS();
+ }
+
+ @Override
+ public final int getTotalFPSFrames() {
+ return fpsCounter.getTotalFPSFrames();
+ }
+
+ @Override
+ public final long getTotalFPSDuration() {
+ return fpsCounter.getTotalFPSDuration();
+ }
+
+ @Override
+ public final float getTotalFPS() {
+ return fpsCounter.getTotalFPS();
+ }
+ }
+
+ class ReparentKeyListener implements KeyListener {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ System.err.println(e);
+ if( !e.isAutoRepeat() ) {
+ int keyCode = e.getKeyCode();
+ // FIXME: Workaround JOGL/NEWT Bug 798
+ if( 0 == keyCode ) {
+ keyCode = e.getKeySymbol();
+ }
+ if( KeyEvent.VK_HOME == keyCode ) {
+ shouldReparent = true;
+ }
+ }
+ }
+ @Override
+ public void keyReleased(KeyEvent e) {
+ System.err.println(e);
+ }
+ }
+
}