git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9878 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
1843916822
commit
9b9db3bd31
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,386 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.renderer.jogl; |
||||||
|
|
||||||
|
import com.jme3.renderer.RendererException; |
||||||
|
import com.jme3.texture.Image; |
||||||
|
import com.jme3.texture.Image.Format; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import javax.media.opengl.GL; |
||||||
|
import javax.media.opengl.GL2; |
||||||
|
import javax.media.opengl.GL2ES2; |
||||||
|
import javax.media.opengl.GL3; |
||||||
|
import javax.media.opengl.GLContext; |
||||||
|
|
||||||
|
public class TextureUtil { |
||||||
|
|
||||||
|
public static int convertTextureFormat(Format fmt) { |
||||||
|
switch (fmt) { |
||||||
|
case Alpha16: |
||||||
|
case Alpha8: |
||||||
|
return GL.GL_ALPHA; |
||||||
|
case Luminance8Alpha8: |
||||||
|
case Luminance16Alpha16: |
||||||
|
return GL.GL_LUMINANCE_ALPHA; |
||||||
|
case Luminance8: |
||||||
|
case Luminance16: |
||||||
|
return GL.GL_LUMINANCE; |
||||||
|
case RGB10: |
||||||
|
case RGB16: |
||||||
|
case BGR8: |
||||||
|
case RGB8: |
||||||
|
case RGB565: |
||||||
|
return GL.GL_RGB; |
||||||
|
case RGB5A1: |
||||||
|
case RGBA16: |
||||||
|
case RGBA8: |
||||||
|
return GL.GL_RGBA; |
||||||
|
case Depth: |
||||||
|
return GL2ES2.GL_DEPTH_COMPONENT; |
||||||
|
default: |
||||||
|
throw new UnsupportedOperationException("Unrecognized format: " + fmt); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static class GLImageFormat { |
||||||
|
|
||||||
|
int internalFormat; |
||||||
|
int format; |
||||||
|
int dataType; |
||||||
|
boolean compressed; |
||||||
|
|
||||||
|
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) { |
||||||
|
this.internalFormat = internalFormat; |
||||||
|
this.format = format; |
||||||
|
this.dataType = dataType; |
||||||
|
this.compressed = compressed; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static final GLImageFormat[] formatToGL = new GLImageFormat[Format.values().length]; |
||||||
|
|
||||||
|
private static void setFormat(Format format, int glInternalFormat, int glFormat, int glDataType, boolean glCompressed){ |
||||||
|
formatToGL[format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, glCompressed); |
||||||
|
} |
||||||
|
|
||||||
|
static { |
||||||
|
// Alpha formats
|
||||||
|
setFormat(Format.Alpha8, GL2.GL_ALPHA8, GL.GL_ALPHA, GL.GL_UNSIGNED_BYTE, false); |
||||||
|
setFormat(Format.Alpha16, GL2.GL_ALPHA16, GL.GL_ALPHA, GL.GL_UNSIGNED_SHORT, false); |
||||||
|
|
||||||
|
// Luminance formats
|
||||||
|
setFormat(Format.Luminance8, GL2.GL_LUMINANCE8, GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE, false); |
||||||
|
setFormat(Format.Luminance16, GL2.GL_LUMINANCE16, GL.GL_LUMINANCE, GL.GL_UNSIGNED_SHORT, false); |
||||||
|
setFormat(Format.Luminance16F, GL2.GL_LUMINANCE16F_ARB, GL.GL_LUMINANCE, GL.GL_HALF_FLOAT, false); |
||||||
|
setFormat(Format.Luminance32F, GL.GL_LUMINANCE32F_ARB, GL.GL_LUMINANCE, GL.GL_FLOAT, false); |
||||||
|
|
||||||
|
// Luminance alpha formats
|
||||||
|
setFormat(Format.Luminance8Alpha8, GL2.GL_LUMINANCE8_ALPHA8, GL.GL_LUMINANCE_ALPHA, GL.GL_UNSIGNED_BYTE, false); |
||||||
|
setFormat(Format.Luminance16Alpha16, GL2.GL_LUMINANCE16_ALPHA16, GL.GL_LUMINANCE_ALPHA, GL.GL_UNSIGNED_SHORT, false); |
||||||
|
setFormat(Format.Luminance16FAlpha16F, GL2.GL_LUMINANCE_ALPHA16F_ARB, GL2.GL_LUMINANCE_ALPHA, GL2.GL_HALF_FLOAT, false); |
||||||
|
|
||||||
|
// Depth formats
|
||||||
|
setFormat(Format.Depth, GL2.GL_DEPTH_COMPONENT, GL2.GL_DEPTH_COMPONENT, GL2.GL_UNSIGNED_BYTE, false); |
||||||
|
setFormat(Format.Depth16, GL2.GL_DEPTH_COMPONENT16, GL2.GL_DEPTH_COMPONENT, GL2.GL_UNSIGNED_SHORT, false); |
||||||
|
setFormat(Format.Depth24, GL2.GL_DEPTH_COMPONENT24, GL2.GL_DEPTH_COMPONENT, GL2.GL_UNSIGNED_INT, false); |
||||||
|
setFormat(Format.Depth32, GL2.GL_DEPTH_COMPONENT32, GL2.GL_DEPTH_COMPONENT, GL2.GL_UNSIGNED_INT, false); |
||||||
|
setFormat(Format.Depth32F, GL2.GL_DEPTH_COMPONENT32F, GL2.GL_DEPTH_COMPONENT, GL2.GL_FLOAT, false); |
||||||
|
|
||||||
|
// Depth stencil formats
|
||||||
|
setFormat(Format.Depth24Stencil8, GL3.GL_DEPTH24_STENCIL8, GL3.GL_DEPTH_STENCIL, GL3.GL_UNSIGNED_INT_24_8, false); |
||||||
|
|
||||||
|
// RGB formats
|
||||||
|
setFormat(Format.BGR8, GL.GL_RGB8, GL2.GL_BGR, GL.GL_UNSIGNED_BYTE, false); |
||||||
|
setFormat(Format.RGB8, GL.GL_RGB8, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, false); |
||||||
|
// setFormat(Format.RGB10, GL11.GL_RGB10, GL11.GL_RGB, GL12.GL_UNSIGNED_INT_10_10_10_2, false);
|
||||||
|
setFormat(Format.RGB16, GL2.GL_RGB16, GL.GL_RGB, GL.GL_UNSIGNED_SHORT, false); |
||||||
|
setFormat(Format.RGB16F, GL2ES2.GL_RGB16F, GL.GL_RGB, GL.GL_HALF_FLOAT, false); |
||||||
|
setFormat(Format.RGB32F, GL.GL_RGB32F, GL.GL_RGB, GL.GL_FLOAT, false); |
||||||
|
|
||||||
|
// Special RGB formats
|
||||||
|
setFormat(Format.RGB111110F, GL2.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_UNSIGNED_INT_10F_11F_11F_REV, false); |
||||||
|
setFormat(Format.RGB9E5, GL2.GL_RGB9_E5, GL.GL_RGB, GL2.GL_UNSIGNED_INT_5_9_9_9_REV, false); |
||||||
|
setFormat(Format.RGB16F_to_RGB111110F, GL2.GL_R11F_G11F_B10F, GL.GL_RGB, GL.GL_HALF_FLOAT, false); |
||||||
|
setFormat(Format.RGB16F_to_RGB9E5, GL2.GL_RGB9_E5, GL.GL_RGB, GL.GL_HALF_FLOAT, false); |
||||||
|
|
||||||
|
// RGBA formats
|
||||||
|
setFormat(Format.ABGR8, GL.GL_RGBA8, GL2.GL_ABGR_EXT, GL.GL_UNSIGNED_BYTE, false); |
||||||
|
setFormat(Format.RGB5A1, GL.GL_RGB5_A1, GL.GL_RGBA, GL.GL_UNSIGNED_SHORT_5_5_5_1, false); |
||||||
|
setFormat(Format.ARGB4444, GL.GL_RGBA4, GL2.GL_ABGR_EXT, GL.GL_UNSIGNED_SHORT_4_4_4_4, false); |
||||||
|
setFormat(Format.RGBA8, GL.GL_RGBA8, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, false); |
||||||
|
setFormat(Format.RGBA16, GL2.GL_RGBA16, GL.GL_RGBA, GL.GL_UNSIGNED_SHORT, false); // might be incorrect
|
||||||
|
setFormat(Format.RGBA16F, GL2.GL_RGBA16F, GL.GL_RGBA, GL.GL_HALF_FLOAT, false); |
||||||
|
setFormat(Format.RGBA32F, GL.GL_RGBA32F, GL.GL_RGBA, GL.GL_FLOAT, false); |
||||||
|
|
||||||
|
// DXT formats
|
||||||
|
setFormat(Format.DXT1, GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL.GL_RGB, GL2.GL_UNSIGNED_BYTE, true); |
||||||
|
setFormat(Format.DXT1A, GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL.GL_RGBA, GL2.GL_UNSIGNED_BYTE, true); |
||||||
|
setFormat(Format.DXT3, GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL.GL_RGBA, GL2.GL_UNSIGNED_BYTE, true); |
||||||
|
setFormat(Format.DXT5, GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL.GL_RGBA, GL2.GL_UNSIGNED_BYTE, true); |
||||||
|
|
||||||
|
// LTC/LATC/3Dc formats
|
||||||
|
setFormat(Format.LTC, GL2.GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE, true); |
||||||
|
setFormat(Format.LATC, GL2.GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL.GL_LUMINANCE_ALPHA, GL.GL_UNSIGNED_BYTE, true); |
||||||
|
} |
||||||
|
|
||||||
|
public static GLImageFormat getImageFormat(Format fmt){ |
||||||
|
GL gl = GLContext.getCurrentGL(); |
||||||
|
switch (fmt){ |
||||||
|
case ABGR8: |
||||||
|
if (!gl.isExtensionAvailable("GL_EXT_abgr")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case BGR8: |
||||||
|
if (!gl.isExtensionAvailable("GL_VERSION_1_2") && !gl.isExtensionAvailable("EXT_bgra")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case DXT1: |
||||||
|
case DXT1A: |
||||||
|
case DXT3: |
||||||
|
case DXT5: |
||||||
|
if (!gl.isExtensionAvailable("GL_EXT_texture_compression_s3tc")) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case Depth: |
||||||
|
case Depth16: |
||||||
|
case Depth24: |
||||||
|
case Depth32: |
||||||
|
if (!gl.isExtensionAvailable("GL_VERSION_1_4") && !gl.isExtensionAvailable("ARB_depth_texture")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case Depth24Stencil8: |
||||||
|
if (!gl.isExtensionAvailable("GL_VERSION_3_0")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case Luminance16F: |
||||||
|
case Luminance16FAlpha16F: |
||||||
|
case Luminance32F: |
||||||
|
if (!gl.isExtensionAvailable("GL_ARB_texture_float")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case RGB16F: |
||||||
|
case RGB32F: |
||||||
|
case RGBA16F: |
||||||
|
case RGBA32F: |
||||||
|
if (!gl.isExtensionAvailable("GL_VERSION_3_0") && !gl.isExtensionAvailable("GL_ARB_texture_float")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case Depth32F: |
||||||
|
if (!gl.isExtensionAvailable("GL_VERSION_3_0") && !gl.isExtensionAvailable("GL_NV_depth_buffer_float")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case LATC: |
||||||
|
case LTC: |
||||||
|
if (!gl.isExtensionAvailable("GL_EXT_texture_compression_latc")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case RGB9E5: |
||||||
|
case RGB16F_to_RGB9E5: |
||||||
|
if (!gl.isExtensionAvailable("GL_VERSION_3_0") && !gl.isExtensionAvailable("GL_EXT_texture_shared_exponent")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
case RGB111110F: |
||||||
|
case RGB16F_to_RGB111110F: |
||||||
|
if (!gl.isExtensionAvailable("GL_VERSION_3_0") && !gl.isExtensionAvailable("GL_EXT_packed_float")){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
return formatToGL[fmt.ordinal()]; |
||||||
|
} |
||||||
|
|
||||||
|
public static GLImageFormat getImageFormatWithError(Format fmt) { |
||||||
|
GLImageFormat glFmt = getImageFormat(fmt); |
||||||
|
if (glFmt == null) { |
||||||
|
throw new RendererException("Image format '" + fmt + "' is unsupported by the video hardware."); |
||||||
|
} |
||||||
|
return glFmt; |
||||||
|
} |
||||||
|
|
||||||
|
public static void uploadTexture(Image image, |
||||||
|
int target, |
||||||
|
int index, |
||||||
|
int border){ |
||||||
|
GL gl = GLContext.getCurrentGL(); |
||||||
|
Image.Format fmt = image.getFormat(); |
||||||
|
GLImageFormat glFmt = getImageFormatWithError(fmt); |
||||||
|
|
||||||
|
ByteBuffer data; |
||||||
|
if (index >= 0 && image.getData() != null && image.getData().size() > 0){ |
||||||
|
data = image.getData(index); |
||||||
|
}else{ |
||||||
|
data = null; |
||||||
|
} |
||||||
|
|
||||||
|
int width = image.getWidth(); |
||||||
|
int height = image.getHeight(); |
||||||
|
int depth = image.getDepth(); |
||||||
|
|
||||||
|
if (data != null) { |
||||||
|
gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); |
||||||
|
} |
||||||
|
|
||||||
|
int[] mipSizes = image.getMipMapSizes(); |
||||||
|
int pos = 0; |
||||||
|
// TODO: Remove unneccessary allocation
|
||||||
|
if (mipSizes == null){ |
||||||
|
if (data != null) |
||||||
|
mipSizes = new int[]{ data.capacity() }; |
||||||
|
else |
||||||
|
mipSizes = new int[]{ width * height * fmt.getBitsPerPixel() / 8 }; |
||||||
|
} |
||||||
|
|
||||||
|
boolean subtex = false; |
||||||
|
int samples = image.getMultiSamples(); |
||||||
|
|
||||||
|
for (int i = 0; i < mipSizes.length; i++){ |
||||||
|
int mipWidth = Math.max(1, width >> i); |
||||||
|
int mipHeight = Math.max(1, height >> i); |
||||||
|
int mipDepth = Math.max(1, depth >> i); |
||||||
|
|
||||||
|
if (data != null){ |
||||||
|
data.position(pos); |
||||||
|
data.limit(pos + mipSizes[i]); |
||||||
|
} |
||||||
|
|
||||||
|
if (glFmt.compressed && data != null){ |
||||||
|
if (target == GL2.GL_TEXTURE_3D){ |
||||||
|
gl.getGL2().glCompressedTexImage3D(target, |
||||||
|
i, |
||||||
|
glFmt.internalFormat, |
||||||
|
mipWidth, |
||||||
|
mipHeight, |
||||||
|
mipDepth, |
||||||
|
0, |
||||||
|
border, |
||||||
|
data); |
||||||
|
}else{ |
||||||
|
//all other targets use 2D: array, cubemap, 2d
|
||||||
|
gl.getGL2().glCompressedTexImage2D(target, |
||||||
|
i, |
||||||
|
glFmt.internalFormat, |
||||||
|
mipWidth, |
||||||
|
mipHeight, |
||||||
|
0, |
||||||
|
border, |
||||||
|
data); |
||||||
|
} |
||||||
|
}else{ |
||||||
|
if (target == GL2.GL_TEXTURE_3D){ |
||||||
|
gl.getGL2().glTexImage3D(target, |
||||||
|
i, |
||||||
|
glFmt.internalFormat, |
||||||
|
mipWidth, |
||||||
|
mipHeight, |
||||||
|
mipDepth, |
||||||
|
border, |
||||||
|
glFmt.format, |
||||||
|
glFmt.dataType, |
||||||
|
data); |
||||||
|
}else if (target == GL.GL_TEXTURE_2D_ARRAY){ |
||||||
|
// prepare data for 2D array
|
||||||
|
// or upload slice
|
||||||
|
if (index == -1){ |
||||||
|
gl.getGL2().glTexImage3D(target, |
||||||
|
0, |
||||||
|
glFmt.internalFormat, |
||||||
|
mipWidth, |
||||||
|
mipHeight, |
||||||
|
image.getData().size(), //# of slices
|
||||||
|
border, |
||||||
|
glFmt.format, |
||||||
|
glFmt.dataType, |
||||||
|
data); |
||||||
|
}else{ |
||||||
|
gl.getGL2().glTexSubImage3D(target, |
||||||
|
i, // level
|
||||||
|
0, // xoffset
|
||||||
|
0, // yoffset
|
||||||
|
index, // zoffset
|
||||||
|
width, // width
|
||||||
|
height, // height
|
||||||
|
1, // depth
|
||||||
|
glFmt.format, |
||||||
|
glFmt.dataType, |
||||||
|
data); |
||||||
|
} |
||||||
|
}else{ |
||||||
|
if (subtex){ |
||||||
|
if (samples > 1){ |
||||||
|
throw new IllegalStateException("Cannot update multisample textures"); |
||||||
|
} |
||||||
|
|
||||||
|
gl.getGL2().glTexSubImage2D(target, |
||||||
|
i, |
||||||
|
0, 0, |
||||||
|
mipWidth, mipHeight, |
||||||
|
glFmt.format, |
||||||
|
glFmt.dataType, |
||||||
|
data); |
||||||
|
}else{ |
||||||
|
if (samples > 1){ |
||||||
|
gl.getGL2().glTexImage2DMultisample(target, |
||||||
|
samples, |
||||||
|
glFmt.internalFormat, |
||||||
|
mipWidth, |
||||||
|
mipHeight, |
||||||
|
true); |
||||||
|
}else{ |
||||||
|
gl.getGL2().glTexImage2D(target, |
||||||
|
i, |
||||||
|
glFmt.internalFormat, |
||||||
|
mipWidth, |
||||||
|
mipHeight, |
||||||
|
border, |
||||||
|
glFmt.format, |
||||||
|
glFmt.dataType, |
||||||
|
data); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pos += mipSizes[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,182 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.system.jogl; |
||||||
|
|
||||||
|
import com.jme3.input.KeyInput; |
||||||
|
import com.jme3.input.MouseInput; |
||||||
|
import com.jme3.input.TouchInput; |
||||||
|
import com.jme3.input.awt.AwtKeyInput; |
||||||
|
import com.jme3.input.awt.AwtMouseInput; |
||||||
|
import com.jme3.renderer.jogl.JoglRenderer; |
||||||
|
import com.jogamp.opengl.util.Animator; |
||||||
|
import com.jogamp.opengl.util.AnimatorBase; |
||||||
|
import com.jogamp.opengl.util.FPSAnimator; |
||||||
|
import java.awt.GraphicsDevice; |
||||||
|
import java.awt.GraphicsEnvironment; |
||||||
|
import java.util.concurrent.atomic.AtomicBoolean; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import javax.media.opengl.GLAutoDrawable; |
||||||
|
import javax.media.opengl.GLCapabilities; |
||||||
|
import javax.media.opengl.GLEventListener; |
||||||
|
import javax.media.opengl.GLProfile; |
||||||
|
import javax.media.opengl.awt.GLCanvas; |
||||||
|
|
||||||
|
public abstract class JoglAbstractDisplay extends JoglContext implements GLEventListener { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(JoglAbstractDisplay.class.getName()); |
||||||
|
|
||||||
|
protected GraphicsDevice device; |
||||||
|
|
||||||
|
protected GLCanvas canvas; |
||||||
|
|
||||||
|
protected AnimatorBase animator; |
||||||
|
|
||||||
|
protected AtomicBoolean active = new AtomicBoolean(false); |
||||||
|
|
||||||
|
protected boolean wasActive = false; |
||||||
|
|
||||||
|
protected int frameRate; |
||||||
|
|
||||||
|
protected boolean useAwt = true; |
||||||
|
|
||||||
|
protected AtomicBoolean autoFlush = new AtomicBoolean(true); |
||||||
|
|
||||||
|
protected boolean wasAnimating = false; |
||||||
|
|
||||||
|
protected void initGLCanvas() { |
||||||
|
device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); |
||||||
|
|
||||||
|
GLCapabilities caps = new GLCapabilities(GLProfile.getDefault()); |
||||||
|
caps.setHardwareAccelerated(true); |
||||||
|
caps.setDoubleBuffered(true); |
||||||
|
caps.setStencilBits(settings.getStencilBits()); |
||||||
|
caps.setDepthBits(settings.getDepthBits()); |
||||||
|
|
||||||
|
if (settings.getSamples() > 1) { |
||||||
|
caps.setSampleBuffers(true); |
||||||
|
caps.setNumSamples(settings.getSamples()); |
||||||
|
} |
||||||
|
|
||||||
|
canvas = new GLCanvas(caps) { |
||||||
|
@Override |
||||||
|
public void addNotify() { |
||||||
|
super.addNotify(); |
||||||
|
onCanvasAdded(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void removeNotify() { |
||||||
|
onCanvasRemoved(); |
||||||
|
super.removeNotify(); |
||||||
|
} |
||||||
|
}; |
||||||
|
if (settings.isVSync()) { |
||||||
|
// FIXME: it is too early to get the GL instance from the canvas
|
||||||
|
canvas.getGL().setSwapInterval(1); |
||||||
|
} |
||||||
|
canvas.setFocusable(true); |
||||||
|
canvas.setIgnoreRepaint(true); |
||||||
|
canvas.addGLEventListener(this); |
||||||
|
|
||||||
|
// N.B: it is too early to get the GL instance from the canvas
|
||||||
|
// if (false){
|
||||||
|
// trace mode
|
||||||
|
// jME already uses err stream, use out instead
|
||||||
|
// gl = new TraceGL(gl, System.out);
|
||||||
|
// }else if (false){
|
||||||
|
// debug mode
|
||||||
|
// gl = new DebugGL(gl);
|
||||||
|
// }else{
|
||||||
|
// production mode
|
||||||
|
// }
|
||||||
|
renderer = new JoglRenderer(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void startGLCanvas() { |
||||||
|
if (frameRate > 0) { |
||||||
|
animator = new FPSAnimator(canvas, frameRate); |
||||||
|
// ((FPSAnimator)animator).setRunAsFastAsPossible(true);
|
||||||
|
} |
||||||
|
else { |
||||||
|
animator = new Animator(canvas); |
||||||
|
((Animator) animator).setRunAsFastAsPossible(true); |
||||||
|
} |
||||||
|
|
||||||
|
animator.start(); |
||||||
|
wasAnimating = true; |
||||||
|
} |
||||||
|
|
||||||
|
protected void onCanvasAdded() { |
||||||
|
} |
||||||
|
|
||||||
|
protected void onCanvasRemoved() { |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public KeyInput getKeyInput() { |
||||||
|
return new AwtKeyInput(/*canvas*/); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public MouseInput getMouseInput() { |
||||||
|
return new AwtMouseInput(/*canvas*/); |
||||||
|
} |
||||||
|
|
||||||
|
public TouchInput getTouchInput() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public void setAutoFlushFrames(boolean enabled) { |
||||||
|
autoFlush.set(enabled); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Callback. |
||||||
|
*/ |
||||||
|
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { |
||||||
|
listener.reshape(width, height); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Callback. |
||||||
|
*/ |
||||||
|
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Callback |
||||||
|
*/ |
||||||
|
public void dispose(GLAutoDrawable drawable) { |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,129 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.system.jogl; |
||||||
|
|
||||||
|
import com.jme3.system.JmeCanvasContext; |
||||||
|
import java.awt.Canvas; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import javax.media.opengl.GLAutoDrawable; |
||||||
|
|
||||||
|
public class JoglCanvas extends JoglAbstractDisplay implements JmeCanvasContext { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(JoglCanvas.class.getName()); |
||||||
|
private int width, height; |
||||||
|
|
||||||
|
public JoglCanvas(){ |
||||||
|
super(); |
||||||
|
initGLCanvas(); |
||||||
|
} |
||||||
|
|
||||||
|
public Type getType() { |
||||||
|
return Type.Canvas; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTitle(String title) { |
||||||
|
} |
||||||
|
|
||||||
|
public void restart() { |
||||||
|
} |
||||||
|
|
||||||
|
public void create(boolean waitFor){ |
||||||
|
if (waitFor) |
||||||
|
waitFor(true); |
||||||
|
} |
||||||
|
|
||||||
|
public void destroy(boolean waitFor){ |
||||||
|
if (waitFor) |
||||||
|
waitFor(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onCanvasRemoved(){ |
||||||
|
super.onCanvasRemoved(); |
||||||
|
created.set(false); |
||||||
|
waitFor(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onCanvasAdded(){ |
||||||
|
startGLCanvas(); |
||||||
|
} |
||||||
|
|
||||||
|
public void init(GLAutoDrawable drawable) { |
||||||
|
canvas.requestFocus(); |
||||||
|
|
||||||
|
super.internalCreate(); |
||||||
|
logger.info("Display created."); |
||||||
|
|
||||||
|
renderer.initialize(); |
||||||
|
listener.initialize(); |
||||||
|
} |
||||||
|
|
||||||
|
public void display(GLAutoDrawable glad) { |
||||||
|
if (!created.get() && renderer != null){ |
||||||
|
listener.destroy(); |
||||||
|
logger.info("Canvas destroyed."); |
||||||
|
super.internalDestroy(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (width != canvas.getWidth() || height != canvas.getHeight()){ |
||||||
|
width = canvas.getWidth(); |
||||||
|
height = canvas.getHeight(); |
||||||
|
if (listener != null) |
||||||
|
listener.reshape(width, height); |
||||||
|
} |
||||||
|
|
||||||
|
boolean flush = autoFlush.get(); |
||||||
|
if (flush && !wasAnimating){ |
||||||
|
animator.start(); |
||||||
|
wasAnimating = true; |
||||||
|
}else if (!flush && wasAnimating){ |
||||||
|
animator.stop(); |
||||||
|
wasAnimating = false; |
||||||
|
} |
||||||
|
|
||||||
|
listener.update(); |
||||||
|
renderer.onFrame(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public Canvas getCanvas() { |
||||||
|
return canvas; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void dispose(GLAutoDrawable arg0) { |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,146 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.system.jogl; |
||||||
|
|
||||||
|
import com.jme3.input.JoyInput; |
||||||
|
import com.jme3.input.KeyInput; |
||||||
|
import com.jme3.input.MouseInput; |
||||||
|
import com.jme3.input.awt.AwtKeyInput; |
||||||
|
import com.jme3.input.awt.AwtMouseInput; |
||||||
|
import com.jme3.renderer.Renderer; |
||||||
|
import com.jme3.renderer.jogl.JoglRenderer; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import com.jme3.system.JmeContext; |
||||||
|
import com.jme3.system.NanoTimer; |
||||||
|
import com.jme3.system.SystemListener; |
||||||
|
import com.jme3.system.Timer; |
||||||
|
import java.util.concurrent.atomic.AtomicBoolean; |
||||||
|
|
||||||
|
public abstract class JoglContext implements JmeContext { |
||||||
|
|
||||||
|
protected AtomicBoolean created = new AtomicBoolean(false); |
||||||
|
protected AtomicBoolean renderable = new AtomicBoolean(false); |
||||||
|
protected final Object createdLock = new Object(); |
||||||
|
|
||||||
|
protected AppSettings settings = new AppSettings(true); |
||||||
|
protected JoglRenderer renderer; |
||||||
|
protected Timer timer; |
||||||
|
protected SystemListener listener; |
||||||
|
|
||||||
|
protected AwtKeyInput keyInput; |
||||||
|
protected AwtMouseInput mouseInput; |
||||||
|
|
||||||
|
public void setSystemListener(SystemListener listener){ |
||||||
|
this.listener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSettings(AppSettings settings) { |
||||||
|
this.settings.copyFrom(settings); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isRenderable(){ |
||||||
|
return renderable.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public AppSettings getSettings() { |
||||||
|
return settings; |
||||||
|
} |
||||||
|
|
||||||
|
public Renderer getRenderer() { |
||||||
|
return renderer; |
||||||
|
} |
||||||
|
|
||||||
|
public MouseInput getMouseInput() { |
||||||
|
return mouseInput; |
||||||
|
} |
||||||
|
|
||||||
|
public KeyInput getKeyInput() { |
||||||
|
return keyInput; |
||||||
|
} |
||||||
|
|
||||||
|
public JoyInput getJoyInput() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public Timer getTimer() { |
||||||
|
return timer; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isCreated() { |
||||||
|
return created.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public void create(){ |
||||||
|
create(false); |
||||||
|
} |
||||||
|
|
||||||
|
public void destroy(){ |
||||||
|
destroy(false); |
||||||
|
} |
||||||
|
|
||||||
|
protected void waitFor(boolean createdVal){ |
||||||
|
synchronized (createdLock){ |
||||||
|
while (created.get() != createdVal){ |
||||||
|
try { |
||||||
|
createdLock.wait(); |
||||||
|
} catch (InterruptedException ex) { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void internalCreate() { |
||||||
|
timer = new NanoTimer(); |
||||||
|
synchronized (createdLock){ |
||||||
|
created.set(true); |
||||||
|
createdLock.notifyAll(); |
||||||
|
} |
||||||
|
// renderer initialization must happen in subclass.
|
||||||
|
/*if (renderable.get()){ |
||||||
|
initContextFirstTime(); |
||||||
|
}else{ |
||||||
|
assert getType() == Type.Canvas; |
||||||
|
}*/ |
||||||
|
} |
||||||
|
|
||||||
|
protected void internalDestroy() { |
||||||
|
renderer = null; |
||||||
|
timer = null; |
||||||
|
renderable.set(false); |
||||||
|
synchronized (createdLock){ |
||||||
|
created.set(false); |
||||||
|
createdLock.notifyAll(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,307 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.system.jogl; |
||||||
|
|
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.Container; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.DisplayMode; |
||||||
|
import java.awt.Frame; |
||||||
|
import java.awt.Toolkit; |
||||||
|
import java.awt.event.WindowAdapter; |
||||||
|
import java.awt.event.WindowEvent; |
||||||
|
import java.lang.reflect.InvocationTargetException; |
||||||
|
import java.util.concurrent.atomic.AtomicBoolean; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import javax.media.opengl.GLAutoDrawable; |
||||||
|
import javax.swing.JFrame; |
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
|
||||||
|
public class JoglDisplay extends JoglAbstractDisplay { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(JoglDisplay.class.getName()); |
||||||
|
|
||||||
|
protected AtomicBoolean windowCloseRequest = new AtomicBoolean(false); |
||||||
|
protected AtomicBoolean needClose = new AtomicBoolean(false); |
||||||
|
protected AtomicBoolean needRestart = new AtomicBoolean(false); |
||||||
|
protected boolean wasInited = false; |
||||||
|
protected Frame frame; |
||||||
|
|
||||||
|
public Type getType() { |
||||||
|
return Type.Display; |
||||||
|
} |
||||||
|
|
||||||
|
protected DisplayMode getFullscreenDisplayMode(DisplayMode[] modes, int width, int height, int bpp, int freq){ |
||||||
|
for (DisplayMode mode : modes){ |
||||||
|
if (mode.getWidth() == width |
||||||
|
&& mode.getHeight() == height |
||||||
|
&& (mode.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI |
||||||
|
|| mode.getBitDepth() == bpp |
||||||
|
|| (mode.getBitDepth() == 32 && bpp==24)) |
||||||
|
&& mode.getRefreshRate() == freq){ |
||||||
|
return mode; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
protected void createGLFrame(){ |
||||||
|
Container contentPane; |
||||||
|
if (useAwt){ |
||||||
|
frame = new Frame(settings.getTitle()); |
||||||
|
contentPane = frame; |
||||||
|
}else{ |
||||||
|
frame = new JFrame(settings.getTitle()); |
||||||
|
contentPane = ((JFrame)frame).getContentPane(); |
||||||
|
} |
||||||
|
|
||||||
|
contentPane.setLayout(new BorderLayout()); |
||||||
|
|
||||||
|
applySettings(settings); |
||||||
|
|
||||||
|
frame.setResizable(false); |
||||||
|
frame.setFocusable(true); |
||||||
|
|
||||||
|
// only add canvas after frame is visible
|
||||||
|
contentPane.add(canvas, BorderLayout.CENTER); |
||||||
|
//frame.pack();
|
||||||
|
// frame.setSize(contentPane.getPreferredSize());
|
||||||
|
frame.setSize(settings.getWidth(),settings.getHeight()); |
||||||
|
|
||||||
|
if (device.getFullScreenWindow() == null){ |
||||||
|
// now that canvas is attached,
|
||||||
|
// determine optimal size to contain it
|
||||||
|
|
||||||
|
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); |
||||||
|
frame.setLocation((screenSize.width - frame.getWidth()) / 2, |
||||||
|
(screenSize.height - frame.getHeight()) / 2); |
||||||
|
} |
||||||
|
|
||||||
|
frame.addWindowListener(new WindowAdapter() { |
||||||
|
@Override |
||||||
|
public void windowClosing(WindowEvent evt) { |
||||||
|
windowCloseRequest.set(true); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void windowActivated(WindowEvent evt) { |
||||||
|
active.set(true); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void windowDeactivated(WindowEvent evt) { |
||||||
|
active.set(false); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
protected void applySettings(AppSettings settings){ |
||||||
|
DisplayMode displayMode; |
||||||
|
if (settings.getWidth() <= 0 || settings.getHeight() <= 0){ |
||||||
|
displayMode = device.getDisplayMode(); |
||||||
|
settings.setResolution(displayMode.getWidth(), displayMode.getHeight()); |
||||||
|
}else if (settings.isFullscreen()){ |
||||||
|
displayMode = getFullscreenDisplayMode(device.getDisplayModes(), |
||||||
|
settings.getWidth(), settings.getHeight(), |
||||||
|
settings.getBitsPerPixel(), settings.getFrequency()); |
||||||
|
if (displayMode == null) |
||||||
|
throw new RuntimeException("Unable to find fullscreen display mode matching settings"); |
||||||
|
}else{ |
||||||
|
displayMode = new DisplayMode(settings.getWidth(), settings.getHeight(), DisplayMode.BIT_DEPTH_MULTI, DisplayMode.REFRESH_RATE_UNKNOWN); |
||||||
|
} |
||||||
|
|
||||||
|
// FIXME: seems to return false even though
|
||||||
|
// it is supported..
|
||||||
|
// if (!device.isDisplayChangeSupported()){
|
||||||
|
// // must use current device mode if display mode change not supported
|
||||||
|
// displayMode = device.getDisplayMode();
|
||||||
|
// settings.setResolution(displayMode.getWidth(), displayMode.getHeight());
|
||||||
|
// }
|
||||||
|
|
||||||
|
frameRate = settings.getFrameRate(); |
||||||
|
logger.log(Level.INFO, "Selected display mode: {0}x{1}x{2} @{3}", |
||||||
|
new Object[]{displayMode.getWidth(), |
||||||
|
displayMode.getHeight(), |
||||||
|
displayMode.getBitDepth(), |
||||||
|
displayMode.getRefreshRate()}); |
||||||
|
|
||||||
|
canvas.setSize(displayMode.getWidth(), displayMode.getHeight()); |
||||||
|
|
||||||
|
DisplayMode prevDisplayMode = device.getDisplayMode(); |
||||||
|
|
||||||
|
if (settings.isFullscreen() && device.isFullScreenSupported()){ |
||||||
|
frame.setUndecorated(true); |
||||||
|
|
||||||
|
try{ |
||||||
|
device.setFullScreenWindow(frame); |
||||||
|
if (!prevDisplayMode.equals(displayMode) |
||||||
|
&& device.isDisplayChangeSupported()){ |
||||||
|
device.setDisplayMode(displayMode); |
||||||
|
} |
||||||
|
} catch (Throwable t){ |
||||||
|
logger.log(Level.SEVERE, "Failed to enter fullscreen mode", t); |
||||||
|
device.setFullScreenWindow(null); |
||||||
|
} |
||||||
|
}else{ |
||||||
|
if (!device.isFullScreenSupported()){ |
||||||
|
logger.warning("Fullscreen not supported."); |
||||||
|
}else{ |
||||||
|
frame.setUndecorated(false); |
||||||
|
device.setFullScreenWindow(null); |
||||||
|
} |
||||||
|
|
||||||
|
frame.setVisible(true); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void initInEDT(){ |
||||||
|
initGLCanvas(); |
||||||
|
|
||||||
|
createGLFrame(); |
||||||
|
|
||||||
|
startGLCanvas(); |
||||||
|
} |
||||||
|
|
||||||
|
public void init(GLAutoDrawable drawable){ |
||||||
|
// prevent initializing twice on restart
|
||||||
|
if (!wasInited){ |
||||||
|
canvas.requestFocus(); |
||||||
|
|
||||||
|
super.internalCreate(); |
||||||
|
logger.info("Display created."); |
||||||
|
|
||||||
|
renderer.initialize(); |
||||||
|
listener.initialize(); |
||||||
|
|
||||||
|
wasInited = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void create(boolean waitFor){ |
||||||
|
try { |
||||||
|
if (waitFor){ |
||||||
|
try{ |
||||||
|
SwingUtilities.invokeAndWait(new Runnable() { |
||||||
|
public void run() { |
||||||
|
initInEDT(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} catch (InterruptedException ex) { |
||||||
|
listener.handleError("Interrupted", ex); |
||||||
|
} |
||||||
|
}else{ |
||||||
|
SwingUtilities.invokeLater(new Runnable() { |
||||||
|
public void run() { |
||||||
|
initInEDT(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} catch (InvocationTargetException ex) { |
||||||
|
throw new AssertionError(); // can never happen
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void destroy(boolean waitFor){ |
||||||
|
needClose.set(true); |
||||||
|
if (waitFor){ |
||||||
|
waitFor(false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void restart() { |
||||||
|
if (created.get()){ |
||||||
|
needRestart.set(true); |
||||||
|
}else{ |
||||||
|
throw new IllegalStateException("Display not started yet. Cannot restart"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void setTitle(String title){ |
||||||
|
if (frame != null) |
||||||
|
frame.setTitle(title); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Callback. |
||||||
|
*/ |
||||||
|
public void display(GLAutoDrawable drawable) { |
||||||
|
if (needClose.get()) { |
||||||
|
listener.destroy(); |
||||||
|
animator.stop(); |
||||||
|
if (settings.isFullscreen()) { |
||||||
|
device.setFullScreenWindow(null); |
||||||
|
} |
||||||
|
frame.dispose(); |
||||||
|
logger.info("Display destroyed."); |
||||||
|
super.internalDestroy(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (windowCloseRequest.get()){ |
||||||
|
listener.requestClose(false); |
||||||
|
windowCloseRequest.set(false); |
||||||
|
} |
||||||
|
|
||||||
|
if (needRestart.getAndSet(false)){ |
||||||
|
// for restarting contexts
|
||||||
|
if (frame.isVisible()){ |
||||||
|
animator.stop(); |
||||||
|
frame.dispose(); |
||||||
|
createGLFrame(); |
||||||
|
startGLCanvas(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// boolean flush = autoFlush.get();
|
||||||
|
// if (animator.isAnimating() != flush){
|
||||||
|
// if (flush)
|
||||||
|
// animator.stop();
|
||||||
|
// else
|
||||||
|
// animator.start();
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (wasActive != active.get()){ |
||||||
|
if (!wasActive){ |
||||||
|
listener.gainFocus(); |
||||||
|
wasActive = true; |
||||||
|
}else{ |
||||||
|
listener.loseFocus(); |
||||||
|
wasActive = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
listener.update(); |
||||||
|
renderer.onFrame(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue