diff --git a/.gitignore b/.gitignore index 09d505187..6b6f30e2d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /jme3-desktop/build/ /jme3-android-native/build/ /jme3-android/build/ +/jme3-android-examples/build/ /jme3-blender/build/ /jme3-effects/build/ /jme3-bullet/build/ diff --git a/build.gradle b/build.gradle index adb31217b..8e6790230 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,23 @@ import org.gradle.api.artifacts.* -apply plugin: 'base' // To add "clean" task to the root project. -//apply plugin: 'java-library-distribution' +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.0' + } +} + +apply plugin: 'base' // This is applied to all sub projects subprojects { - // Don't add to native builds - // if(!project.name.endsWith('native')){ - apply from: rootProject.file('common.gradle') - // } + if(!project.name.equals('jme3-android-examples')) { + apply from: rootProject.file('common.gradle') + } else { + apply from: rootProject.file('common-android-app.gradle') + } } task run(dependsOn: ':jme3-examples:run') { @@ -166,11 +175,11 @@ ext { // } //} -allprojects { - tasks.withType(JavaExec) { - enableAssertions = true // false by default - } - tasks.withType(Test) { - enableAssertions = true // true by default - } -} \ No newline at end of file +//allprojects { +// tasks.withType(JavaExec) { +// enableAssertions = true // false by default +// } +// tasks.withType(Test) { +// enableAssertions = true // true by default +// } +//} \ No newline at end of file diff --git a/common-android-app.gradle b/common-android-app.gradle new file mode 100644 index 000000000..0ec48fbd7 --- /dev/null +++ b/common-android-app.gradle @@ -0,0 +1,13 @@ +apply plugin: 'com.android.application' + +group = 'com.jme3' +version = jmeVersion + '-' + jmeVersionTag + +sourceCompatibility = '1.6' + +repositories { + mavenCentral() + maven { + url "http://nifty-gui.sourceforge.net/nifty-maven-repo" + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index ccc3ed460..a00139bdf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,6 +11,7 @@ buildJavaDoc = true # specify if SDK and Native libraries get built buildSdkProject = true buildNativeProjects = false +buildAndroidExamples = false # Path to android NDK for building native libraries #ndkPath=/Users/normenhansen/Documents/Code-Import/android-ndk-r7 diff --git a/jme3-android-examples/build.gradle b/jme3-android-examples/build.gradle new file mode 100644 index 000000000..f1ee38739 --- /dev/null +++ b/jme3-android-examples/build.gradle @@ -0,0 +1,40 @@ +dependencies { + compile project(':jme3-core') + compile project(':jme3-android') + compile project(':jme3-effects') + compile project(':jme3-bullet') + compile project(':jme3-bullet-native-android') + compile project(':jme3-networking') + compile project(':jme3-niftygui') + compile project(':jme3-plugins') + compile project(':jme3-terrain') + compile project(':jme3-testdata') +} + +android { + compileSdkVersion 10 + buildToolsVersion "22.0.1" + + lintOptions { + // Fix nifty gui referencing "java.awt" package. + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "com.jme3.android" + minSdkVersion 10 // Android 2.3 GINGERBREAD + targetSdkVersion 22 // Android 5.1 LOLLIPOP + versionCode 1 + versionName "1.0" // TODO: from settings.gradle + } + + buildTypes { + release { + minifyEnabled false + } + debug { + applicationIdSuffix ".debug" + debuggable true + } + } +} \ No newline at end of file diff --git a/jme3-android-examples/src/main/AndroidManifest.xml b/jme3-android-examples/src/main/AndroidManifest.xml new file mode 100644 index 000000000..ee80b6b28 --- /dev/null +++ b/jme3-android-examples/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jme3-android-examples/src/main/java/jme3test/android/TestChooserAndroid.java b/jme3-android-examples/src/main/java/jme3test/android/TestChooserAndroid.java new file mode 100644 index 000000000..e704bc85a --- /dev/null +++ b/jme3-android-examples/src/main/java/jme3test/android/TestChooserAndroid.java @@ -0,0 +1,12 @@ +package jme3test.android; + +import android.content.pm.ActivityInfo; +import android.app.*; +import android.os.Bundle; + +public class TestChooserAndroid extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } +} \ No newline at end of file diff --git a/jme3-android-examples/src/main/res/values/strings.xml b/jme3-android-examples/src/main/res/values/strings.xml new file mode 100644 index 000000000..b184fa936 --- /dev/null +++ b/jme3-android-examples/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + JMEAndroidTest + About + Quit + \ No newline at end of file diff --git a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java b/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java deleted file mode 100644 index 462715f37..000000000 --- a/jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java +++ /dev/null @@ -1,2549 +0,0 @@ -/* - * 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.android; - -import android.opengl.GLES20; -import android.os.Build; -import com.jme3.asset.AndroidImageInfo; -import com.jme3.light.LightList; -import com.jme3.material.RenderState; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; -import com.jme3.math.Vector4f; -import com.jme3.renderer.Caps; -import com.jme3.renderer.IDList; -import com.jme3.renderer.RenderContext; -import com.jme3.renderer.Renderer; -import com.jme3.renderer.RendererException; -import com.jme3.renderer.Statistics; -import com.jme3.renderer.android.TextureUtil.AndroidGLImageFormat; -import com.jme3.renderer.opengl.GLRenderer; -import com.jme3.scene.Mesh; -import com.jme3.scene.Mesh.Mode; -import com.jme3.scene.VertexBuffer; -import com.jme3.scene.VertexBuffer.Format; -import com.jme3.scene.VertexBuffer.Type; -import com.jme3.scene.VertexBuffer.Usage; -import com.jme3.shader.Attribute; -import com.jme3.shader.Shader; -import com.jme3.shader.Shader.ShaderSource; -import com.jme3.shader.Shader.ShaderType; -import com.jme3.shader.Uniform; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.FrameBuffer.RenderBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapAxis; -import com.jme3.util.BufferUtils; -import com.jme3.util.ListMap; -import com.jme3.util.NativeObjectManager; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; -import java.util.EnumSet; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import jme3tools.shader.ShaderDebug; - -/** - * @deprecated Should not be used anymore. Use {@link GLRenderer} instead. - */ -@Deprecated -public class OGLESShaderRenderer implements Renderer { - - private static final Logger logger = Logger.getLogger(OGLESShaderRenderer.class.getName()); - private static final boolean VALIDATE_SHADER = false; - private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); - private final StringBuilder stringBuf = new StringBuilder(250); - private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); - private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16); - private final RenderContext context = new RenderContext(); - private final NativeObjectManager objManager = new NativeObjectManager(); - private final EnumSet caps = EnumSet.noneOf(Caps.class); - // current state - private Shader boundShader; - // initalDrawBuf and initialReadBuf are not used on ES, - // http://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindFramebuffer.xml - //private int initialDrawBuf, initialReadBuf; - private int glslVer; - private int vertexTextureUnits; - private int fragTextureUnits; - private int vertexUniforms; - private int fragUniforms; - private int vertexAttribs; -// private int maxFBOSamples; - private final int maxFBOAttachs = 1; // Only 1 color attachment on ES - private final int maxMRTFBOAttachs = 1; // FIXME for now, not sure if > 1 is needed for ES - private int maxRBSize; - private int maxTexSize; - private int maxCubeTexSize; - private int maxVertCount; - private int maxTriCount; - private boolean tdc; - private FrameBuffer lastFb = null; - private FrameBuffer mainFbOverride = null; - private final Statistics statistics = new Statistics(); - private int vpX, vpY, vpW, vpH; - private int clipX, clipY, clipW, clipH; - //private final GL10 gl; - private boolean powerVr = false; - private boolean useVBO = false; - - public OGLESShaderRenderer() { - } - - protected void updateNameBuffer() { - int len = stringBuf.length(); - - nameBuf.position(0); - nameBuf.limit(len); - for (int i = 0; i < len; i++) { - nameBuf.put((byte) stringBuf.charAt(i)); - } - - nameBuf.rewind(); - } - - public Statistics getStatistics() { - return statistics; - } - - public EnumSet getCaps() { - return caps; - } - - private static final Pattern VERSION = Pattern.compile(".*?(\\d+)\\.(\\d+).*"); - - public static int extractVersion(String version) { - - Matcher m = VERSION.matcher(version); - if (m.matches()) { - int major = Integer.parseInt(m.group(1)); - int minor = Integer.parseInt(m.group(2)); - - return major * 100 + minor * 10; - } else { - return -1; - } - } - - public void initialize() { - logger.log(Level.FINE, "Vendor: {0}", GLES20.glGetString(GLES20.GL_VENDOR)); - logger.log(Level.FINE, "Renderer: {0}", GLES20.glGetString(GLES20.GL_RENDERER)); - logger.log(Level.FINE, "Version: {0}", GLES20.glGetString(GLES20.GL_VERSION)); - logger.log(Level.FINE, "Shading Language Version: {0}", GLES20.glGetString(GLES20.GL_SHADING_LANGUAGE_VERSION)); - - powerVr = GLES20.glGetString(GLES20.GL_RENDERER).contains("PowerVR"); - - - //workaround, always assume we support GLSL100 - //some cards just don't report this correctly - caps.add(Caps.GLSL100); - - /* - // Fix issue in TestRenderToMemory when GL_FRONT is the main - // buffer being used. - initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); - initialReadBuf = glGetInteger(GL_READ_BUFFER); - - // XXX: This has to be GL_BACK for canvas on Mac - // Since initialDrawBuf is GL_FRONT for pbuffer, gotta - // change this value later on ... -// initialDrawBuf = GL_BACK; -// initialReadBuf = GL_BACK; - */ - - // Check OpenGL version - int openGlVer = extractVersion(GLES20.glGetString(GLES20.GL_VERSION)); - if (openGlVer == -1) { - glslVer = -1; - throw new UnsupportedOperationException("OpenGL ES 2.0+ is required for OGLESShaderRenderer!"); - } - - // Check shader language version - glslVer = extractVersion(GLES20.glGetString(GLES20.GL_SHADING_LANGUAGE_VERSION)); - switch (glslVer) { - // TODO: When new versions of OpenGL ES shader language come out, - // update this. - default: - caps.add(Caps.GLSL100); - break; - } - - GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, intBuf16); - vertexTextureUnits = intBuf16.get(0); - logger.log(Level.FINE, "VTF Units: {0}", vertexTextureUnits); - if (vertexTextureUnits > 0) { - caps.add(Caps.VertexTextureFetch); - } - - GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_IMAGE_UNITS, intBuf16); - fragTextureUnits = intBuf16.get(0); - logger.log(Level.FINE, "Texture Units: {0}", fragTextureUnits); - - // Multiply vector count by 4 to get float count. - GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, intBuf16); - vertexUniforms = intBuf16.get(0) * 4; - logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); - - GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, intBuf16); - fragUniforms = intBuf16.get(0) * 4; - logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); - - GLES20.glGetIntegerv(GLES20.GL_MAX_VARYING_VECTORS, intBuf16); - int varyingFloats = intBuf16.get(0) * 4; - logger.log(Level.FINER, "Varying Floats: {0}", varyingFloats); - - GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_ATTRIBS, intBuf16); - vertexAttribs = intBuf16.get(0); - logger.log(Level.FINE, "Vertex Attributes: {0}", vertexAttribs); - - GLES20.glGetIntegerv(GLES20.GL_SUBPIXEL_BITS, intBuf16); - int subpixelBits = intBuf16.get(0); - logger.log(Level.FINE, "Subpixel Bits: {0}", subpixelBits); - -// GLES10.glGetIntegerv(GLES10.GL_MAX_ELEMENTS_VERTICES, intBuf16); -// maxVertCount = intBuf16.get(0); -// logger.log(Level.FINER, "Preferred Batch Vertex Count: {0}", maxVertCount); -// -// GLES10.glGetIntegerv(GLES10.GL_MAX_ELEMENTS_INDICES, intBuf16); -// maxTriCount = intBuf16.get(0); -// logger.log(Level.FINER, "Preferred Batch Index Count: {0}", maxTriCount); - - GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, intBuf16); - maxTexSize = intBuf16.get(0); - logger.log(Level.FINE, "Maximum Texture Resolution: {0}", maxTexSize); - - GLES20.glGetIntegerv(GLES20.GL_MAX_CUBE_MAP_TEXTURE_SIZE, intBuf16); - maxCubeTexSize = intBuf16.get(0); - logger.log(Level.FINE, "Maximum CubeMap Resolution: {0}", maxCubeTexSize); - - GLES20.glGetIntegerv(GLES20.GL_MAX_RENDERBUFFER_SIZE, intBuf16); - maxRBSize = intBuf16.get(0); - logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); - - /* - if (ctxCaps.GL_ARB_color_buffer_float){ - // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. - if (ctxCaps.GL_ARB_half_float_pixel){ - caps.add(Caps.FloatColorBuffer); - } - } - - if (ctxCaps.GL_ARB_depth_buffer_float){ - caps.add(Caps.FloatDepthBuffer); - } - - if (ctxCaps.GL_ARB_draw_instanced) - caps.add(Caps.MeshInstancing); - - if (ctxCaps.GL_ARB_texture_buffer_object) - caps.add(Caps.TextureBuffer); - - if (ctxCaps.GL_ARB_texture_float){ - if (ctxCaps.GL_ARB_half_float_pixel){ - caps.add(Caps.FloatTexture); - } - } - - if (ctxCaps.GL_EXT_packed_float){ - caps.add(Caps.PackedFloatColorBuffer); - if (ctxCaps.GL_ARB_half_float_pixel){ - // because textures are usually uploaded as RGB16F - // need half-float pixel - caps.add(Caps.PackedFloatTexture); - } - } - - if (ctxCaps.GL_EXT_texture_array) - caps.add(Caps.TextureArray); - - if (ctxCaps.GL_EXT_texture_shared_exponent) - caps.add(Caps.SharedExponentTexture); - - if (ctxCaps.GL_EXT_framebuffer_object){ - caps.add(Caps.FrameBuffer); - - glGetInteger(GL_MAX_RENDERBUFFER_SIZE_EXT, intBuf16); - maxRBSize = intBuf16.get(0); - logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); - - glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT, intBuf16); - maxFBOAttachs = intBuf16.get(0); - logger.log(Level.FINER, "FBO Max renderbuffers: {0}", maxFBOAttachs); - - if (ctxCaps.GL_EXT_framebuffer_multisample){ - caps.add(Caps.FrameBufferMultisample); - - glGetInteger(GL_MAX_SAMPLES_EXT, intBuf16); - maxFBOSamples = intBuf16.get(0); - logger.log(Level.FINER, "FBO Max Samples: {0}", maxFBOSamples); - } - - if (ctxCaps.GL_ARB_draw_buffers){ - caps.add(Caps.FrameBufferMRT); - glGetInteger(ARBDrawBuffers.GL_MAX_DRAW_BUFFERS_ARB, intBuf16); - maxMRTFBOAttachs = intBuf16.get(0); - logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); - } - } - - if (ctxCaps.GL_ARB_multisample){ - glGetInteger(ARBMultisample.GL_SAMPLE_BUFFERS_ARB, intBuf16); - boolean available = intBuf16.get(0) != 0; - glGetInteger(ARBMultisample.GL_SAMPLES_ARB, intBuf16); - int samples = intBuf16.get(0); - logger.log(Level.FINER, "Samples: {0}", samples); - boolean enabled = glIsEnabled(ARBMultisample.GL_MULTISAMPLE_ARB); - if (samples > 0 && available && !enabled){ - glEnable(ARBMultisample.GL_MULTISAMPLE_ARB); - } - } - */ - - String extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS); - logger.log(Level.FINE, "GL_EXTENSIONS: {0}", extensions); - - // Get number of compressed formats available. - GLES20.glGetIntegerv(GLES20.GL_NUM_COMPRESSED_TEXTURE_FORMATS, intBuf16); - int numCompressedFormats = intBuf16.get(0); - - // Allocate buffer for compressed formats. - IntBuffer compressedFormats = BufferUtils.createIntBuffer(numCompressedFormats); - GLES20.glGetIntegerv(GLES20.GL_COMPRESSED_TEXTURE_FORMATS, compressedFormats); - - // Check for errors after all glGet calls. - RendererUtil.checkGLError(); - - // Print compressed formats. - for (int i = 0; i < numCompressedFormats; i++) { - logger.log(Level.FINE, "Compressed Texture Formats: {0}", compressedFormats.get(i)); - } - - TextureUtil.loadTextureFeatures(extensions); - - applyRenderState(RenderState.DEFAULT); - GLES20.glDisable(GLES20.GL_DITHER); - RendererUtil.checkGLError(); - - useVBO = false; - - // NOTE: SDK_INT is only available since 1.6, - // but for jME3 it doesn't matter since android versions 1.5 and below - // are not supported. - if (Build.VERSION.SDK_INT >= 9){ - logger.log(Level.FINE, "Force-enabling VBO (Android 2.3 or higher)"); - useVBO = true; - } else { - useVBO = false; - } - - logger.log(Level.FINE, "Caps: {0}", caps); - } - - /** - * resetGLObjects should be called when die GLView gets recreated to reset all GPU objects - */ - public void resetGLObjects() { - objManager.resetObjects(); - statistics.clearMemory(); - boundShader = null; - lastFb = null; - context.reset(); - } - - public void cleanup() { - objManager.deleteAllObjects(this); - statistics.clearMemory(); - } - - private void checkCap(Caps cap) { - if (!caps.contains(cap)) { - throw new UnsupportedOperationException("Required capability missing: " + cap.name()); - } - } - - /*********************************************************************\ - |* Render State *| - \*********************************************************************/ - public void setDepthRange(float start, float end) { - GLES20.glDepthRangef(start, end); - RendererUtil.checkGLError(); - } - - public void clearBuffers(boolean color, boolean depth, boolean stencil) { - int bits = 0; - if (color) { - //See explanations of the depth below, we must enable color write to be able to clear the color buffer - if (context.colorWriteEnabled == false) { - GLES20.glColorMask(true, true, true, true); - context.colorWriteEnabled = true; - } - bits = GLES20.GL_COLOR_BUFFER_BIT; - } - if (depth) { - //glClear(GL_DEPTH_BUFFER_BIT) seems to not work when glDepthMask is false - //here s some link on openl board - //http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=257223 - //if depth clear is requested, we enable the depthMask - if (context.depthWriteEnabled == false) { - GLES20.glDepthMask(true); - context.depthWriteEnabled = true; - } - bits |= GLES20.GL_DEPTH_BUFFER_BIT; - } - if (stencil) { - bits |= GLES20.GL_STENCIL_BUFFER_BIT; - } - if (bits != 0) { - GLES20.glClear(bits); - RendererUtil.checkGLError(); - } - } - - public void setBackgroundColor(ColorRGBA color) { - GLES20.glClearColor(color.r, color.g, color.b, color.a); - RendererUtil.checkGLError(); - } - - public void applyRenderState(RenderState state) { - /* - if (state.isWireframe() && !context.wireframe){ - GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_LINE); - context.wireframe = true; - }else if (!state.isWireframe() && context.wireframe){ - GLES20.glPolygonMode(GLES20.GL_FRONT_AND_BACK, GLES20.GL_FILL); - context.wireframe = false; - } - */ - if (state.isDepthTest() && !context.depthTestEnabled) { - GLES20.glEnable(GLES20.GL_DEPTH_TEST); - GLES20.glDepthFunc(convertTestFunction(context.depthFunc)); - RendererUtil.checkGLError(); - context.depthTestEnabled = true; - } else if (!state.isDepthTest() && context.depthTestEnabled) { - GLES20.glDisable(GLES20.GL_DEPTH_TEST); - RendererUtil.checkGLError(); - context.depthTestEnabled = false; - } - if (state.getDepthFunc() != context.depthFunc) { - GLES20.glDepthFunc(convertTestFunction(state.getDepthFunc())); - context.depthFunc = state.getDepthFunc(); - } - - if (state.isDepthWrite() && !context.depthWriteEnabled) { - GLES20.glDepthMask(true); - RendererUtil.checkGLError(); - context.depthWriteEnabled = true; - } else if (!state.isDepthWrite() && context.depthWriteEnabled) { - GLES20.glDepthMask(false); - RendererUtil.checkGLError(); - context.depthWriteEnabled = false; - } - if (state.isColorWrite() && !context.colorWriteEnabled) { - GLES20.glColorMask(true, true, true, true); - RendererUtil.checkGLError(); - context.colorWriteEnabled = true; - } else if (!state.isColorWrite() && context.colorWriteEnabled) { - GLES20.glColorMask(false, false, false, false); - RendererUtil.checkGLError(); - context.colorWriteEnabled = false; - } -// if (state.isPointSprite() && !context.pointSprite) { -//// GLES20.glEnable(GLES20.GL_POINT_SPRITE); -//// GLES20.glTexEnvi(GLES20.GL_POINT_SPRITE, GLES20.GL_COORD_REPLACE, GLES20.GL_TRUE); -//// GLES20.glEnable(GLES20.GL_VERTEX_PROGRAM_POINT_SIZE); -//// GLES20.glPointParameterf(GLES20.GL_POINT_SIZE_MIN, 1.0f); -// } else if (!state.isPointSprite() && context.pointSprite) { -//// GLES20.glDisable(GLES20.GL_POINT_SPRITE); -// } - - if (state.isPolyOffset()) { - if (!context.polyOffsetEnabled) { - GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL); - GLES20.glPolygonOffset(state.getPolyOffsetFactor(), - state.getPolyOffsetUnits()); - RendererUtil.checkGLError(); - - context.polyOffsetEnabled = true; - context.polyOffsetFactor = state.getPolyOffsetFactor(); - context.polyOffsetUnits = state.getPolyOffsetUnits(); - } else { - if (state.getPolyOffsetFactor() != context.polyOffsetFactor - || state.getPolyOffsetUnits() != context.polyOffsetUnits) { - GLES20.glPolygonOffset(state.getPolyOffsetFactor(), - state.getPolyOffsetUnits()); - RendererUtil.checkGLError(); - - context.polyOffsetFactor = state.getPolyOffsetFactor(); - context.polyOffsetUnits = state.getPolyOffsetUnits(); - } - } - } else { - if (context.polyOffsetEnabled) { - GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL); - RendererUtil.checkGLError(); - - context.polyOffsetEnabled = false; - context.polyOffsetFactor = 0; - context.polyOffsetUnits = 0; - } - } - if (state.getFaceCullMode() != context.cullMode) { - if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) { - GLES20.glDisable(GLES20.GL_CULL_FACE); - RendererUtil.checkGLError(); - } else { - GLES20.glEnable(GLES20.GL_CULL_FACE); - RendererUtil.checkGLError(); - } - - switch (state.getFaceCullMode()) { - case Off: - break; - case Back: - GLES20.glCullFace(GLES20.GL_BACK); - RendererUtil.checkGLError(); - break; - case Front: - GLES20.glCullFace(GLES20.GL_FRONT); - RendererUtil.checkGLError(); - break; - case FrontAndBack: - GLES20.glCullFace(GLES20.GL_FRONT_AND_BACK); - RendererUtil.checkGLError(); - break; - default: - throw new UnsupportedOperationException("Unrecognized face cull mode: " - + state.getFaceCullMode()); - } - - context.cullMode = state.getFaceCullMode(); - } - - if (state.getBlendMode() != context.blendMode) { - if (state.getBlendMode() == RenderState.BlendMode.Off) { - GLES20.glDisable(GLES20.GL_BLEND); - RendererUtil.checkGLError(); - } else { - GLES20.glEnable(GLES20.GL_BLEND); - switch (state.getBlendMode()) { - case Off: - break; - case Additive: - GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE); - break; - case AlphaAdditive: - GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE); - break; - case Color: - GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_COLOR); - break; - case Alpha: - GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); - break; - case PremultAlpha: - GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); - break; - case Modulate: - GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_ZERO); - break; - case ModulateX2: - GLES20.glBlendFunc(GLES20.GL_DST_COLOR, GLES20.GL_SRC_COLOR); - break; - case Screen: - GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_COLOR); - break; - case Exclusion: - GLES20.glBlendFunc(GLES20.GL_ONE_MINUS_DST_COLOR, GLES20.GL_ONE_MINUS_SRC_COLOR); - break; - default: - throw new UnsupportedOperationException("Unrecognized blend mode: " - + state.getBlendMode()); - } - RendererUtil.checkGLError(); - } - context.blendMode = state.getBlendMode(); - } - } - - /*********************************************************************\ - |* Camera and World transforms *| - \*********************************************************************/ - public void setViewPort(int x, int y, int w, int h) { - if (x != vpX || vpY != y || vpW != w || vpH != h) { - GLES20.glViewport(x, y, w, h); - RendererUtil.checkGLError(); - - vpX = x; - vpY = y; - vpW = w; - vpH = h; - } - } - - public void setClipRect(int x, int y, int width, int height) { - if (!context.clipRectEnabled) { - GLES20.glEnable(GLES20.GL_SCISSOR_TEST); - RendererUtil.checkGLError(); - context.clipRectEnabled = true; - } - if (clipX != x || clipY != y || clipW != width || clipH != height) { - GLES20.glScissor(x, y, width, height); - RendererUtil.checkGLError(); - clipX = x; - clipY = y; - clipW = width; - clipH = height; - } - } - - public void clearClipRect() { - if (context.clipRectEnabled) { - GLES20.glDisable(GLES20.GL_SCISSOR_TEST); - RendererUtil.checkGLError(); - context.clipRectEnabled = false; - - clipX = 0; - clipY = 0; - clipW = 0; - clipH = 0; - } - } - - public void postFrame() { - RendererUtil.checkGLErrorForced(); - - objManager.deleteUnused(this); - } - - /*********************************************************************\ - |* Shaders *| - \*********************************************************************/ - protected void updateUniformLocation(Shader shader, Uniform uniform) { - stringBuf.setLength(0); - stringBuf.append(uniform.getName()).append('\0'); - updateNameBuffer(); - int loc = GLES20.glGetUniformLocation(shader.getId(), uniform.getName()); - RendererUtil.checkGLError(); - - if (loc < 0) { - uniform.setLocation(-1); - // uniform is not declared in shader - } else { - uniform.setLocation(loc); - } - } - - protected void bindProgram(Shader shader) { - int shaderId = shader.getId(); - if (context.boundShaderProgram != shaderId) { - GLES20.glUseProgram(shaderId); - RendererUtil.checkGLError(); - - statistics.onShaderUse(shader, true); - boundShader = shader; - context.boundShaderProgram = shaderId; - } else { - statistics.onShaderUse(shader, false); - } - } - - protected void updateUniform(Shader shader, Uniform uniform) { - assert uniform.getName() != null; - assert shader.getId() > 0; - - bindProgram(shader); - - int loc = uniform.getLocation(); - if (loc == -1) { - return; - } - - if (loc == -2) { - // get uniform location - updateUniformLocation(shader, uniform); - if (uniform.getLocation() == -1) { - // not declared, ignore - uniform.clearUpdateNeeded(); - return; - } - loc = uniform.getLocation(); - } - - if (uniform.getVarType() == null) { - // removed logging the warning to avoid flooding the log - // (LWJGL also doesn't post a warning) - //logger.log(Level.FINEST, "Uniform value is not set yet. Shader: {0}, Uniform: {1}", - // new Object[]{shader.toString(), uniform.toString()}); - return; // value not set yet.. - } - - statistics.onUniformSet(); - - uniform.clearUpdateNeeded(); - FloatBuffer fb; - IntBuffer ib; - switch (uniform.getVarType()) { - case Float: - Float f = (Float) uniform.getValue(); - GLES20.glUniform1f(loc, f.floatValue()); - break; - case Vector2: - Vector2f v2 = (Vector2f) uniform.getValue(); - GLES20.glUniform2f(loc, v2.getX(), v2.getY()); - break; - case Vector3: - Vector3f v3 = (Vector3f) uniform.getValue(); - GLES20.glUniform3f(loc, v3.getX(), v3.getY(), v3.getZ()); - break; - case Vector4: - Object val = uniform.getValue(); - if (val instanceof ColorRGBA) { - ColorRGBA c = (ColorRGBA) val; - GLES20.glUniform4f(loc, c.r, c.g, c.b, c.a); - } else if (val instanceof Vector4f) { - Vector4f c = (Vector4f) val; - GLES20.glUniform4f(loc, c.x, c.y, c.z, c.w); - } else { - Quaternion c = (Quaternion) uniform.getValue(); - GLES20.glUniform4f(loc, c.getX(), c.getY(), c.getZ(), c.getW()); - } - break; - case Boolean: - Boolean b = (Boolean) uniform.getValue(); - GLES20.glUniform1i(loc, b.booleanValue() ? GLES20.GL_TRUE : GLES20.GL_FALSE); - break; - case Matrix3: - fb = (FloatBuffer) uniform.getValue(); - assert fb.remaining() == 9; - GLES20.glUniformMatrix3fv(loc, 1, false, fb); - break; - case Matrix4: - fb = (FloatBuffer) uniform.getValue(); - assert fb.remaining() == 16; - GLES20.glUniformMatrix4fv(loc, 1, false, fb); - break; - case IntArray: - ib = (IntBuffer) uniform.getValue(); - GLES20.glUniform1iv(loc, ib.limit(), ib); - break; - case FloatArray: - fb = (FloatBuffer) uniform.getValue(); - GLES20.glUniform1fv(loc, fb.limit(), fb); - break; - case Vector2Array: - fb = (FloatBuffer) uniform.getValue(); - GLES20.glUniform2fv(loc, fb.limit() / 2, fb); - break; - case Vector3Array: - fb = (FloatBuffer) uniform.getValue(); - GLES20.glUniform3fv(loc, fb.limit() / 3, fb); - break; - case Vector4Array: - fb = (FloatBuffer) uniform.getValue(); - GLES20.glUniform4fv(loc, fb.limit() / 4, fb); - break; - case Matrix4Array: - fb = (FloatBuffer) uniform.getValue(); - GLES20.glUniformMatrix4fv(loc, fb.limit() / 16, false, fb); - break; - case Int: - Integer i = (Integer) uniform.getValue(); - GLES20.glUniform1i(loc, i.intValue()); - break; - default: - throw new UnsupportedOperationException("Unsupported uniform type: " + uniform.getVarType()); - } - RendererUtil.checkGLError(); - } - - protected void updateShaderUniforms(Shader shader) { - ListMap uniforms = shader.getUniformMap(); - for (int i = 0; i < uniforms.size(); i++) { - Uniform uniform = uniforms.getValue(i); - if (uniform.isUpdateNeeded()) { - updateUniform(shader, uniform); - } - } - } - - protected void resetUniformLocations(Shader shader) { - ListMap uniforms = shader.getUniformMap(); - for (int i = 0; i < uniforms.size(); i++) { - Uniform uniform = uniforms.getValue(i); - uniform.reset(); // e.g check location again - } - } - - /* - * (Non-javadoc) - * Only used for fixed-function. Ignored. - */ - public void setLighting(LightList list) { - } - - public int convertShaderType(ShaderType type) { - switch (type) { - case Fragment: - return GLES20.GL_FRAGMENT_SHADER; - case Vertex: - return GLES20.GL_VERTEX_SHADER; -// case Geometry: -// return ARBGeometryShader4.GL_GEOMETRY_SHADER_ARB; - default: - throw new RuntimeException("Unrecognized shader type."); - } - } - - public void updateShaderSourceData(ShaderSource source) { - int id = source.getId(); - if (id == -1) { - // Create id - id = GLES20.glCreateShader(convertShaderType(source.getType())); - RendererUtil.checkGLError(); - - if (id <= 0) { - throw new RendererException("Invalid ID received when trying to create shader."); - } - source.setId(id); - } - - if (!source.getLanguage().equals("GLSL100")) { - throw new RendererException("This shader cannot run in OpenGL ES. " - + "Only GLSL 1.0 shaders are supported."); - } - - // upload shader source - // merge the defines and source code - byte[] definesCodeData = source.getDefines().getBytes(); - byte[] sourceCodeData = source.getSource().getBytes(); - ByteBuffer codeBuf = BufferUtils.createByteBuffer(definesCodeData.length - + sourceCodeData.length); - codeBuf.put(definesCodeData); - codeBuf.put(sourceCodeData); - codeBuf.flip(); - - if (powerVr && source.getType() == ShaderType.Vertex) { - // XXX: This is to fix a bug in old PowerVR, remove - // when no longer applicable. - GLES20.glShaderSource( - id, source.getDefines() - + source.getSource()); - } else { - String precision =""; - if (source.getType() == ShaderType.Fragment) { - precision = "precision mediump float;\n"; - } - GLES20.glShaderSource( - id, - precision - +source.getDefines() - + source.getSource()); - } -// int range[] = new int[2]; -// int precision[] = new int[1]; -// GLES20.glGetShaderPrecisionFormat(GLES20.GL_VERTEX_SHADER, GLES20.GL_HIGH_FLOAT, range, 0, precision, 0); -// System.out.println("PRECISION HIGH FLOAT VERTEX"); -// System.out.println("range "+range[0]+"," +range[1]); -// System.out.println("precision "+precision[0]); - - GLES20.glCompileShader(id); - RendererUtil.checkGLError(); - - GLES20.glGetShaderiv(id, GLES20.GL_COMPILE_STATUS, intBuf1); - RendererUtil.checkGLError(); - - boolean compiledOK = intBuf1.get(0) == GLES20.GL_TRUE; - String infoLog = null; - - if (VALIDATE_SHADER || !compiledOK) { - // even if compile succeeded, check - // log for warnings - GLES20.glGetShaderiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1); - RendererUtil.checkGLError(); - infoLog = GLES20.glGetShaderInfoLog(id); - } - - if (compiledOK) { - if (infoLog != null) { - logger.log(Level.FINE, "compile success: {0}, {1}", new Object[]{source.getName(), infoLog}); - } else { - logger.log(Level.FINE, "compile success: {0}", source.getName()); - } - source.clearUpdateNeeded(); - } else { - logger.log(Level.WARNING, "Bad compile of:\n{0}", - new Object[]{ShaderDebug.formatShaderSource(stringBuf.toString() + source.getDefines() + source.getSource())}); - if (infoLog != null) { - throw new RendererException("compile error in: " + source + "\n" + infoLog); - } else { - throw new RendererException("compile error in: " + source + "\nerror: "); - } - } - } - - public void updateShaderData(Shader shader) { - int id = shader.getId(); - boolean needRegister = false; - if (id == -1) { - // create program - id = GLES20.glCreateProgram(); - RendererUtil.checkGLError(); - - if (id <= 0) { - throw new RendererException("Invalid ID received when trying to create shader program."); - } - - shader.setId(id); - needRegister = true; - } - - for (ShaderSource source : shader.getSources()) { - if (source.isUpdateNeeded()) { - updateShaderSourceData(source); - } - - GLES20.glAttachShader(id, source.getId()); - RendererUtil.checkGLError(); - } - - // link shaders to program - GLES20.glLinkProgram(id); - RendererUtil.checkGLError(); - - GLES20.glGetProgramiv(id, GLES20.GL_LINK_STATUS, intBuf1); - RendererUtil.checkGLError(); - - boolean linkOK = intBuf1.get(0) == GLES20.GL_TRUE; - String infoLog = null; - - if (VALIDATE_SHADER || !linkOK) { - GLES20.glGetProgramiv(id, GLES20.GL_INFO_LOG_LENGTH, intBuf1); - RendererUtil.checkGLError(); - - int length = intBuf1.get(0); - if (length > 3) { - // get infos - infoLog = GLES20.glGetProgramInfoLog(id); - RendererUtil.checkGLError(); - } - } - - if (linkOK) { - if (infoLog != null) { - logger.log(Level.FINE, "shader link success. \n{0}", infoLog); - } else { - logger.fine("shader link success"); - } - shader.clearUpdateNeeded(); - if (needRegister) { - // Register shader for clean up if it was created in this method. - objManager.registerObject(shader); - statistics.onNewShader(); - } else { - // OpenGL spec: uniform locations may change after re-link - resetUniformLocations(shader); - } - } else { - if (infoLog != null) { - throw new RendererException("Shader link failure, shader: " + shader + "\n" + infoLog); - } else { - throw new RendererException("Shader link failure, shader: " + shader + "\ninfo: "); - } - } - } - - public void setShader(Shader shader) { - if (shader == null) { - throw new IllegalArgumentException("Shader cannot be null"); - } else { - if (shader.isUpdateNeeded()) { - updateShaderData(shader); - } - - // NOTE: might want to check if any of the - // sources need an update? - - assert shader.getId() > 0; - - updateShaderUniforms(shader); - bindProgram(shader); - } - } - - public void deleteShaderSource(ShaderSource source) { - if (source.getId() < 0) { - logger.warning("Shader source is not uploaded to GPU, cannot delete."); - return; - } - - source.clearUpdateNeeded(); - - GLES20.glDeleteShader(source.getId()); - RendererUtil.checkGLError(); - - source.resetObject(); - } - - public void deleteShader(Shader shader) { - if (shader.getId() == -1) { - logger.warning("Shader is not uploaded to GPU, cannot delete."); - return; - } - - for (ShaderSource source : shader.getSources()) { - if (source.getId() != -1) { - GLES20.glDetachShader(shader.getId(), source.getId()); - RendererUtil.checkGLError(); - - deleteShaderSource(source); - } - } - - GLES20.glDeleteProgram(shader.getId()); - RendererUtil.checkGLError(); - - statistics.onDeleteShader(); - shader.resetObject(); - } - - private int convertTestFunction(RenderState.TestFunction testFunc) { - switch (testFunc) { - case Never: - return GLES20.GL_NEVER; - case Less: - return GLES20.GL_LESS; - case LessOrEqual: - return GLES20.GL_LEQUAL; - case Greater: - return GLES20.GL_GREATER; - case GreaterOrEqual: - return GLES20.GL_GEQUAL; - case Equal: - return GLES20.GL_EQUAL; - case NotEqual: - return GLES20.GL_NOTEQUAL; - case Always: - return GLES20.GL_ALWAYS; - default: - throw new UnsupportedOperationException("Unrecognized test function: " + testFunc); - } - } - - /*********************************************************************\ - |* Framebuffers *| - \*********************************************************************/ - - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { - throw new RendererException("Copy framebuffer not implemented yet."); - -// if (GLContext.getCapabilities().GL_EXT_framebuffer_blit) { -// int srcX0 = 0; -// int srcY0 = 0; -// int srcX1 = 0; -// int srcY1 = 0; -// -// int dstX0 = 0; -// int dstY0 = 0; -// int dstX1 = 0; -// int dstY1 = 0; -// -// int prevFBO = context.boundFBO; -// -// if (mainFbOverride != null) { -// if (src == null) { -// src = mainFbOverride; -// } -// if (dst == null) { -// dst = mainFbOverride; -// } -// } -// -// if (src != null && src.isUpdateNeeded()) { -// updateFrameBuffer(src); -// } -// -// if (dst != null && dst.isUpdateNeeded()) { -// updateFrameBuffer(dst); -// } -// -// if (src == null) { -// GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); -// srcX0 = vpX; -// srcY0 = vpY; -// srcX1 = vpX + vpW; -// srcY1 = vpY + vpH; -// } else { -// GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, src.getId()); -// srcX1 = src.getWidth(); -// srcY1 = src.getHeight(); -// } -// if (dst == null) { -// GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); -// dstX0 = vpX; -// dstY0 = vpY; -// dstX1 = vpX + vpW; -// dstY1 = vpY + vpH; -// } else { -// GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, dst.getId()); -// dstX1 = dst.getWidth(); -// dstY1 = dst.getHeight(); -// } -// -// -// int mask = GL_COLOR_BUFFER_BIT; -// if (copyDepth) { -// mask |= GL_DEPTH_BUFFER_BIT; -// } -// GLES20.glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, -// dstX0, dstY0, dstX1, dstY1, mask, -// GL_NEAREST); -// -// -// GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, prevFBO); -// try { -// checkFrameBufferError(); -// } catch (IllegalStateException ex) { -// logger.log(Level.SEVERE, "Source FBO:\n{0}", src); -// logger.log(Level.SEVERE, "Dest FBO:\n{0}", dst); -// throw ex; -// } -// } else { -// throw new RendererException("EXT_framebuffer_blit required."); -// // TODO: support non-blit copies? -// } - } - - private void checkFrameBufferStatus(FrameBuffer fb) { - try { - checkFrameBufferError(); - } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "=== jMonkeyEngine FBO State ===\n{0}", fb); - printRealFrameBufferInfo(fb); - throw ex; - } - } - - private void checkFrameBufferError() { - int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); - switch (status) { - case GLES20.GL_FRAMEBUFFER_COMPLETE: - break; - case GLES20.GL_FRAMEBUFFER_UNSUPPORTED: - //Choose different formats - throw new IllegalStateException("Framebuffer object format is " - + "unsupported by the video hardware."); - case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - throw new IllegalStateException("Framebuffer has erronous attachment."); - case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - throw new IllegalStateException("Framebuffer doesn't have any renderbuffers attached."); - case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - throw new IllegalStateException("Framebuffer attachments must have same dimensions."); -// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: -// throw new IllegalStateException("Framebuffer attachments must have same formats."); -// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: -// throw new IllegalStateException("Incomplete draw buffer."); -// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: -// throw new IllegalStateException("Incomplete read buffer."); -// case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: -// throw new IllegalStateException("Incomplete multisample buffer."); - default: - //Programming error; will fail on all hardware - throw new IllegalStateException("Some video driver error " - + "or programming error occured. " - + "Framebuffer object status is invalid: " + status); - } - } - - private void printRealRenderBufferInfo(FrameBuffer fb, RenderBuffer rb, String name) { - System.out.println("== Renderbuffer " + name + " =="); - System.out.println("RB ID: " + rb.getId()); - System.out.println("Is proper? " + GLES20.glIsRenderbuffer(rb.getId())); - - int attachment = convertAttachmentSlot(rb.getSlot()); - - intBuf16.clear(); - GLES20.glGetFramebufferAttachmentParameteriv(GLES20.GL_FRAMEBUFFER, - attachment, GLES20.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, intBuf16); - int type = intBuf16.get(0); - - intBuf16.clear(); - GLES20.glGetFramebufferAttachmentParameteriv(GLES20.GL_FRAMEBUFFER, - attachment, GLES20.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, intBuf16); - int rbName = intBuf16.get(0); - - switch (type) { - case GLES20.GL_NONE: - System.out.println("Type: None"); - break; - case GLES20.GL_TEXTURE: - System.out.println("Type: Texture"); - break; - case GLES20.GL_RENDERBUFFER: - System.out.println("Type: Buffer"); - System.out.println("RB ID: " + rbName); - break; - } - - - - } - - private void printRealFrameBufferInfo(FrameBuffer fb) { -// boolean doubleBuffer = GLES20.glGetBooleanv(GLES20.GL_DOUBLEBUFFER); - boolean doubleBuffer = false; // FIXME -// String drawBuf = getTargetBufferName(glGetInteger(GL_DRAW_BUFFER)); -// String readBuf = getTargetBufferName(glGetInteger(GL_READ_BUFFER)); - - int fbId = fb.getId(); - intBuf16.clear(); -// int curDrawBinding = GLES20.glGetIntegerv(GLES20.GL_DRAW_FRAMEBUFFER_BINDING); -// int curReadBinding = glGetInteger(ARBFramebufferObject.GL_READ_FRAMEBUFFER_BINDING); - - System.out.println("=== OpenGL FBO State ==="); - System.out.println("Context doublebuffered? " + doubleBuffer); - System.out.println("FBO ID: " + fbId); - System.out.println("Is proper? " + GLES20.glIsFramebuffer(fbId)); -// System.out.println("Is bound to draw? " + (fbId == curDrawBinding)); -// System.out.println("Is bound to read? " + (fbId == curReadBinding)); -// System.out.println("Draw buffer: " + drawBuf); -// System.out.println("Read buffer: " + readBuf); - - if (context.boundFBO != fbId) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbId); - context.boundFBO = fbId; - } - - if (fb.getDepthBuffer() != null) { - printRealRenderBufferInfo(fb, fb.getDepthBuffer(), "Depth"); - } - for (int i = 0; i < fb.getNumColorBuffers(); i++) { - printRealRenderBufferInfo(fb, fb.getColorBuffer(i), "Color" + i); - } - } - - private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb) { - int id = rb.getId(); - if (id == -1) { - GLES20.glGenRenderbuffers(1, intBuf1); - RendererUtil.checkGLError(); - - id = intBuf1.get(0); - rb.setId(id); - } - - if (context.boundRB != id) { - GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, id); - RendererUtil.checkGLError(); - - context.boundRB = id; - } - - if (fb.getWidth() > maxRBSize || fb.getHeight() > maxRBSize) { - throw new RendererException("Resolution " + fb.getWidth() - + ":" + fb.getHeight() + " is not supported."); - } - - AndroidGLImageFormat imageFormat = TextureUtil.getImageFormat(rb.getFormat(), true); - if (imageFormat.renderBufferStorageFormat == 0) { - throw new RendererException("The format '" + rb.getFormat() + "' cannot be used for renderbuffers."); - } - -// if (fb.getSamples() > 1 && GLContext.getCapabilities().GL_EXT_framebuffer_multisample) { - if (fb.getSamples() > 1) { -// // FIXME - throw new RendererException("Multisample FrameBuffer is not supported yet."); -// int samples = fb.getSamples(); -// if (maxFBOSamples < samples) { -// samples = maxFBOSamples; -// } -// glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, -// samples, -// glFmt.internalFormat, -// fb.getWidth(), -// fb.getHeight()); - } else { - GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, - imageFormat.renderBufferStorageFormat, - fb.getWidth(), - fb.getHeight()); - - RendererUtil.checkGLError(); - } - } - - private int convertAttachmentSlot(int attachmentSlot) { - // can also add support for stencil here - if (attachmentSlot == FrameBuffer.SLOT_DEPTH) { - return GLES20.GL_DEPTH_ATTACHMENT; -// if (attachmentSlot == FrameBuffer.SLOT_DEPTH_STENCIL) { -// return GLES30.GL_DEPTH_STENCIL_ATTACHMENT; - } else if (attachmentSlot == 0) { - return GLES20.GL_COLOR_ATTACHMENT0; - } else { - throw new UnsupportedOperationException("Android does not support multiple color attachments to an FBO"); - } - } - - public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { - Texture tex = rb.getTexture(); - Image image = tex.getImage(); - if (image.isUpdateNeeded()) { - updateTexImageData(image, tex.getType()); - - // NOTE: For depth textures, sets nearest/no-mips mode - // Required to fix "framebuffer unsupported" - // for old NVIDIA drivers! - setupTextureParams(tex); - } - - GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, - convertAttachmentSlot(rb.getSlot()), - convertTextureType(tex.getType()), - image.getId(), - 0); - - RendererUtil.checkGLError(); - } - - public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) { - boolean needAttach; - if (rb.getTexture() == null) { - // if it hasn't been created yet, then attach is required. - needAttach = rb.getId() == -1; - updateRenderBuffer(fb, rb); - } else { - needAttach = false; - updateRenderTexture(fb, rb); - } - if (needAttach) { - GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, - convertAttachmentSlot(rb.getSlot()), - GLES20.GL_RENDERBUFFER, - rb.getId()); - - RendererUtil.checkGLError(); - } - } - - public void updateFrameBuffer(FrameBuffer fb) { - int id = fb.getId(); - if (id == -1) { - intBuf1.clear(); - // create FBO - GLES20.glGenFramebuffers(1, intBuf1); - RendererUtil.checkGLError(); - - id = intBuf1.get(0); - fb.setId(id); - objManager.registerObject(fb); - - statistics.onNewFrameBuffer(); - } - - if (context.boundFBO != id) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, id); - RendererUtil.checkGLError(); - - // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0 - context.boundDrawBuf = 0; - context.boundFBO = id; - } - - FrameBuffer.RenderBuffer depthBuf = fb.getDepthBuffer(); - if (depthBuf != null) { - updateFrameBufferAttachment(fb, depthBuf); - } - - for (int i = 0; i < fb.getNumColorBuffers(); i++) { - FrameBuffer.RenderBuffer colorBuf = fb.getColorBuffer(i); - updateFrameBufferAttachment(fb, colorBuf); - } - - fb.clearUpdateNeeded(); - } - - public void setMainFrameBufferOverride(FrameBuffer fb){ - mainFbOverride = fb; - } - - public void setFrameBuffer(FrameBuffer fb) { - if (fb == null && mainFbOverride != null) { - fb = mainFbOverride; - } - - if (lastFb == fb) { - if (fb == null || !fb.isUpdateNeeded()) { - return; - } - } - - // generate mipmaps for last FB if needed - if (lastFb != null) { - for (int i = 0; i < lastFb.getNumColorBuffers(); i++) { - RenderBuffer rb = lastFb.getColorBuffer(i); - Texture tex = rb.getTexture(); - if (tex != null - && tex.getMinFilter().usesMipMapLevels()) { - setTexture(0, rb.getTexture()); - -// int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace()); - int textureType = convertTextureType(tex.getType()); - GLES20.glGenerateMipmap(textureType); - RendererUtil.checkGLError(); - } - } - } - - if (fb == null) { - // unbind any fbos - if (context.boundFBO != 0) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - RendererUtil.checkGLError(); - - statistics.onFrameBufferUse(null, true); - - context.boundFBO = 0; - } - - /* - // select back buffer - if (context.boundDrawBuf != -1) { - glDrawBuffer(initialDrawBuf); - context.boundDrawBuf = -1; - } - if (context.boundReadBuf != -1) { - glReadBuffer(initialReadBuf); - context.boundReadBuf = -1; - } - */ - - lastFb = null; - } else { - if (fb.getNumColorBuffers() == 0 && fb.getDepthBuffer() == null) { - throw new IllegalArgumentException("The framebuffer: " + fb - + "\nDoesn't have any color/depth buffers"); - } - - if (fb.isUpdateNeeded()) { - updateFrameBuffer(fb); - } - - if (context.boundFBO != fb.getId()) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb.getId()); - RendererUtil.checkGLError(); - - statistics.onFrameBufferUse(fb, true); - - // update viewport to reflect framebuffer's resolution - setViewPort(0, 0, fb.getWidth(), fb.getHeight()); - - context.boundFBO = fb.getId(); - } else { - statistics.onFrameBufferUse(fb, false); - } - if (fb.getNumColorBuffers() == 0) { -// // make sure to select NONE as draw buf -// // no color buffer attached. select NONE - if (context.boundDrawBuf != -2) { -// glDrawBuffer(GL_NONE); - context.boundDrawBuf = -2; - } - if (context.boundReadBuf != -2) { -// glReadBuffer(GL_NONE); - context.boundReadBuf = -2; - } - } else { - if (fb.getNumColorBuffers() > maxFBOAttachs) { - throw new RendererException("Framebuffer has more color " - + "attachments than are supported" - + " by the video hardware!"); - } - if (fb.isMultiTarget()) { - if (fb.getNumColorBuffers() > maxMRTFBOAttachs) { - throw new RendererException("Framebuffer has more" - + " multi targets than are supported" - + " by the video hardware!"); - } - - if (context.boundDrawBuf != 100 + fb.getNumColorBuffers()) { - intBuf16.clear(); - for (int i = 0; i < fb.getNumColorBuffers(); i++) { - intBuf16.put(GLES20.GL_COLOR_ATTACHMENT0 + i); - } - - intBuf16.flip(); -// glDrawBuffers(intBuf16); - context.boundDrawBuf = 100 + fb.getNumColorBuffers(); - } - } else { - RenderBuffer rb = fb.getColorBuffer(fb.getTargetIndex()); - // select this draw buffer - if (context.boundDrawBuf != rb.getSlot()) { - GLES20.glActiveTexture(convertAttachmentSlot(rb.getSlot())); - RendererUtil.checkGLError(); - - context.boundDrawBuf = rb.getSlot(); - } - } - } - - assert fb.getId() >= 0; - assert context.boundFBO == fb.getId(); - - lastFb = fb; - - checkFrameBufferStatus(fb); - } - } - - /** - * Reads the Color Buffer from OpenGL and stores into the ByteBuffer. - * Make sure to call setViewPort with the appropriate viewport size before - * calling readFrameBuffer. - * @param fb FrameBuffer - * @param byteBuf ByteBuffer to store the Color Buffer from OpenGL - */ - public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { - if (fb != null) { - RenderBuffer rb = fb.getColorBuffer(); - if (rb == null) { - throw new IllegalArgumentException("Specified framebuffer" - + " does not have a colorbuffer"); - } - - setFrameBuffer(fb); - } else { - setFrameBuffer(null); - } - - GLES20.glReadPixels(vpX, vpY, vpW, vpH, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuf); - RendererUtil.checkGLError(); - } - - private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) { - intBuf1.put(0, rb.getId()); - GLES20.glDeleteRenderbuffers(1, intBuf1); - RendererUtil.checkGLError(); - } - - public void deleteFrameBuffer(FrameBuffer fb) { - if (fb.getId() != -1) { - if (context.boundFBO == fb.getId()) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - RendererUtil.checkGLError(); - - context.boundFBO = 0; - } - - if (fb.getDepthBuffer() != null) { - deleteRenderBuffer(fb, fb.getDepthBuffer()); - } - if (fb.getColorBuffer() != null) { - deleteRenderBuffer(fb, fb.getColorBuffer()); - } - - intBuf1.put(0, fb.getId()); - GLES20.glDeleteFramebuffers(1, intBuf1); - RendererUtil.checkGLError(); - - fb.resetObject(); - - statistics.onDeleteFrameBuffer(); - } - } - - /*********************************************************************\ - |* Textures *| - \*********************************************************************/ - private int convertTextureType(Texture.Type type) { - switch (type) { - case TwoDimensional: - return GLES20.GL_TEXTURE_2D; - // case TwoDimensionalArray: - // return EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT; -// case ThreeDimensional: - // return GLES20.GL_TEXTURE_3D; - case CubeMap: - return GLES20.GL_TEXTURE_CUBE_MAP; - default: - throw new UnsupportedOperationException("Unknown texture type: " + type); - } - } - - private int convertMagFilter(Texture.MagFilter filter) { - switch (filter) { - case Bilinear: - return GLES20.GL_LINEAR; - case Nearest: - return GLES20.GL_NEAREST; - default: - throw new UnsupportedOperationException("Unknown mag filter: " + filter); - } - } - - private int convertMinFilter(Texture.MinFilter filter) { - switch (filter) { - case Trilinear: - return GLES20.GL_LINEAR_MIPMAP_LINEAR; - case BilinearNearestMipMap: - return GLES20.GL_LINEAR_MIPMAP_NEAREST; - case NearestLinearMipMap: - return GLES20.GL_NEAREST_MIPMAP_LINEAR; - case NearestNearestMipMap: - return GLES20.GL_NEAREST_MIPMAP_NEAREST; - case BilinearNoMipMaps: - return GLES20.GL_LINEAR; - case NearestNoMipMaps: - return GLES20.GL_NEAREST; - default: - throw new UnsupportedOperationException("Unknown min filter: " + filter); - } - } - - private int convertWrapMode(Texture.WrapMode mode) { - switch (mode) { - case BorderClamp: - case Clamp: - case EdgeClamp: - return GLES20.GL_CLAMP_TO_EDGE; - case Repeat: - return GLES20.GL_REPEAT; - case MirroredRepeat: - return GLES20.GL_MIRRORED_REPEAT; - default: - throw new UnsupportedOperationException("Unknown wrap mode: " + mode); - } - } - - /** - * setupTextureParams sets the OpenGL context texture parameters - * @param tex the Texture to set the texture parameters from - */ - private void setupTextureParams(Texture tex) { - int target = convertTextureType(tex.getType()); - - // filter things - int minFilter = convertMinFilter(tex.getMinFilter()); - int magFilter = convertMagFilter(tex.getMagFilter()); - - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, minFilter); - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, magFilter); - RendererUtil.checkGLError(); - - /* - if (tex.getAnisotropicFilter() > 1){ - - if (GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){ - glTexParameterf(target, - EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, - tex.getAnisotropicFilter()); - } - - } - */ - // repeat modes - - switch (tex.getType()) { - case ThreeDimensional: - case CubeMap: // cubemaps use 3D coords - // GL_TEXTURE_WRAP_R is not available in api 8 - //GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R))); - case TwoDimensional: - case TwoDimensionalArray: - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T))); - - // fall down here is intentional.. -// case OneDimensional: - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S))); - - RendererUtil.checkGLError(); - break; - default: - throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); - } - - // R to Texture compare mode -/* - if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off){ - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_MODE, GLES20.GL_COMPARE_R_TO_TEXTURE); - GLES20.glTexParameteri(target, GLES20.GL_DEPTH_TEXTURE_MODE, GLES20.GL_INTENSITY); - if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual){ - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_GEQUAL); - }else{ - GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_COMPARE_FUNC, GLES20.GL_LEQUAL); - } - } - */ - } - - /** - * activates and binds the texture - * @param img - * @param type - */ - public void updateTexImageData(Image img, Texture.Type type) { - int texId = img.getId(); - if (texId == -1) { - // create texture - GLES20.glGenTextures(1, intBuf1); - RendererUtil.checkGLError(); - - texId = intBuf1.get(0); - img.setId(texId); - objManager.registerObject(img); - - statistics.onNewTexture(); - } - - // bind texture - int target = convertTextureType(type); - if (context.boundTextures[0] != img) { - if (context.boundTextureUnit != 0) { - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - RendererUtil.checkGLError(); - - context.boundTextureUnit = 0; - } - - GLES20.glBindTexture(target, texId); - RendererUtil.checkGLError(); - - context.boundTextures[0] = img; - } - - boolean needMips = false; - if (img.isGeneratedMipmapsRequired()) { - needMips = true; - img.setMipmapsGenerated(true); - } - - if (target == GLES20.GL_TEXTURE_CUBE_MAP) { - // Check max texture size before upload - if (img.getWidth() > maxCubeTexSize || img.getHeight() > maxCubeTexSize) { - throw new RendererException("Cannot upload cubemap " + img + ". The maximum supported cubemap resolution is " + maxCubeTexSize); - } - } else { - if (img.getWidth() > maxTexSize || img.getHeight() > maxTexSize) { - throw new RendererException("Cannot upload texture " + img + ". The maximum supported texture resolution is " + maxTexSize); - } - } - - if (target == GLES20.GL_TEXTURE_CUBE_MAP) { - // Upload a cube map / sky box - @SuppressWarnings("unchecked") - List bmps = (List) img.getEfficentData(); - if (bmps != null) { - // Native android bitmap - if (bmps.size() != 6) { - throw new UnsupportedOperationException("Invalid texture: " + img - + "Cubemap textures must contain 6 data units."); - } - for (int i = 0; i < 6; i++) { - TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i).getBitmap(), needMips); - bmps.get(i).notifyBitmapUploaded(); - } - } else { - // Standard jme3 image data - List data = img.getData(); - if (data.size() != 6) { - throw new UnsupportedOperationException("Invalid texture: " + img - + "Cubemap textures must contain 6 data units."); - } - for (int i = 0; i < 6; i++) { - TextureUtil.uploadTextureAny(img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, needMips); - } - } - } else { - TextureUtil.uploadTextureAny(img, target, 0, needMips); - if (img.getEfficentData() instanceof AndroidImageInfo) { - AndroidImageInfo info = (AndroidImageInfo) img.getEfficentData(); - info.notifyBitmapUploaded(); - } - } - - img.clearUpdateNeeded(); - } - - public void setTexture(int unit, Texture tex) { - Image image = tex.getImage(); - if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated()) ) { - updateTexImageData(image, tex.getType()); - } - - int texId = image.getId(); - assert texId != -1; - - if (texId == -1) { - logger.warning("error: texture image has -1 id"); - } - - Image[] textures = context.boundTextures; - - int type = convertTextureType(tex.getType()); -// if (!context.textureIndexList.moveToNew(unit)) { -// if (context.boundTextureUnit != unit){ -// glActiveTexture(GL_TEXTURE0 + unit); -// context.boundTextureUnit = unit; -// } -// glEnable(type); -// } - - if (textures[unit] != image) { - if (context.boundTextureUnit != unit) { - GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + unit); - context.boundTextureUnit = unit; - } - - GLES20.glBindTexture(type, texId); - RendererUtil.checkGLError(); - - textures[unit] = image; - - statistics.onTextureUse(tex.getImage(), true); - } else { - statistics.onTextureUse(tex.getImage(), false); - } - - setupTextureParams(tex); - } - - public void modifyTexture(Texture tex, Image pixels, int x, int y) { - setTexture(0, tex); - TextureUtil.uploadSubTexture(pixels, convertTextureType(tex.getType()), 0, x, y); - } - - public void deleteImage(Image image) { - int texId = image.getId(); - if (texId != -1) { - intBuf1.put(0, texId); - intBuf1.position(0).limit(1); - - GLES20.glDeleteTextures(1, intBuf1); - RendererUtil.checkGLError(); - - image.resetObject(); - - statistics.onDeleteTexture(); - } - } - - /*********************************************************************\ - |* Vertex Buffers and Attributes *| - \*********************************************************************/ - private int convertUsage(Usage usage) { - switch (usage) { - case Static: - return GLES20.GL_STATIC_DRAW; - case Dynamic: - return GLES20.GL_DYNAMIC_DRAW; - case Stream: - return GLES20.GL_STREAM_DRAW; - default: - throw new RuntimeException("Unknown usage type."); - } - } - - private int convertVertexBufferFormat(Format format) { - switch (format) { - case Byte: - return GLES20.GL_BYTE; - case UnsignedByte: - return GLES20.GL_UNSIGNED_BYTE; - case Short: - return GLES20.GL_SHORT; - case UnsignedShort: - return GLES20.GL_UNSIGNED_SHORT; - case Int: - return GLES20.GL_INT; - case UnsignedInt: - return GLES20.GL_UNSIGNED_INT; - /* - case Half: - return NVHalfFloat.GL_HALF_FLOAT_NV; - // return ARBHalfFloatVertex.GL_HALF_FLOAT; - */ - case Float: - return GLES20.GL_FLOAT; -// case Double: -// return GLES20.GL_DOUBLE; - default: - throw new RuntimeException("Unknown buffer format."); - - } - } - - public void updateBufferData(VertexBuffer vb) { - int bufId = vb.getId(); - boolean created = false; - if (bufId == -1) { - // create buffer - GLES20.glGenBuffers(1, intBuf1); - RendererUtil.checkGLError(); - - bufId = intBuf1.get(0); - vb.setId(bufId); - objManager.registerObject(vb); - - created = true; - } - - // bind buffer - int target; - if (vb.getBufferType() == VertexBuffer.Type.Index) { - target = GLES20.GL_ELEMENT_ARRAY_BUFFER; - if (context.boundElementArrayVBO != bufId) { - GLES20.glBindBuffer(target, bufId); - RendererUtil.checkGLError(); - - context.boundElementArrayVBO = bufId; - } - } else { - target = GLES20.GL_ARRAY_BUFFER; - if (context.boundArrayVBO != bufId) { - GLES20.glBindBuffer(target, bufId); - RendererUtil.checkGLError(); - - context.boundArrayVBO = bufId; - } - } - - int usage = convertUsage(vb.getUsage()); - vb.getData().rewind(); - - // if (created || vb.hasDataSizeChanged()) { - // upload data based on format - int size = vb.getData().limit() * vb.getFormat().getComponentSize(); - - switch (vb.getFormat()) { - case Byte: - case UnsignedByte: - GLES20.glBufferData(target, size, (ByteBuffer) vb.getData(), usage); - RendererUtil.checkGLError(); - break; - case Short: - case UnsignedShort: - GLES20.glBufferData(target, size, (ShortBuffer) vb.getData(), usage); - RendererUtil.checkGLError(); - break; - case Int: - case UnsignedInt: - GLES20.glBufferData(target, size, (IntBuffer) vb.getData(), usage); - RendererUtil.checkGLError(); - break; - case Float: - GLES20.glBufferData(target, size, (FloatBuffer) vb.getData(), usage); - RendererUtil.checkGLError(); - break; - default: - throw new RuntimeException("Unknown buffer format."); - } -// } else { -// int size = vb.getData().limit() * vb.getFormat().getComponentSize(); -// -// switch (vb.getFormat()) { -// case Byte: -// case UnsignedByte: -// GLES20.glBufferSubData(target, 0, size, (ByteBuffer) vb.getData()); -// RendererUtil.checkGLError(); -// break; -// case Short: -// case UnsignedShort: -// GLES20.glBufferSubData(target, 0, size, (ShortBuffer) vb.getData()); -// RendererUtil.checkGLError(); -// break; -// case Int: -// case UnsignedInt: -// GLES20.glBufferSubData(target, 0, size, (IntBuffer) vb.getData()); -// RendererUtil.checkGLError(); -// break; -// case Float: -// GLES20.glBufferSubData(target, 0, size, (FloatBuffer) vb.getData()); -// RendererUtil.checkGLError(); -// break; -// default: -// throw new RuntimeException("Unknown buffer format."); -// } -// } - vb.clearUpdateNeeded(); - } - - public void deleteBuffer(VertexBuffer vb) { - int bufId = vb.getId(); - if (bufId != -1) { - // delete buffer - intBuf1.put(0, bufId); - intBuf1.position(0).limit(1); - - GLES20.glDeleteBuffers(1, intBuf1); - RendererUtil.checkGLError(); - - vb.resetObject(); - } - } - - public void clearVertexAttribs() { - IDList attribList = context.attribIndexList; - for (int i = 0; i < attribList.oldLen; i++) { - int idx = attribList.oldList[i]; - - GLES20.glDisableVertexAttribArray(idx); - RendererUtil.checkGLError(); - - context.boundAttribs[idx] = null; - } - context.attribIndexList.copyNewToOld(); - } - - public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) { - if (vb.getBufferType() == VertexBuffer.Type.Index) { - throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); - } - - if (vb.isUpdateNeeded() && idb == null) { - updateBufferData(vb); - } - - int programId = context.boundShaderProgram; - if (programId > 0) { - Attribute attrib = boundShader.getAttribute(vb.getBufferType()); - int loc = attrib.getLocation(); - if (loc == -1) { - return; // not defined - } - - if (loc == -2) { -// stringBuf.setLength(0); -// stringBuf.append("in").append(vb.getBufferType().name()).append('\0'); -// updateNameBuffer(); - - String attributeName = "in" + vb.getBufferType().name(); - loc = GLES20.glGetAttribLocation(programId, attributeName); - RendererUtil.checkGLError(); - - // not really the name of it in the shader (inPosition\0) but - // the internal name of the enum (Position). - if (loc < 0) { - attrib.setLocation(-1); - return; // not available in shader. - } else { - attrib.setLocation(loc); - } - } - - VertexBuffer[] attribs = context.boundAttribs; - if (!context.attribIndexList.moveToNew(loc)) { - GLES20.glEnableVertexAttribArray(loc); - RendererUtil.checkGLError(); - //System.out.println("Enabled ATTRIB IDX: "+loc); - } - if (attribs[loc] != vb) { - // NOTE: Use id from interleaved buffer if specified - int bufId = idb != null ? idb.getId() : vb.getId(); - assert bufId != -1; - - if (bufId == -1) { - logger.warning("invalid buffer id"); - } - - if (context.boundArrayVBO != bufId) { - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufId); - RendererUtil.checkGLError(); - - context.boundArrayVBO = bufId; - } - - vb.getData().rewind(); - - GLES20.glVertexAttribPointer(loc, - vb.getNumComponents(), - convertVertexBufferFormat(vb.getFormat()), - vb.isNormalized(), - vb.getStride(), - 0); - - RendererUtil.checkGLError(); - - attribs[loc] = vb; - } - } else { - throw new IllegalStateException("Cannot render mesh without shader bound"); - } - } - - public void setVertexAttrib(VertexBuffer vb) { - setVertexAttrib(vb, null); - } - - public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) { - /* if (count > 1){ - ARBDrawInstanced.glDrawArraysInstancedARB(convertElementMode(mode), 0, - vertCount, count); - }else{*/ - GLES20.glDrawArrays(convertElementMode(mode), 0, vertCount); - RendererUtil.checkGLError(); - /* - }*/ - } - - public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { - if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { - throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); - } - - if (indexBuf.isUpdateNeeded()) { - updateBufferData(indexBuf); - } - - int bufId = indexBuf.getId(); - assert bufId != -1; - - if (bufId == -1) { - throw new RendererException("Invalid buffer ID"); - } - - if (context.boundElementArrayVBO != bufId) { - GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, bufId); - RendererUtil.checkGLError(); - - context.boundElementArrayVBO = bufId; - } - - int vertCount = mesh.getVertexCount(); - boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); - - Buffer indexData = indexBuf.getData(); - - if (indexBuf.getFormat() == Format.UnsignedInt) { - throw new RendererException("OpenGL ES does not support 32-bit index buffers." + - "Split your models to avoid going over 65536 vertices."); - } - - if (mesh.getMode() == Mode.Hybrid) { - int[] modeStart = mesh.getModeStart(); - int[] elementLengths = mesh.getElementLengths(); - - int elMode = convertElementMode(Mode.Triangles); - int fmt = convertVertexBufferFormat(indexBuf.getFormat()); - int elSize = indexBuf.getFormat().getComponentSize(); - int listStart = modeStart[0]; - int stripStart = modeStart[1]; - int fanStart = modeStart[2]; - int curOffset = 0; - for (int i = 0; i < elementLengths.length; i++) { - if (i == stripStart) { - elMode = convertElementMode(Mode.TriangleStrip); - } else if (i == fanStart) { - elMode = convertElementMode(Mode.TriangleStrip); - } - int elementLength = elementLengths[i]; - - if (useInstancing) { - //ARBDrawInstanced. - throw new IllegalArgumentException("instancing is not supported."); - /* - GLES20.glDrawElementsInstancedARB(elMode, - elementLength, - fmt, - curOffset, - count); - */ - } else { - indexBuf.getData().position(curOffset); - GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); - RendererUtil.checkGLError(); - /* - glDrawRangeElements(elMode, - 0, - vertCount, - elementLength, - fmt, - curOffset); - */ - } - - curOffset += elementLength * elSize; - } - } else { - if (useInstancing) { - throw new IllegalArgumentException("instancing is not supported."); - //ARBDrawInstanced. -/* - GLES20.glDrawElementsInstancedARB(convertElementMode(mesh.getMode()), - indexBuf.getData().limit(), - convertVertexBufferFormat(indexBuf.getFormat()), - 0, - count); - */ - } else { - indexData.rewind(); - GLES20.glDrawElements( - convertElementMode(mesh.getMode()), - indexBuf.getData().limit(), - convertVertexBufferFormat(indexBuf.getFormat()), - 0); - RendererUtil.checkGLError(); - } - } - } - - /*********************************************************************\ - |* Render Calls *| - \*********************************************************************/ - public int convertElementMode(Mesh.Mode mode) { - switch (mode) { - case Points: - return GLES20.GL_POINTS; - case Lines: - return GLES20.GL_LINES; - case LineLoop: - return GLES20.GL_LINE_LOOP; - case LineStrip: - return GLES20.GL_LINE_STRIP; - case Triangles: - return GLES20.GL_TRIANGLES; - case TriangleFan: - return GLES20.GL_TRIANGLE_FAN; - case TriangleStrip: - return GLES20.GL_TRIANGLE_STRIP; - default: - throw new UnsupportedOperationException("Unrecognized mesh mode: " + mode); - } - } - - public void updateVertexArray(Mesh mesh) { - logger.log(Level.FINE, "updateVertexArray({0})", mesh); - int id = mesh.getId(); - /* - if (id == -1){ - IntBuffer temp = intBuf1; - // ARBVertexArrayObject.glGenVertexArrays(temp); - GLES20.glGenVertexArrays(temp); - id = temp.get(0); - mesh.setId(id); - } - - if (context.boundVertexArray != id){ - // ARBVertexArrayObject.glBindVertexArray(id); - GLES20.glBindVertexArray(id); - context.boundVertexArray = id; - } - */ - VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); - if (interleavedData != null && interleavedData.isUpdateNeeded()) { - updateBufferData(interleavedData); - } - - - for (VertexBuffer vb : mesh.getBufferList().getArray()){ - - if (vb.getBufferType() == Type.InterleavedData - || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers - || vb.getBufferType() == Type.Index) { - continue; - } - - if (vb.getStride() == 0) { - // not interleaved - setVertexAttrib(vb); - } else { - // interleaved - setVertexAttrib(vb, interleavedData); - } - } - } - - /** - * renderMeshVertexArray renders a mesh using vertex arrays - */ - private void renderMeshVertexArray(Mesh mesh, int lod, int count) { - for (VertexBuffer vb : mesh.getBufferList().getArray()) { - if (vb.getBufferType() == Type.InterleavedData - || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers - || vb.getBufferType() == Type.Index) { - continue; - } - - if (vb.getStride() == 0) { - // not interleaved - setVertexAttrib_Array(vb); - } else { - // interleaved - VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); - setVertexAttrib_Array(vb, interleavedData); - } - } - - VertexBuffer indices; - if (mesh.getNumLodLevels() > 0) { - indices = mesh.getLodLevel(lod); - } else { - indices = mesh.getBuffer(Type.Index);//buffers.get(Type.Index.ordinal()); - } - if (indices != null) { - drawTriangleList_Array(indices, mesh, count); - } else { - GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); - RendererUtil.checkGLError(); - } - clearVertexAttribs(); - } - - private void renderMeshDefault(Mesh mesh, int lod, int count) { - VertexBuffer indices; - VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); - if (interleavedData != null && interleavedData.isUpdateNeeded()) { - updateBufferData(interleavedData); - } - - //IntMap buffers = mesh.getBuffers(); ; - if (mesh.getNumLodLevels() > 0) { - indices = mesh.getLodLevel(lod); - } else { - indices = mesh.getBuffer(Type.Index);// buffers.get(Type.Index.ordinal()); - } - for (VertexBuffer vb : mesh.getBufferList().getArray()){ - if (vb.getBufferType() == Type.InterleavedData - || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers - || vb.getBufferType() == Type.Index) { - continue; - } - - if (vb.getStride() == 0) { - // not interleaved - setVertexAttrib(vb); - } else { - // interleaved - setVertexAttrib(vb, interleavedData); - } - } - if (indices != null) { - drawTriangleList(indices, mesh, count); - } else { -// throw new UnsupportedOperationException("Cannot render without index buffer"); - GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount()); - RendererUtil.checkGLError(); - } - clearVertexAttribs(); - } - - public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { - if (mesh.getVertexCount() == 0) { - return; - } - - /* - * NOTE: not supported in OpenGL ES 2.0. - if (context.pointSize != mesh.getPointSize()) { - GLES10.glPointSize(mesh.getPointSize()); - context.pointSize = mesh.getPointSize(); - } - */ - if (context.lineWidth != mesh.getLineWidth()) { - GLES20.glLineWidth(mesh.getLineWidth()); - RendererUtil.checkGLError(); - context.lineWidth = mesh.getLineWidth(); - } - - statistics.onMeshDrawn(mesh, lod); -// if (GLContext.getCapabilities().GL_ARB_vertex_array_object){ -// renderMeshVertexArray(mesh, lod, count); -// }else{ - - if (useVBO) { - renderMeshDefault(mesh, lod, count); - } else { - renderMeshVertexArray(mesh, lod, count); - } - } - - /** - * drawTriangleList_Array uses Vertex Array - * @param indexBuf - * @param mesh - * @param count - */ - public void drawTriangleList_Array(VertexBuffer indexBuf, Mesh mesh, int count) { - if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { - throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); - } - - boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); - if (useInstancing) { - throw new IllegalArgumentException("Caps.MeshInstancing is not supported."); - } - - int vertCount = mesh.getVertexCount(); - Buffer indexData = indexBuf.getData(); - indexData.rewind(); - - if (mesh.getMode() == Mode.Hybrid) { - int[] modeStart = mesh.getModeStart(); - int[] elementLengths = mesh.getElementLengths(); - - int elMode = convertElementMode(Mode.Triangles); - int fmt = convertVertexBufferFormat(indexBuf.getFormat()); - int elSize = indexBuf.getFormat().getComponentSize(); - int listStart = modeStart[0]; - int stripStart = modeStart[1]; - int fanStart = modeStart[2]; - int curOffset = 0; - for (int i = 0; i < elementLengths.length; i++) { - if (i == stripStart) { - elMode = convertElementMode(Mode.TriangleStrip); - } else if (i == fanStart) { - elMode = convertElementMode(Mode.TriangleFan); - } - int elementLength = elementLengths[i]; - - indexBuf.getData().position(curOffset); - GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData()); - RendererUtil.checkGLError(); - - curOffset += elementLength * elSize; - } - } else { - GLES20.glDrawElements( - convertElementMode(mesh.getMode()), - indexBuf.getData().limit(), - convertVertexBufferFormat(indexBuf.getFormat()), - indexBuf.getData()); - RendererUtil.checkGLError(); - } - } - - /** - * setVertexAttrib_Array uses Vertex Array - * @param vb - * @param idb - */ - public void setVertexAttrib_Array(VertexBuffer vb, VertexBuffer idb) { - if (vb.getBufferType() == VertexBuffer.Type.Index) { - throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); - } - - // Get shader - int programId = context.boundShaderProgram; - if (programId > 0) { - VertexBuffer[] attribs = context.boundAttribs; - - Attribute attrib = boundShader.getAttribute(vb.getBufferType()); - int loc = attrib.getLocation(); - if (loc == -1) { - //throw new IllegalArgumentException("Location is invalid for attrib: [" + vb.getBufferType().name() + "]"); - return; - } else if (loc == -2) { - String attributeName = "in" + vb.getBufferType().name(); - - loc = GLES20.glGetAttribLocation(programId, attributeName); - RendererUtil.checkGLError(); - - if (loc < 0) { - attrib.setLocation(-1); - return; // not available in shader. - } else { - attrib.setLocation(loc); - } - - } // if (loc == -2) - - if ((attribs[loc] != vb) || vb.isUpdateNeeded()) { - // NOTE: Use data from interleaved buffer if specified - VertexBuffer avb = idb != null ? idb : vb; - avb.getData().rewind(); - avb.getData().position(vb.getOffset()); - - // Upload attribute data - GLES20.glVertexAttribPointer(loc, - vb.getNumComponents(), - convertVertexBufferFormat(vb.getFormat()), - vb.isNormalized(), - vb.getStride(), - avb.getData()); - - RendererUtil.checkGLError(); - - GLES20.glEnableVertexAttribArray(loc); - RendererUtil.checkGLError(); - - attribs[loc] = vb; - } // if (attribs[loc] != vb) - } else { - throw new IllegalStateException("Cannot render mesh without shader bound"); - } - } - - /** - * setVertexAttrib_Array uses Vertex Array - * @param vb - */ - public void setVertexAttrib_Array(VertexBuffer vb) { - setVertexAttrib_Array(vb, null); - } - - public void setAlphaToCoverage(boolean value) { - if (value) { - GLES20.glEnable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE); - RendererUtil.checkGLError(); - } else { - GLES20.glDisable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE); - RendererUtil.checkGLError(); - } - } - - @Override - public void invalidateState() { - context.reset(); - boundShader = null; - lastFb = null; - } - - public void setMainFrameBufferSrgb(boolean srgb) { - //TODO once opglES3.0 is supported maybe.... - } - - public void setLinearizeSrgbImages(boolean linearize) { - //TODO once opglES3.0 is supported maybe.... - } - - public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { - throw new UnsupportedOperationException("Not supported yet. URA will make that work seamlessly"); - } -} diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java index 666da7896..6a5222a9c 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java @@ -31,6 +31,7 @@ */ package com.jme3.scene.plugins.blender.file; +import java.util.logging.Level; import java.util.logging.Logger; import com.jme3.scene.plugins.blender.BlenderContext; @@ -171,8 +172,21 @@ public class FileBlockHeader { BLOCK_IP00('I' << 24 | 'P' << 16), // ipo BLOCK_AC00('A' << 24 | 'C' << 16), // action BLOCK_IM00('I' << 24 | 'M' << 16), // image - BLOCK_TE00('T' << 24 | 'E' << 16), BLOCK_WM00('W' << 24 | 'M' << 16), BLOCK_SR00('S' << 24 | 'R' << 16), BLOCK_SN00('S' << 24 | 'N' << 16), BLOCK_BR00('B' << 24 | 'R' << 16), BLOCK_LS00('L' << 24 | 'S' << 16), BLOCK_GLOB('G' << 24 | 'L' << 16 | 'O' << 8 | 'B'), BLOCK_REND('R' << 24 | 'E' << 16 | 'N' << 8 | 'D'), BLOCK_DATA('D' << 24 | 'A' << 16 | 'T' << 8 | 'A'), BLOCK_DNA1('D' << 24 | 'N' << 16 | 'A' << 8 | '1'), BLOCK_ENDB('E' << 24 | 'N' << 16 | 'D' << 8 | 'B'), BLOCK_TEST('T' << 24 | 'E' << 16 - | 'S' << 8 | 'T'), BLOCK_UNKN(0); + BLOCK_TE00('T' << 24 | 'E' << 16), + BLOCK_WM00('W' << 24 | 'M' << 16), + BLOCK_SR00('S' << 24 | 'R' << 16), + BLOCK_SN00('S' << 24 | 'N' << 16), + BLOCK_BR00('B' << 24 | 'R' << 16), + BLOCK_LS00('L' << 24 | 'S' << 16), + BLOCK_GR00('G' << 24 | 'R' << 16), + BLOCK_AR00('A' << 24 | 'R' << 16), + BLOCK_GLOB('G' << 24 | 'L' << 16 | 'O' << 8 | 'B'), + BLOCK_REND('R' << 24 | 'E' << 16 | 'N' << 8 | 'D'), + BLOCK_DATA('D' << 24 | 'A' << 16 | 'T' << 8 | 'A'), + BLOCK_DNA1('D' << 24 | 'N' << 16 | 'A' << 8 | '1'), + BLOCK_ENDB('E' << 24 | 'N' << 16 | 'D' << 8 | 'B'), + BLOCK_TEST('T' << 24 | 'E' << 16 | 'S' << 8 | 'T'), + BLOCK_UNKN(0); private int code; @@ -187,7 +201,12 @@ public class FileBlockHeader { } } byte[] codeBytes = new byte[] { (byte) (code >> 24 & 0xFF), (byte) (code >> 16 & 0xFF), (byte) (code >> 8 & 0xFF), (byte) (code & 0xFF) }; - LOGGER.warning("Unknown block header: " + new String(codeBytes)); + for (int i = 0; i < codeBytes.length; ++i) { + if (codeBytes[i] == 0) { + codeBytes[i] = '0'; + } + } + LOGGER.log(Level.WARNING, "Unknown block header: {0}", new String(codeBytes)); return BLOCK_UNKN; } } diff --git a/jme3-bullet-native/libs/native/windows/x86/bulletjme.dll b/jme3-bullet-native/libs/native/windows/x86/bulletjme.dll index 6839705bf..6874ad53d 100644 Binary files a/jme3-bullet-native/libs/native/windows/x86/bulletjme.dll and b/jme3-bullet-native/libs/native/windows/x86/bulletjme.dll differ diff --git a/jme3-bullet-native/libs/native/windows/x86_64/bulletjme.dll b/jme3-bullet-native/libs/native/windows/x86_64/bulletjme.dll index 3a2aa3449..24ae0eb52 100644 Binary files a/jme3-bullet-native/libs/native/windows/x86_64/bulletjme.dll and b/jme3-bullet-native/libs/native/windows/x86_64/bulletjme.dll differ diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 5e3eeca90..3f14bdb10 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -84,21 +84,6 @@ public class GLRenderer implements Renderer { private final EnumSet caps = EnumSet.noneOf(Caps.class); private final EnumMap limits = new EnumMap(Limits.class); -// private int vertexTextureUnits; -// private int fragTextureUnits; -// private int vertexUniforms; -// private int fragUniforms; -// private int vertexAttribs; -// private int maxFBOSamples; -// private int maxFBOAttachs; -// private int maxMRTFBOAttachs; -// private int maxRBSize; -// private int maxTexSize; -// private int maxCubeTexSize; -// private int maxVertCount; -// private int maxTriCount; -// private int maxColorTexSamples; -// private int maxDepthTexSamples; private FrameBuffer mainFbOverride = null; private final Statistics statistics = new Statistics(); private int vpX, vpY, vpW, vpH; @@ -366,7 +351,6 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_ARB_texture_non_power_of_two") || hasExtension("GL_OES_texture_npot") || - hasExtension("GL_APPLE_texture_2D_limited_npot") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.NonPowerOfTwoTextures); } else { @@ -1859,10 +1843,6 @@ public class GLRenderer implements Renderer { } } - if (context.pointSprite) { - return; // Attempt to fix glTexParameter crash for some ATI GPUs - } - // repeat modes switch (tex.getType()) { case ThreeDimensional: @@ -2671,7 +2651,7 @@ public class GLRenderer implements Renderer { public void setMainFrameBufferSrgb(boolean enableSrgb) { // Gamma correction - if (!caps.contains(Caps.Srgb)) { + if (!caps.contains(Caps.Srgb) && enableSrgb) { // Not supported, sorry. logger.warning("sRGB framebuffer is not supported " + "by video hardware, but was requested."); diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index 5fac9c834..5ff4ac8a7 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -424,7 +424,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable renderManager.setCamera(shadowCam, false); renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]); - renderManager.getRenderer().clearBuffers(false, true, false); + renderManager.getRenderer().clearBuffers(true, true, true); // render shadow casters to shadow map viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true); diff --git a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java index bc4273db7..1410574ea 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java @@ -190,7 +190,7 @@ public class BasicShadowRenderer implements SceneProcessor { renderManager.setForcedMaterial(preshadowMat); r.setFrameBuffer(shadowFB); - r.clearBuffers(false, true, false); + r.clearBuffers(true, true, true); viewPort.getQueue().renderShadowQueue(shadowOccluders, renderManager, shadowCam, true); r.setFrameBuffer(viewPort.getOutputFrameBuffer()); diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java index 182052e13..e06b5c337 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -450,7 +450,7 @@ public class PssmShadowRenderer implements SceneProcessor { } r.setFrameBuffer(shadowFB[i]); - r.clearBuffers(false, true, false); + r.clearBuffers(true, true, true); // render shadow casters to shadow map viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true); diff --git a/jme3-core/src/main/resources/Common/ShaderLib/MultiSample.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/MultiSample.glsllib index bea736f9d..3b06e6441 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/MultiSample.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/MultiSample.glsllib @@ -15,8 +15,14 @@ uniform int m_NumSamplesDepth; #define DEPTHTEXTURE sampler2D #endif -// NOTE: Only define multisample functions if multisample is available and is being used! -#if defined(GL_ARB_texture_multisample) && (defined(RESOLVE_MS) || defined(RESOLVE_DEPTH_MS)) +#if __VERSION__ >= 150 + #define TEXTURE texture +#else + #define TEXTURE texture2D +#endif + +// NOTE: Only define multisample functions if multisample is available +#if defined(GL_ARB_texture_multisample) vec4 textureFetch(in sampler2DMS tex,in vec2 texC, in int numSamples){ ivec2 iTexC = ivec2(texC * vec2(textureSize(tex))); vec4 color = vec4(0.0); @@ -44,40 +50,21 @@ vec4 getDepth(in sampler2DMS tex,in vec2 texC){ return textureFetch(tex,texC,m_NumSamplesDepth); } -#elif __VERSION__ >= 150 - -vec4 fetchTextureSample(in sampler2D tex,in vec2 texC,in int sample){ - return texture(tex,texC); -} - -vec4 getColor(in sampler2D tex, in vec2 texC){ - return texture(tex,texC); -} - -vec4 getColorSingle(in sampler2D tex, in vec2 texC){ - return texture(tex, texC); -} - -vec4 getDepth(in sampler2D tex,in vec2 texC){ - return texture(tex,texC); -} - -#else +#endif vec4 fetchTextureSample(in sampler2D tex,in vec2 texC,in int sample){ - return texture2D(tex,texC); + return TEXTURE(tex,texC); } vec4 getColor(in sampler2D tex, in vec2 texC){ - return texture2D(tex,texC); + return TEXTURE(tex,texC); } vec4 getColorSingle(in sampler2D tex, in vec2 texC){ - return texture2D(tex, texC); + return TEXTURE(tex, texC); } vec4 getDepth(in sampler2D tex,in vec2 texC){ - return texture2D(tex,texC); + return TEXTURE(tex,texC); } -#endif \ No newline at end of file diff --git a/jme3-examples/build.gradle b/jme3-examples/build.gradle index 186a6bc2d..de1c3931c 100644 --- a/jme3-examples/build.gradle +++ b/jme3-examples/build.gradle @@ -6,7 +6,10 @@ if (!hasProperty('mainClass')) { task run(dependsOn: 'build', type:JavaExec) { main = mainClass - classpath = sourceSets.main.runtimeClasspath + classpath = sourceSets.main.runtimeClasspath + if( assertions == "true" ){ + enableAssertions = true; + } } dependencies { diff --git a/jme3-examples/gradle.properties b/jme3-examples/gradle.properties new file mode 100644 index 000000000..6f0993120 --- /dev/null +++ b/jme3-examples/gradle.properties @@ -0,0 +1,5 @@ +# When running this project we don't need javadoc to be built. +buildJavaDoc = false + +# We want assertions, because this is the test project. +assertions = true diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java deleted file mode 100644 index e614d1dfd..000000000 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java +++ /dev/null @@ -1,2695 +0,0 @@ -/* - * 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.lwjgl; - -import com.jme3.light.LightList; -import com.jme3.material.RenderState; -import com.jme3.material.RenderState.StencilOperation; -import com.jme3.material.RenderState.TestFunction; -import com.jme3.math.*; -import com.jme3.renderer.*; -import com.jme3.scene.Mesh; -import com.jme3.scene.Mesh.Mode; -import com.jme3.scene.VertexBuffer; -import com.jme3.scene.VertexBuffer.Format; -import com.jme3.scene.VertexBuffer.Type; -import com.jme3.scene.VertexBuffer.Usage; -import com.jme3.shader.Attribute; -import com.jme3.shader.Shader; -import com.jme3.shader.Shader.ShaderSource; -import com.jme3.shader.Shader.ShaderType; -import com.jme3.shader.Uniform; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.FrameBuffer.RenderBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapAxis; -import com.jme3.util.BufferUtils; -import com.jme3.util.ListMap; -import com.jme3.util.NativeObjectManager; -import java.nio.*; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3tools.converters.MipMapGenerator; -import jme3tools.shader.ShaderDebug; - -import static org.lwjgl.opengl.ARBDrawInstanced.*; -import static org.lwjgl.opengl.ARBInstancedArrays.*; -import static org.lwjgl.opengl.ARBMultisample.*; -import static org.lwjgl.opengl.ARBTextureMultisample.*; -import static org.lwjgl.opengl.ARBVertexArrayObject.*; -import static org.lwjgl.opengl.EXTFramebufferBlit.*; -import static org.lwjgl.opengl.EXTFramebufferMultisample.*; -import static org.lwjgl.opengl.EXTFramebufferObject.*; -import static org.lwjgl.opengl.EXTFramebufferSRGB.*; -import static org.lwjgl.opengl.EXTTextureArray.*; -import static org.lwjgl.opengl.EXTTextureFilterAnisotropic.*; -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL12.*; -import static org.lwjgl.opengl.GL13.*; -import static org.lwjgl.opengl.GL14.*; -import static org.lwjgl.opengl.GL15.*; -import static org.lwjgl.opengl.GL20.*; -import org.lwjgl.opengl.GL30; - -/** - * - * Should not be used, has been replaced by Unified Rendering Architechture. - * @deprecated - */ -@Deprecated -public class LwjglRenderer { - - private static final Logger logger = Logger.getLogger(LwjglRenderer.class.getName()); - private static final boolean VALIDATE_SHADER = false; - private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); - private final StringBuilder stringBuf = new StringBuilder(250); - private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); - private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16); - private final FloatBuffer floatBuf16 = BufferUtils.createFloatBuffer(16); - private final RenderContext context = new RenderContext(); - private final NativeObjectManager objManager = new NativeObjectManager(); - private final EnumSet caps = EnumSet.noneOf(Caps.class); - - private int vertexTextureUnits; - private int fragTextureUnits; - private int vertexUniforms; - private int fragUniforms; - private int vertexAttribs; - private int maxFBOSamples; - private int maxFBOAttachs; - private int maxMRTFBOAttachs; - private int maxRBSize; - private int maxTexSize; - private int maxCubeTexSize; - private int maxVertCount; - private int maxTriCount; - private int maxColorTexSamples; - private int maxDepthTexSamples; - private FrameBuffer mainFbOverride = null; - private final Statistics statistics = new Statistics(); - private int vpX, vpY, vpW, vpH; - private int clipX, clipY, clipW, clipH; - private boolean linearizeSrgbImages; - private HashSet extensions; - - public LwjglRenderer() { - } - - protected void updateNameBuffer() { - int len = stringBuf.length(); - - nameBuf.position(0); - nameBuf.limit(len); - for (int i = 0; i < len; i++) { - nameBuf.put((byte) stringBuf.charAt(i)); - } - - nameBuf.rewind(); - } - -// @Override - public Statistics getStatistics() { - return statistics; - } - - // @Override - public EnumSet getCaps() { - return caps; - } - - private static HashSet loadExtensions(String extensions) { - HashSet extensionSet = new HashSet(64); - for (String extension : extensions.split(" ")) { - extensionSet.add(extension); - } - return extensionSet; - } - - private static int extractVersion(String prefixStr, String versionStr) { - if (versionStr != null) { - int spaceIdx = versionStr.indexOf(" ", prefixStr.length()); - if (spaceIdx >= 1) { - versionStr = versionStr.substring(prefixStr.length(), spaceIdx).trim(); - } else { - versionStr = versionStr.substring(prefixStr.length()).trim(); - } - - // Find a character which is not a period or digit. - for (int i = 0; i < versionStr.length(); i++) { - char c = versionStr.charAt(i); - if (c != '.' && (c < '0' || c > '9')) { - versionStr = versionStr.substring(0, i); - break; - } - } - - // Pivot on first point. - int firstPoint = versionStr.indexOf("."); - - // Remove everything after second point. - int secondPoint = versionStr.indexOf(".", firstPoint + 1); - - if (secondPoint != -1) { - versionStr = versionStr.substring(0, secondPoint); - } - - String majorVerStr = versionStr.substring(0, firstPoint); - String minorVerStr = versionStr.substring(firstPoint + 1); - - if (minorVerStr.endsWith("0") && minorVerStr.length() > 1) { - minorVerStr = minorVerStr.substring(0, minorVerStr.length() - 1); - } - - int majorVer = Integer.parseInt(majorVerStr); - int minorVer = Integer.parseInt(minorVerStr); - - return majorVer * 100 + minorVer * 10; - } else { - return -1; - } - } - - private boolean hasExtension(String extensionName) { - return extensions.contains(extensionName); - } - - private void loadCapabilities() { - int oglVer = extractVersion("", glGetString(GL_VERSION)); - - if (oglVer >= 200) { - caps.add(Caps.OpenGL20); - if (oglVer >= 210) { - caps.add(Caps.OpenGL21); - if (oglVer >= 300) { - caps.add(Caps.OpenGL30); - if (oglVer >= 310) { - caps.add(Caps.OpenGL31); - if (oglVer >= 320) { - caps.add(Caps.OpenGL32); - } - } - } - } - } - - int glslVer = extractVersion("", glGetString(GL_SHADING_LANGUAGE_VERSION)); - - switch (glslVer) { - default: - if (glslVer < 400) { - break; - } - // so that future OpenGL revisions wont break jme3 - // fall through intentional - case 400: - case 330: - case 150: - caps.add(Caps.GLSL150); - case 140: - caps.add(Caps.GLSL140); - case 130: - caps.add(Caps.GLSL130); - case 120: - caps.add(Caps.GLSL120); - case 110: - caps.add(Caps.GLSL110); - case 100: - caps.add(Caps.GLSL100); - break; - } - - // Workaround, always assume we support GLSL100. - // Some cards just don't report this correctly. - caps.add(Caps.GLSL100); - - extensions = loadExtensions(glGetString(GL_EXTENSIONS)); - } - - @SuppressWarnings("fallthrough") - public void initialize() { - loadCapabilities(); - - // Fix issue in TestRenderToMemory when GL_FRONT is the main - // buffer being used. - context.initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); - context.initialReadBuf = glGetInteger(GL_READ_BUFFER); - - // XXX: This has to be GL_BACK for canvas on Mac - // Since initialDrawBuf is GL_FRONT for pbuffer, gotta - // change this value later on ... -// initialDrawBuf = GL_BACK; -// initialReadBuf = GL_BACK; - - glGetInteger(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, intBuf16); - vertexTextureUnits = intBuf16.get(0); - logger.log(Level.FINER, "VTF Units: {0}", vertexTextureUnits); - if (vertexTextureUnits > 0) { - caps.add(Caps.VertexTextureFetch); - } - - glGetInteger(GL_MAX_TEXTURE_IMAGE_UNITS, intBuf16); - fragTextureUnits = intBuf16.get(0); - logger.log(Level.FINER, "Texture Units: {0}", fragTextureUnits); - - glGetInteger(GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16); - vertexUniforms = intBuf16.get(0); - logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); - - glGetInteger(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); - fragUniforms = intBuf16.get(0); - logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); - - glGetInteger(GL_MAX_VERTEX_ATTRIBS, intBuf16); - vertexAttribs = intBuf16.get(0); - logger.log(Level.FINER, "Vertex Attributes: {0}", vertexAttribs); - - glGetInteger(GL_SUBPIXEL_BITS, intBuf16); - int subpixelBits = intBuf16.get(0); - logger.log(Level.FINER, "Subpixel Bits: {0}", subpixelBits); - - glGetInteger(GL_MAX_ELEMENTS_VERTICES, intBuf16); - maxVertCount = intBuf16.get(0); - logger.log(Level.FINER, "Preferred Batch Vertex Count: {0}", maxVertCount); - - glGetInteger(GL_MAX_ELEMENTS_INDICES, intBuf16); - maxTriCount = intBuf16.get(0); - logger.log(Level.FINER, "Preferred Batch Index Count: {0}", maxTriCount); - - glGetInteger(GL_MAX_TEXTURE_SIZE, intBuf16); - maxTexSize = intBuf16.get(0); - logger.log(Level.FINER, "Maximum Texture Resolution: {0}", maxTexSize); - - glGetInteger(GL_MAX_CUBE_MAP_TEXTURE_SIZE, intBuf16); - maxCubeTexSize = intBuf16.get(0); - logger.log(Level.FINER, "Maximum CubeMap Resolution: {0}", maxCubeTexSize); - - // ctxCaps = GLContext.getCapabilities(); - - if (hasExtension("GL_ARB_color_buffer_float") && - hasExtension("GL_ARB_half_float_pixel")) { - // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. - caps.add(Caps.FloatColorBuffer); - } - - if (hasExtension("GL_ARB_depth_buffer_float")) { - caps.add(Caps.FloatDepthBuffer); - } - - if (caps.contains(Caps.OpenGL30)) { - caps.add(Caps.PackedDepthStencilBuffer); - } - - if (hasExtension("GL_ARB_draw_instanced") && - hasExtension("GL_ARB_instanced_arrays")) { - caps.add(Caps.MeshInstancing); - } - - if (hasExtension("GL_ARB_texture_buffer_object")) { - caps.add(Caps.TextureBuffer); - } - - if (hasExtension("GL_ARB_texture_float") && - hasExtension("GL_ARB_half_float_pixel")) { - caps.add(Caps.FloatTexture); - } - - if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30)) { - caps.add(Caps.VertexBufferArray); - } - - if (hasExtension("GL_ARB_texture_non_power_of_two") || caps.contains(Caps.OpenGL30)) { - caps.add(Caps.NonPowerOfTwoTextures); - } else { - logger.log(Level.WARNING, "Your graphics card does not " - + "support non-power-of-2 textures. " - + "Some features might not work."); - } - - if (hasExtension("GL_EXT_texture_compression_s3tc")) { - caps.add(Caps.TextureCompressionS3TC); - } - - if (hasExtension("GL_ARB_ES3_compatibility")) { - caps.add(Caps.TextureCompressionETC1); - } - - if (hasExtension("GL_EXT_packed_float") || caps.contains(Caps.OpenGL30)) { - // This format is part of the OGL3 specification - caps.add(Caps.PackedFloatColorBuffer); - - if (hasExtension("GL_ARB_half_float_pixel")) { - // because textures are usually uploaded as RGB16F - // need half-float pixel - caps.add(Caps.PackedFloatTexture); - } - } - - if (hasExtension("GL_EXT_texture_array") || caps.contains(Caps.OpenGL30)) { - caps.add(Caps.TextureArray); - } - - if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) { - caps.add(Caps.SharedExponentTexture); - } - - if (hasExtension("GL_EXT_texture_filter_anisotropic")) { - caps.add(Caps.TextureFilterAnisotropic); - } - - if (hasExtension("GL_EXT_framebuffer_object")) { - caps.add(Caps.FrameBuffer); - - glGetInteger(GL_MAX_RENDERBUFFER_SIZE_EXT, intBuf16); - maxRBSize = intBuf16.get(0); - logger.log(Level.FINER, "FBO RB Max Size: {0}", maxRBSize); - - glGetInteger(GL_MAX_COLOR_ATTACHMENTS_EXT, intBuf16); - maxFBOAttachs = intBuf16.get(0); - logger.log(Level.FINER, "FBO Max renderbuffers: {0}", maxFBOAttachs); - - if (hasExtension("GL_EXT_framebuffer_blit")) { - caps.add(Caps.FrameBufferBlit); - } - - if (hasExtension("GL_EXT_framebuffer_multisample")) { - caps.add(Caps.FrameBufferMultisample); - - glGetInteger(GL_MAX_SAMPLES_EXT, intBuf16); - maxFBOSamples = intBuf16.get(0); - logger.log(Level.FINER, "FBO Max Samples: {0}", maxFBOSamples); - } - - if (hasExtension("GL_ARB_texture_multisample")) { - caps.add(Caps.TextureMultisample); - - glGetInteger(GL_MAX_COLOR_TEXTURE_SAMPLES, intBuf16); - maxColorTexSamples = intBuf16.get(0); - logger.log(Level.FINER, "Texture Multisample Color Samples: {0}", maxColorTexSamples); - - glGetInteger(GL_MAX_DEPTH_TEXTURE_SAMPLES, intBuf16); - maxDepthTexSamples = intBuf16.get(0); - logger.log(Level.FINER, "Texture Multisample Depth Samples: {0}", maxDepthTexSamples); - } - - if (hasExtension("GL_ARB_draw_buffers")) { - glGetInteger(GL_MAX_DRAW_BUFFERS, intBuf16); - maxMRTFBOAttachs = intBuf16.get(0); - if (maxMRTFBOAttachs > 1) { - caps.add(Caps.FrameBufferMRT); - logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs); - } - } - } - - if (hasExtension("GL_ARB_multisample")) { - glGetInteger(GL_SAMPLE_BUFFERS_ARB, intBuf16); - boolean available = intBuf16.get(0) != 0; - glGetInteger(GL_SAMPLES_ARB, intBuf16); - int samples = intBuf16.get(0); - logger.log(Level.FINER, "Samples: {0}", samples); - boolean enabled = glIsEnabled(GL_MULTISAMPLE_ARB); - if (samples > 0 && available && !enabled) { - glEnable(GL_MULTISAMPLE_ARB); - } - caps.add(Caps.Multisample); - } - - // Supports sRGB pipeline. - if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) - || caps.contains(Caps.OpenGL30) ) { - caps.add(Caps.Srgb); - } - - logger.log(Level.FINE, "Caps: {0}", caps); - } - - public void invalidateState() { - context.reset(); - context.initialDrawBuf = glGetInteger(GL_DRAW_BUFFER); - context.initialReadBuf = glGetInteger(GL_READ_BUFFER); - } - - public void resetGLObjects() { - logger.log(Level.FINE, "Reseting objects and invalidating state"); - objManager.resetObjects(); - statistics.clearMemory(); - invalidateState(); - } - - public void cleanup() { - logger.log(Level.FINE, "Deleting objects and invalidating state"); - objManager.deleteAllObjects(this); - statistics.clearMemory(); - invalidateState(); - } - - private void checkCap(Caps cap) { - if (!caps.contains(cap)) { - throw new UnsupportedOperationException("Required capability missing: " + cap.name()); - } - } - - /*********************************************************************\ - |* Render State *| - \*********************************************************************/ - public void setDepthRange(float start, float end) { - glDepthRange(start, end); - } - - public void clearBuffers(boolean color, boolean depth, boolean stencil) { - int bits = 0; - if (color) { - //See explanations of the depth below, we must enable color write to be able to clear the color buffer - if (context.colorWriteEnabled == false) { - glColorMask(true, true, true, true); - context.colorWriteEnabled = true; - } - bits = GL_COLOR_BUFFER_BIT; - } - if (depth) { - - //glClear(GL_DEPTH_BUFFER_BIT) seems to not work when glDepthMask is false - //here s some link on openl board - //http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=257223 - //if depth clear is requested, we enable the depthMask - if (context.depthWriteEnabled == false) { - glDepthMask(true); - context.depthWriteEnabled = true; - } - bits |= GL_DEPTH_BUFFER_BIT; - } - if (stencil) { - bits |= GL_STENCIL_BUFFER_BIT; - } - if (bits != 0) { - glClear(bits); - } - } - - public void setBackgroundColor(ColorRGBA color) { - glClearColor(color.r, color.g, color.b, color.a); - } - - public void setAlphaToCoverage(boolean value) { - if (caps.contains(Caps.Multisample)) { - if (value) { - glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); - } else { - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); - } - } - } - - public void applyRenderState(RenderState state) { - if (state.isWireframe() && !context.wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - context.wireframe = true; - } else if (!state.isWireframe() && context.wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - context.wireframe = false; - } - - if (state.isDepthTest() && !context.depthTestEnabled) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(convertTestFunction(context.depthFunc)); - context.depthTestEnabled = true; - } else if (!state.isDepthTest() && context.depthTestEnabled) { - glDisable(GL_DEPTH_TEST); - context.depthTestEnabled = false; - } - if (state.getDepthFunc() != context.depthFunc) { - glDepthFunc(convertTestFunction(state.getDepthFunc())); - context.depthFunc = state.getDepthFunc(); - } - - if (state.isAlphaTest() && !context.alphaTestEnabled) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(convertTestFunction(context.alphaFunc), context.alphaTestFallOff); - context.alphaTestEnabled = true; - } else if (!state.isAlphaTest() && context.alphaTestEnabled) { - glDisable(GL_ALPHA_TEST); - context.alphaTestEnabled = false; - } - if (state.getAlphaFallOff() != context.alphaTestFallOff) { - glAlphaFunc(convertTestFunction(context.alphaFunc), context.alphaTestFallOff); - context.alphaTestFallOff = state.getAlphaFallOff(); - } - if (state.getAlphaFunc() != context.alphaFunc) { - glAlphaFunc(convertTestFunction(state.getAlphaFunc()), context.alphaTestFallOff); - context.alphaFunc = state.getAlphaFunc(); - } - - if (state.isDepthWrite() && !context.depthWriteEnabled) { - glDepthMask(true); - context.depthWriteEnabled = true; - } else if (!state.isDepthWrite() && context.depthWriteEnabled) { - glDepthMask(false); - context.depthWriteEnabled = false; - } - - if (state.isColorWrite() && !context.colorWriteEnabled) { - glColorMask(true, true, true, true); - context.colorWriteEnabled = true; - } else if (!state.isColorWrite() && context.colorWriteEnabled) { - glColorMask(false, false, false, false); - context.colorWriteEnabled = false; - } - - if (state.isPointSprite() && !context.pointSprite) { - // Only enable/disable sprite - if (context.boundTextures[0] != null) { - if (context.boundTextureUnit != 0) { - glActiveTexture(GL_TEXTURE0); - context.boundTextureUnit = 0; - } - glEnable(GL_POINT_SPRITE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - } - context.pointSprite = true; - } else if (!state.isPointSprite() && context.pointSprite) { - if (context.boundTextures[0] != null) { - if (context.boundTextureUnit != 0) { - glActiveTexture(GL_TEXTURE0); - context.boundTextureUnit = 0; - } - glDisable(GL_POINT_SPRITE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); - context.pointSprite = false; - } - } - - if (state.isPolyOffset()) { - if (!context.polyOffsetEnabled) { - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(state.getPolyOffsetFactor(), - state.getPolyOffsetUnits()); - context.polyOffsetEnabled = true; - context.polyOffsetFactor = state.getPolyOffsetFactor(); - context.polyOffsetUnits = state.getPolyOffsetUnits(); - } else { - if (state.getPolyOffsetFactor() != context.polyOffsetFactor - || state.getPolyOffsetUnits() != context.polyOffsetUnits) { - glPolygonOffset(state.getPolyOffsetFactor(), - state.getPolyOffsetUnits()); - context.polyOffsetFactor = state.getPolyOffsetFactor(); - context.polyOffsetUnits = state.getPolyOffsetUnits(); - } - } - } else { - if (context.polyOffsetEnabled) { - glDisable(GL_POLYGON_OFFSET_FILL); - context.polyOffsetEnabled = false; - context.polyOffsetFactor = 0; - context.polyOffsetUnits = 0; - } - } - - if (state.getFaceCullMode() != context.cullMode) { - if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) { - glDisable(GL_CULL_FACE); - } else { - glEnable(GL_CULL_FACE); - } - - switch (state.getFaceCullMode()) { - case Off: - break; - case Back: - glCullFace(GL_BACK); - break; - case Front: - glCullFace(GL_FRONT); - break; - case FrontAndBack: - glCullFace(GL_FRONT_AND_BACK); - break; - default: - throw new UnsupportedOperationException("Unrecognized face cull mode: " - + state.getFaceCullMode()); - } - - context.cullMode = state.getFaceCullMode(); - } - - if (state.getBlendMode() != context.blendMode) { - if (state.getBlendMode() == RenderState.BlendMode.Off) { - glDisable(GL_BLEND); - } else { - glEnable(GL_BLEND); - switch (state.getBlendMode()) { - case Off: - break; - case Additive: - glBlendFunc(GL_ONE, GL_ONE); - break; - case AlphaAdditive: - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - break; - case Color: - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); - break; - case Alpha: - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case PremultAlpha: - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - break; - case Modulate: - glBlendFunc(GL_DST_COLOR, GL_ZERO); - break; - case ModulateX2: - glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); - break; - case Screen: - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); - break; - case Exclusion: - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); - break; - default: - throw new UnsupportedOperationException("Unrecognized blend mode: " - + state.getBlendMode()); - } - } - - context.blendMode = state.getBlendMode(); - } - - if (context.stencilTest != state.isStencilTest() - || context.frontStencilStencilFailOperation != state.getFrontStencilStencilFailOperation() - || context.frontStencilDepthFailOperation != state.getFrontStencilDepthFailOperation() - || context.frontStencilDepthPassOperation != state.getFrontStencilDepthPassOperation() - || context.backStencilStencilFailOperation != state.getBackStencilStencilFailOperation() - || context.backStencilDepthFailOperation != state.getBackStencilDepthFailOperation() - || context.backStencilDepthPassOperation != state.getBackStencilDepthPassOperation() - || context.frontStencilFunction != state.getFrontStencilFunction() - || context.backStencilFunction != state.getBackStencilFunction()) { - - context.frontStencilStencilFailOperation = state.getFrontStencilStencilFailOperation(); //terrible looking, I know - context.frontStencilDepthFailOperation = state.getFrontStencilDepthFailOperation(); - context.frontStencilDepthPassOperation = state.getFrontStencilDepthPassOperation(); - context.backStencilStencilFailOperation = state.getBackStencilStencilFailOperation(); - context.backStencilDepthFailOperation = state.getBackStencilDepthFailOperation(); - context.backStencilDepthPassOperation = state.getBackStencilDepthPassOperation(); - context.frontStencilFunction = state.getFrontStencilFunction(); - context.backStencilFunction = state.getBackStencilFunction(); - - if (state.isStencilTest()) { - glEnable(GL_STENCIL_TEST); - glStencilOpSeparate(GL_FRONT, - convertStencilOperation(state.getFrontStencilStencilFailOperation()), - convertStencilOperation(state.getFrontStencilDepthFailOperation()), - convertStencilOperation(state.getFrontStencilDepthPassOperation())); - glStencilOpSeparate(GL_BACK, - convertStencilOperation(state.getBackStencilStencilFailOperation()), - convertStencilOperation(state.getBackStencilDepthFailOperation()), - convertStencilOperation(state.getBackStencilDepthPassOperation())); - glStencilFuncSeparate(GL_FRONT, - convertTestFunction(state.getFrontStencilFunction()), - 0, Integer.MAX_VALUE); - glStencilFuncSeparate(GL_BACK, - convertTestFunction(state.getBackStencilFunction()), - 0, Integer.MAX_VALUE); - } else { - glDisable(GL_STENCIL_TEST); - } - } - } - - private int convertStencilOperation(StencilOperation stencilOp) { - switch (stencilOp) { - case Keep: - return GL_KEEP; - case Zero: - return GL_ZERO; - case Replace: - return GL_REPLACE; - case Increment: - return GL_INCR; - case IncrementWrap: - return GL_INCR_WRAP; - case Decrement: - return GL_DECR; - case DecrementWrap: - return GL_DECR_WRAP; - case Invert: - return GL_INVERT; - default: - throw new UnsupportedOperationException("Unrecognized stencil operation: " + stencilOp); - } - } - - private int convertTestFunction(TestFunction testFunc) { - switch (testFunc) { - case Never: - return GL_NEVER; - case Less: - return GL_LESS; - case LessOrEqual: - return GL_LEQUAL; - case Greater: - return GL_GREATER; - case GreaterOrEqual: - return GL_GEQUAL; - case Equal: - return GL_EQUAL; - case NotEqual: - return GL_NOTEQUAL; - case Always: - return GL_ALWAYS; - default: - throw new UnsupportedOperationException("Unrecognized test function: " + testFunc); - } - } - - /*********************************************************************\ - |* Camera and World transforms *| - \*********************************************************************/ - public void setViewPort(int x, int y, int w, int h) { - if (x != vpX || vpY != y || vpW != w || vpH != h) { - glViewport(x, y, w, h); - vpX = x; - vpY = y; - vpW = w; - vpH = h; - } - } - - public void setClipRect(int x, int y, int width, int height) { - if (!context.clipRectEnabled) { - glEnable(GL_SCISSOR_TEST); - context.clipRectEnabled = true; - } - if (clipX != x || clipY != y || clipW != width || clipH != height) { - glScissor(x, y, width, height); - clipX = x; - clipY = y; - clipW = width; - clipH = height; - } - } - - public void clearClipRect() { - if (context.clipRectEnabled) { - glDisable(GL_SCISSOR_TEST); - context.clipRectEnabled = false; - - clipX = 0; - clipY = 0; - clipW = 0; - clipH = 0; - } - } - - public void postFrame() { - objManager.deleteUnused(this); -// statistics.clearFrame(); - } - - public void setWorldMatrix(Matrix4f worldMatrix) { - } - - public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) { - } - - /*********************************************************************\ - |* Shaders *| - \*********************************************************************/ - protected void updateUniformLocation(Shader shader, Uniform uniform) { - stringBuf.setLength(0); - stringBuf.append(uniform.getName()).append('\0'); - updateNameBuffer(); - int loc = glGetUniformLocation(shader.getId(), nameBuf); - if (loc < 0) { - uniform.setLocation(-1); - // uniform is not declared in shader - logger.log(Level.FINE, "Uniform {0} is not declared in shader {1}.", new Object[]{uniform.getName(), shader.getSources()}); - } else { - uniform.setLocation(loc); - } - } - - protected void bindProgram(Shader shader) { - int shaderId = shader.getId(); - if (context.boundShaderProgram != shaderId) { - glUseProgram(shaderId); - statistics.onShaderUse(shader, true); - context.boundShader = shader; - context.boundShaderProgram = shaderId; - } else { - statistics.onShaderUse(shader, false); - } - } - - protected void updateUniform(Shader shader, Uniform uniform) { - int shaderId = shader.getId(); - - assert uniform.getName() != null; - assert shader.getId() > 0; - - bindProgram(shader); - - int loc = uniform.getLocation(); - if (loc == -1) { - return; - } - - if (loc == -2) { - // get uniform location - updateUniformLocation(shader, uniform); - if (uniform.getLocation() == -1) { - // not declared, ignore - uniform.clearUpdateNeeded(); - return; - } - loc = uniform.getLocation(); - } - - if (uniform.getVarType() == null) { - return; // value not set yet.. - } - statistics.onUniformSet(); - - uniform.clearUpdateNeeded(); - FloatBuffer fb; - IntBuffer ib; - switch (uniform.getVarType()) { - case Float: - Float f = (Float) uniform.getValue(); - glUniform1f(loc, f.floatValue()); - break; - case Vector2: - Vector2f v2 = (Vector2f) uniform.getValue(); - glUniform2f(loc, v2.getX(), v2.getY()); - break; - case Vector3: - Vector3f v3 = (Vector3f) uniform.getValue(); - glUniform3f(loc, v3.getX(), v3.getY(), v3.getZ()); - break; - case Vector4: - Object val = uniform.getValue(); - if (val instanceof ColorRGBA) { - ColorRGBA c = (ColorRGBA) val; - glUniform4f(loc, c.r, c.g, c.b, c.a); - } else if (val instanceof Vector4f) { - Vector4f c = (Vector4f) val; - glUniform4f(loc, c.x, c.y, c.z, c.w); - } else { - Quaternion c = (Quaternion) uniform.getValue(); - glUniform4f(loc, c.getX(), c.getY(), c.getZ(), c.getW()); - } - break; - case Boolean: - Boolean b = (Boolean) uniform.getValue(); - glUniform1i(loc, b.booleanValue() ? GL_TRUE : GL_FALSE); - break; - case Matrix3: - fb = (FloatBuffer) uniform.getValue(); - assert fb.remaining() == 9; - glUniformMatrix3(loc, false, fb); - break; - case Matrix4: - fb = (FloatBuffer) uniform.getValue(); - assert fb.remaining() == 16; - glUniformMatrix4(loc, false, fb); - break; - case IntArray: - ib = (IntBuffer) uniform.getValue(); - glUniform1(loc, ib); - break; - case FloatArray: - fb = (FloatBuffer) uniform.getValue(); - glUniform1(loc, fb); - break; - case Vector2Array: - fb = (FloatBuffer) uniform.getValue(); - glUniform2(loc, fb); - break; - case Vector3Array: - fb = (FloatBuffer) uniform.getValue(); - glUniform3(loc, fb); - break; - case Vector4Array: - fb = (FloatBuffer) uniform.getValue(); - glUniform4(loc, fb); - break; - case Matrix4Array: - fb = (FloatBuffer) uniform.getValue(); - glUniformMatrix4(loc, false, fb); - break; - case Int: - Integer i = (Integer) uniform.getValue(); - glUniform1i(loc, i.intValue()); - break; - default: - throw new UnsupportedOperationException("Unsupported uniform type: " + uniform.getVarType()); - } - } - - protected void updateShaderUniforms(Shader shader) { - ListMap uniforms = shader.getUniformMap(); - for (int i = 0; i < uniforms.size(); i++) { - Uniform uniform = uniforms.getValue(i); - if (uniform.isUpdateNeeded()) { - updateUniform(shader, uniform); - } - } - } - - protected void resetUniformLocations(Shader shader) { - ListMap uniforms = shader.getUniformMap(); - for (int i = 0; i < uniforms.size(); i++) { - Uniform uniform = uniforms.getValue(i); - uniform.reset(); // e.g check location again - } - } - - /* - * (Non-javadoc) - * Only used for fixed-function. Ignored. - */ - public void setLighting(LightList list) { - } - - public int convertShaderType(ShaderType type) { - switch (type) { - case Fragment: - return GL_FRAGMENT_SHADER; - case Vertex: - return GL_VERTEX_SHADER; - default: - throw new UnsupportedOperationException("Unrecognized shader type."); - } - } - - public void updateShaderSourceData(ShaderSource source) { - int id = source.getId(); - if (id == -1) { - // Create id - id = glCreateShader(convertShaderType(source.getType())); - if (id <= 0) { - throw new RendererException("Invalid ID received when trying to create shader."); - } - - source.setId(id); - } else { - throw new RendererException("Cannot recompile shader source"); - } - - // Upload shader source. - // Merge the defines and source code. - String language = source.getLanguage(); - stringBuf.setLength(0); - if (language.startsWith("GLSL")) { - int version = Integer.parseInt(language.substring(4)); - if (version > 100) { - stringBuf.append("#version "); - stringBuf.append(language.substring(4)); - if (version >= 150) { - stringBuf.append(" core"); - } - stringBuf.append("\n"); - } else { - // version 100 does not exist in desktop GLSL. - // put version 110 in that case to enable strict checking - stringBuf.append("#version 110\n"); - } - } - updateNameBuffer(); - - byte[] definesCodeData = source.getDefines().getBytes(); - byte[] sourceCodeData = source.getSource().getBytes(); - ByteBuffer codeBuf = BufferUtils.createByteBuffer(nameBuf.limit() - + definesCodeData.length - + sourceCodeData.length); - codeBuf.put(nameBuf); - codeBuf.put(definesCodeData); - codeBuf.put(sourceCodeData); - codeBuf.flip(); - - glShaderSource(id, codeBuf); - glCompileShader(id); - - glGetShader(id, GL_COMPILE_STATUS, intBuf1); - - boolean compiledOK = intBuf1.get(0) == GL_TRUE; - String infoLog = null; - - if (VALIDATE_SHADER || !compiledOK) { - // even if compile succeeded, check - // log for warnings - glGetShader(id, GL_INFO_LOG_LENGTH, intBuf1); - int length = intBuf1.get(0); - if (length > 3) { - // get infos - ByteBuffer logBuf = BufferUtils.createByteBuffer(length); - glGetShaderInfoLog(id, null, logBuf); - byte[] logBytes = new byte[length]; - logBuf.get(logBytes, 0, length); - // convert to string, etc - infoLog = new String(logBytes); - } - } - - if (compiledOK) { - if (infoLog != null) { - logger.log(Level.WARNING, "{0} compiled successfully, compiler warnings: \n{1}", - new Object[]{source.getName(), infoLog}); - } else { - logger.log(Level.FINE, "{0} compiled successfully.", source.getName()); - } - source.clearUpdateNeeded(); - } else { - logger.log(Level.WARNING, "Bad compile of:\n{0}", - new Object[]{ShaderDebug.formatShaderSource(stringBuf.toString() + source.getDefines() + source.getSource())}); - if (infoLog != null) { - throw new RendererException("compile error in: " + source + "\n" + infoLog); - } else { - throw new RendererException("compile error in: " + source + "\nerror: "); - } - } - } - - public void updateShaderData(Shader shader) { - int id = shader.getId(); - boolean needRegister = false; - if (id == -1) { - // create program - id = glCreateProgram(); - if (id == 0) { - throw new RendererException("Invalid ID (" + id + ") received when trying to create shader program."); - } - - shader.setId(id); - needRegister = true; - } - - for (ShaderSource source : shader.getSources()) { - if (source.isUpdateNeeded()) { - updateShaderSourceData(source); - } - glAttachShader(id, source.getId()); - } - - if (caps.contains(Caps.OpenGL30)) { - // Check if GLSL version is 1.5 for shader - GL30.glBindFragDataLocation(id, 0, "outFragColor"); - // For MRT - for (int i = 0; i < maxMRTFBOAttachs; i++) { - GL30.glBindFragDataLocation(id, i, "outFragData[" + i + "]"); - } - } - - // Link shaders to program - glLinkProgram(id); - - // Check link status - glGetProgram(id, GL_LINK_STATUS, intBuf1); - boolean linkOK = intBuf1.get(0) == GL_TRUE; - String infoLog = null; - - if (VALIDATE_SHADER || !linkOK) { - glGetProgram(id, GL_INFO_LOG_LENGTH, intBuf1); - int length = intBuf1.get(0); - if (length > 3) { - // get infos - ByteBuffer logBuf = BufferUtils.createByteBuffer(length); - glGetProgramInfoLog(id, null, logBuf); - - // convert to string, etc - byte[] logBytes = new byte[length]; - logBuf.get(logBytes, 0, length); - infoLog = new String(logBytes); - } - } - - if (linkOK) { - if (infoLog != null) { - logger.log(Level.WARNING, "Shader linked successfully. Linker warnings: \n{0}", infoLog); - } else { - logger.fine("Shader linked successfully."); - } - shader.clearUpdateNeeded(); - if (needRegister) { - // Register shader for clean up if it was created in this method. - objManager.registerObject(shader); - statistics.onNewShader(); - } else { - // OpenGL spec: uniform locations may change after re-link - resetUniformLocations(shader); - } - } else { - if (infoLog != null) { - throw new RendererException("Shader failed to link, shader:" + shader + "\n" + infoLog); - } else { - throw new RendererException("Shader failed to link, shader:" + shader + "\ninfo: "); - } - } - } - - public void setShader(Shader shader) { - if (shader == null) { - throw new IllegalArgumentException("Shader cannot be null"); - } else { - if (shader.isUpdateNeeded()) { - updateShaderData(shader); - } - - // NOTE: might want to check if any of the - // sources need an update? - - assert shader.getId() > 0; - - updateShaderUniforms(shader); - bindProgram(shader); - } - } - - public void deleteShaderSource(ShaderSource source) { - if (source.getId() < 0) { - logger.warning("Shader source is not uploaded to GPU, cannot delete."); - return; - } - source.clearUpdateNeeded(); - glDeleteShader(source.getId()); - source.resetObject(); - } - - public void deleteShader(Shader shader) { - if (shader.getId() == -1) { - logger.warning("Shader is not uploaded to GPU, cannot delete."); - return; - } - - for (ShaderSource source : shader.getSources()) { - if (source.getId() != -1) { - glDetachShader(shader.getId(), source.getId()); - deleteShaderSource(source); - } - } - - glDeleteProgram(shader.getId()); - statistics.onDeleteShader(); - shader.resetObject(); - } - - /*********************************************************************\ - |* Framebuffers *| - \*********************************************************************/ - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { - copyFrameBuffer(src, dst, true); - } - - public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) { - if (caps.contains(Caps.FrameBufferBlit)) { - int srcX0 = 0; - int srcY0 = 0; - int srcX1; - int srcY1; - - int dstX0 = 0; - int dstY0 = 0; - int dstX1; - int dstY1; - - int prevFBO = context.boundFBO; - - if (mainFbOverride != null) { - if (src == null) { - src = mainFbOverride; - } - if (dst == null) { - dst = mainFbOverride; - } - } - - if (src != null && src.isUpdateNeeded()) { - updateFrameBuffer(src); - } - - if (dst != null && dst.isUpdateNeeded()) { - updateFrameBuffer(dst); - } - - if (src == null) { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - srcX0 = vpX; - srcY0 = vpY; - srcX1 = vpX + vpW; - srcY1 = vpY + vpH; - } else { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, src.getId()); - srcX1 = src.getWidth(); - srcY1 = src.getHeight(); - } - if (dst == null) { - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - dstX0 = vpX; - dstY0 = vpY; - dstX1 = vpX + vpW; - dstY1 = vpY + vpH; - } else { - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dst.getId()); - dstX1 = dst.getWidth(); - dstY1 = dst.getHeight(); - } - int mask = GL_COLOR_BUFFER_BIT; - if (copyDepth) { - mask |= GL_DEPTH_BUFFER_BIT; - } - glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, - GL_NEAREST); - - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prevFBO); - try { - checkFrameBufferError(); - } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "Source FBO:\n{0}", src); - logger.log(Level.SEVERE, "Dest FBO:\n{0}", dst); - throw ex; - } - } else { - throw new RendererException("EXT_framebuffer_blit required."); - // TODO: support non-blit copies? - } - } - - private String getTargetBufferName(int buffer) { - switch (buffer) { - case GL_NONE: - return "NONE"; - case GL_FRONT: - return "GL_FRONT"; - case GL_BACK: - return "GL_BACK"; - default: - if (buffer >= GL_COLOR_ATTACHMENT0_EXT - && buffer <= GL_COLOR_ATTACHMENT15_EXT) { - return "GL_COLOR_ATTACHMENT" - + (buffer - GL_COLOR_ATTACHMENT0_EXT); - } else { - return "UNKNOWN? " + buffer; - } - } - } - - private void printRealRenderBufferInfo(FrameBuffer fb, RenderBuffer rb, String name) { - System.out.println("== Renderbuffer " + name + " =="); - System.out.println("RB ID: " + rb.getId()); - System.out.println("Is proper? " + glIsRenderbufferEXT(rb.getId())); - - int attachment = convertAttachmentSlot(rb.getSlot()); - - int type = glGetFramebufferAttachmentParameteriEXT(GL_DRAW_FRAMEBUFFER_EXT, - attachment, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT); - - int rbName = glGetFramebufferAttachmentParameteriEXT(GL_DRAW_FRAMEBUFFER_EXT, - attachment, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT); - - switch (type) { - case GL_NONE: - System.out.println("Type: None"); - break; - case GL_TEXTURE: - System.out.println("Type: Texture"); - break; - case GL_RENDERBUFFER_EXT: - System.out.println("Type: Buffer"); - System.out.println("RB ID: " + rbName); - break; - } - - - - } - - private void printRealFrameBufferInfo(FrameBuffer fb) { - boolean doubleBuffer = glGetBoolean(GL_DOUBLEBUFFER); - String drawBuf = getTargetBufferName(glGetInteger(GL_DRAW_BUFFER)); - String readBuf = getTargetBufferName(glGetInteger(GL_READ_BUFFER)); - - int fbId = fb.getId(); - int curDrawBinding = glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING_EXT); - int curReadBinding = glGetInteger(GL_READ_FRAMEBUFFER_BINDING_EXT); - - System.out.println("=== OpenGL FBO State ==="); - System.out.println("Context doublebuffered? " + doubleBuffer); - System.out.println("FBO ID: " + fbId); - System.out.println("Is proper? " + glIsFramebufferEXT(fbId)); - System.out.println("Is bound to draw? " + (fbId == curDrawBinding)); - System.out.println("Is bound to read? " + (fbId == curReadBinding)); - System.out.println("Draw buffer: " + drawBuf); - System.out.println("Read buffer: " + readBuf); - - if (context.boundFBO != fbId) { - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbId); - context.boundFBO = fbId; - } - - if (fb.getDepthBuffer() != null) { - printRealRenderBufferInfo(fb, fb.getDepthBuffer(), "Depth"); - } - for (int i = 0; i < fb.getNumColorBuffers(); i++) { - printRealRenderBufferInfo(fb, fb.getColorBuffer(i), "Color" + i); - } - } - - private void checkFrameBufferError() { - int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - switch (status) { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - //Choose different formats - throw new IllegalStateException("Framebuffer object format is " - + "unsupported by the video hardware."); - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - throw new IllegalStateException("Framebuffer has erronous attachment."); - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - throw new IllegalStateException("Framebuffer doesn't have any renderbuffers attached."); - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - throw new IllegalStateException("Framebuffer attachments must have same dimensions."); - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - throw new IllegalStateException("Framebuffer attachments must have same formats."); - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - throw new IllegalStateException("Incomplete draw buffer."); - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - throw new IllegalStateException("Incomplete read buffer."); - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: - throw new IllegalStateException("Incomplete multisample buffer."); - default: - //Programming error; will fail on all hardware - throw new IllegalStateException("Some video driver error " - + "or programming error occured. " - + "Framebuffer object status is invalid. "); - } - } - - private void updateRenderBuffer(FrameBuffer fb, RenderBuffer rb) { - int id = rb.getId(); - if (id == -1) { - glGenRenderbuffersEXT(intBuf1); - id = intBuf1.get(0); - rb.setId(id); - } - - if (context.boundRB != id) { - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id); - context.boundRB = id; - } - - if (fb.getWidth() > maxRBSize || fb.getHeight() > maxRBSize) { - throw new RendererException("Resolution " + fb.getWidth() - + ":" + fb.getHeight() + " is not supported."); - } - - TextureUtil.GLImageFormat glFmt = TextureUtil.getImageFormatWithError(caps, rb.getFormat(), fb.isSrgb()); - - if (fb.getSamples() > 1 && caps.contains(Caps.FrameBufferMultisample)) { - int samples = fb.getSamples(); - if (maxFBOSamples < samples) { - samples = maxFBOSamples; - } - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, - samples, - glFmt.internalFormat, - fb.getWidth(), - fb.getHeight()); - } else { - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, - glFmt.internalFormat, - fb.getWidth(), - fb.getHeight()); - } - } - - private int convertAttachmentSlot(int attachmentSlot) { - // can also add support for stencil here - if (attachmentSlot == FrameBuffer.SLOT_DEPTH) { - return GL_DEPTH_ATTACHMENT_EXT; - } else if (attachmentSlot == FrameBuffer.SLOT_DEPTH_STENCIL) { - // NOTE: Using depth stencil format requires GL3, this is already - // checked via render caps. - return GL30.GL_DEPTH_STENCIL_ATTACHMENT; - } else if (attachmentSlot < 0 || attachmentSlot >= 16) { - throw new UnsupportedOperationException("Invalid FBO attachment slot: " + attachmentSlot); - } - - return GL_COLOR_ATTACHMENT0_EXT + attachmentSlot; - } - - public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { - Texture tex = rb.getTexture(); - Image image = tex.getImage(); - if (image.isUpdateNeeded()) { - updateTexImageData(image, tex.getType(), 0); - - // NOTE: For depth textures, sets nearest/no-mips mode - // Required to fix "framebuffer unsupported" - // for old NVIDIA drivers! - setupTextureParams(tex); - } - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, - convertAttachmentSlot(rb.getSlot()), - convertTextureType(tex.getType(), image.getMultiSamples(), rb.getFace()), - image.getId(), - 0); - } - - public void updateFrameBufferAttachment(FrameBuffer fb, RenderBuffer rb) { - boolean needAttach; - if (rb.getTexture() == null) { - // if it hasn't been created yet, then attach is required. - needAttach = rb.getId() == -1; - updateRenderBuffer(fb, rb); - } else { - needAttach = false; - updateRenderTexture(fb, rb); - } - if (needAttach) { - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, - convertAttachmentSlot(rb.getSlot()), - GL_RENDERBUFFER_EXT, - rb.getId()); - } - } - - public void updateFrameBuffer(FrameBuffer fb) { - int id = fb.getId(); - if (id == -1) { - // create FBO - glGenFramebuffersEXT(intBuf1); - id = intBuf1.get(0); - fb.setId(id); - objManager.registerObject(fb); - - statistics.onNewFrameBuffer(); - } - - if (context.boundFBO != id) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); - // binding an FBO automatically sets draw buf to GL_COLOR_ATTACHMENT0 - context.boundDrawBuf = 0; - context.boundFBO = id; - } - - FrameBuffer.RenderBuffer depthBuf = fb.getDepthBuffer(); - if (depthBuf != null) { - updateFrameBufferAttachment(fb, depthBuf); - } - - for (int i = 0; i < fb.getNumColorBuffers(); i++) { - FrameBuffer.RenderBuffer colorBuf = fb.getColorBuffer(i); - updateFrameBufferAttachment(fb, colorBuf); - } - - fb.clearUpdateNeeded(); - } - - public Vector2f[] getFrameBufferSamplePositions(FrameBuffer fb) { - if (fb.getSamples() <= 1) { - throw new IllegalArgumentException("Framebuffer must be multisampled"); - } - if (!caps.contains(Caps.TextureMultisample)) { - throw new RendererException("Multisampled textures are not supported"); - } - - setFrameBuffer(fb); - - Vector2f[] samplePositions = new Vector2f[fb.getSamples()]; - FloatBuffer samplePos = BufferUtils.createFloatBuffer(2); - for (int i = 0; i < samplePositions.length; i++) { - glGetMultisample(GL_SAMPLE_POSITION, i, samplePos); - samplePos.clear(); - samplePositions[i] = new Vector2f(samplePos.get(0) - 0.5f, - samplePos.get(1) - 0.5f); - } - return samplePositions; - } - - public void setMainFrameBufferOverride(FrameBuffer fb) { - mainFbOverride = fb; - } - - public void setFrameBuffer(FrameBuffer fb) { - if (!caps.contains(Caps.FrameBuffer)) { - throw new RendererException("Framebuffer objects are not supported" + - " by the video hardware"); - } - - if (fb == null && mainFbOverride != null) { - fb = mainFbOverride; - } - - if (context.boundFB == fb) { - if (fb == null || !fb.isUpdateNeeded()) { - return; - } - } - - // generate mipmaps for last FB if needed - if (context.boundFB != null) { - for (int i = 0; i < context.boundFB.getNumColorBuffers(); i++) { - RenderBuffer rb = context.boundFB.getColorBuffer(i); - Texture tex = rb.getTexture(); - if (tex != null - && tex.getMinFilter().usesMipMapLevels()) { - setTexture(0, rb.getTexture()); - - int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace()); - glEnable(textureType); - glGenerateMipmapEXT(textureType); - glDisable(textureType); - } - } - } - - if (fb == null) { - // unbind any fbos - if (context.boundFBO != 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - statistics.onFrameBufferUse(null, true); - - context.boundFBO = 0; - } - // select back buffer - if (context.boundDrawBuf != -1) { - glDrawBuffer(context.initialDrawBuf); - context.boundDrawBuf = -1; - } - if (context.boundReadBuf != -1) { - glReadBuffer(context.initialReadBuf); - context.boundReadBuf = -1; - } - - context.boundFB = null; - } else { - if (fb.getNumColorBuffers() == 0 && fb.getDepthBuffer() == null) { - throw new IllegalArgumentException("The framebuffer: " + fb - + "\nDoesn't have any color/depth buffers"); - } - - if (fb.isUpdateNeeded()) { - updateFrameBuffer(fb); - } - - if (context.boundFBO != fb.getId()) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb.getId()); - statistics.onFrameBufferUse(fb, true); - - // update viewport to reflect framebuffer's resolution - setViewPort(0, 0, fb.getWidth(), fb.getHeight()); - - context.boundFBO = fb.getId(); - } else { - statistics.onFrameBufferUse(fb, false); - } - if (fb.getNumColorBuffers() == 0) { - // make sure to select NONE as draw buf - // no color buffer attached. select NONE - if (context.boundDrawBuf != -2) { - glDrawBuffer(GL_NONE); - context.boundDrawBuf = -2; - } - if (context.boundReadBuf != -2) { - glReadBuffer(GL_NONE); - context.boundReadBuf = -2; - } - } else { - if (fb.getNumColorBuffers() > maxFBOAttachs) { - throw new RendererException("Framebuffer has more color " - + "attachments than are supported" - + " by the video hardware!"); - } - if (fb.isMultiTarget()) { - if (fb.getNumColorBuffers() > maxMRTFBOAttachs) { - throw new RendererException("Framebuffer has more" - + " multi targets than are supported" - + " by the video hardware!"); - } - - if (context.boundDrawBuf != 100 + fb.getNumColorBuffers()) { - intBuf16.clear(); - for (int i = 0; i < fb.getNumColorBuffers(); i++) { - intBuf16.put(GL_COLOR_ATTACHMENT0_EXT + i); - } - - intBuf16.flip(); - glDrawBuffers(intBuf16); - context.boundDrawBuf = 100 + fb.getNumColorBuffers(); - } - } else { - RenderBuffer rb = fb.getColorBuffer(fb.getTargetIndex()); - // select this draw buffer - if (context.boundDrawBuf != rb.getSlot()) { - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + rb.getSlot()); - context.boundDrawBuf = rb.getSlot(); - } - } - } - - assert fb.getId() >= 0; - assert context.boundFBO == fb.getId(); - - context.boundFB = fb; - - try { - checkFrameBufferError(); - } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "=== jMonkeyEngine FBO State ===\n{0}", fb); - printRealFrameBufferInfo(fb); - throw ex; - } - } - } - - public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { - if (fb != null) { - RenderBuffer rb = fb.getColorBuffer(); - if (rb == null) { - throw new IllegalArgumentException("Specified framebuffer" - + " does not have a colorbuffer"); - } - - setFrameBuffer(fb); - if (context.boundReadBuf != rb.getSlot()) { - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + rb.getSlot()); - context.boundReadBuf = rb.getSlot(); - } - } else { - setFrameBuffer(null); - } - - glReadPixels(vpX, vpY, vpW, vpH, /*GL_RGBA*/ GL_BGRA, GL_UNSIGNED_BYTE, byteBuf); - } - - private void deleteRenderBuffer(FrameBuffer fb, RenderBuffer rb) { - intBuf1.put(0, rb.getId()); - glDeleteRenderbuffersEXT(intBuf1); - } - - public void deleteFrameBuffer(FrameBuffer fb) { - if (fb.getId() != -1) { - if (context.boundFBO == fb.getId()) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - context.boundFBO = 0; - } - - if (fb.getDepthBuffer() != null) { - deleteRenderBuffer(fb, fb.getDepthBuffer()); - } - if (fb.getColorBuffer() != null) { - deleteRenderBuffer(fb, fb.getColorBuffer()); - } - - intBuf1.put(0, fb.getId()); - glDeleteFramebuffersEXT(intBuf1); - fb.resetObject(); - - statistics.onDeleteFrameBuffer(); - } - } - - /*********************************************************************\ - |* Textures *| - \*********************************************************************/ - private int convertTextureType(Texture.Type type, int samples, int face) { - if (samples > 1 && !caps.contains(Caps.TextureMultisample)) { - throw new RendererException("Multisample textures are not supported" + - " by the video hardware."); - } - - switch (type) { - case TwoDimensional: - if (samples > 1) { - return GL_TEXTURE_2D_MULTISAMPLE; - } else { - return GL_TEXTURE_2D; - } - case TwoDimensionalArray: - if (samples > 1) { - return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; - } else { - return GL_TEXTURE_2D_ARRAY_EXT; - } - case ThreeDimensional: - return GL_TEXTURE_3D; - case CubeMap: - if (face < 0) { - return GL_TEXTURE_CUBE_MAP; - } else if (face < 6) { - return GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; - } else { - throw new UnsupportedOperationException("Invalid cube map face index: " + face); - } - default: - throw new UnsupportedOperationException("Unknown texture type: " + type); - } - } - - private int convertMagFilter(Texture.MagFilter filter) { - switch (filter) { - case Bilinear: - return GL_LINEAR; - case Nearest: - return GL_NEAREST; - default: - throw new UnsupportedOperationException("Unknown mag filter: " + filter); - } - } - - private int convertMinFilter(Texture.MinFilter filter, boolean haveMips) { - if (haveMips){ - switch (filter) { - case Trilinear: - return GL_LINEAR_MIPMAP_LINEAR; - case BilinearNearestMipMap: - return GL_LINEAR_MIPMAP_NEAREST; - case NearestLinearMipMap: - return GL_NEAREST_MIPMAP_LINEAR; - case NearestNearestMipMap: - return GL_NEAREST_MIPMAP_NEAREST; - case BilinearNoMipMaps: - return GL_LINEAR; - case NearestNoMipMaps: - return GL_NEAREST; - default: - throw new UnsupportedOperationException("Unknown min filter: " + filter); - } - } else { - switch (filter) { - case Trilinear: - case BilinearNearestMipMap: - case BilinearNoMipMaps: - return GL_LINEAR; - case NearestLinearMipMap: - case NearestNearestMipMap: - case NearestNoMipMaps: - return GL_NEAREST; - default: - throw new UnsupportedOperationException("Unknown min filter: " + filter); - } - } - } - - private int convertWrapMode(Texture.WrapMode mode) { - switch (mode) { - case BorderClamp: - return GL_CLAMP_TO_BORDER; - case Clamp: - // Falldown intentional. - case EdgeClamp: - return GL_CLAMP_TO_EDGE; - case Repeat: - return GL_REPEAT; - case MirroredRepeat: - return GL_MIRRORED_REPEAT; - default: - throw new UnsupportedOperationException("Unknown wrap mode: " + mode); - } - } - - @SuppressWarnings("fallthrough") - private void setupTextureParams(Texture tex) { - Image image = tex.getImage(); - int target = convertTextureType(tex.getType(), image != null ? image.getMultiSamples() : 1, -1); - - boolean haveMips = true; - - if (image != null) { - haveMips = image.isGeneratedMipmapsRequired() || image.hasMipmaps(); - } - - // filter things - int minFilter = convertMinFilter(tex.getMinFilter(), haveMips); - int magFilter = convertMagFilter(tex.getMagFilter()); - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilter); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilter); - - if (tex.getAnisotropicFilter() > 1) { - if (caps.contains(Caps.TextureFilterAnisotropic)) { - glTexParameterf(target, - GL_TEXTURE_MAX_ANISOTROPY_EXT, - tex.getAnisotropicFilter()); - } - } - - if (context.pointSprite) { - return; // Attempt to fix glTexParameter crash for some ATI GPUs - } - - // repeat modes - switch (tex.getType()) { - case ThreeDimensional: - case CubeMap: // cubemaps use 3D coords - glTexParameteri(target, GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R))); - //There is no break statement on purpose here - case TwoDimensional: - case TwoDimensionalArray: - glTexParameteri(target, GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T))); - // fall down here is intentional.. -// case OneDimensional: - glTexParameteri(target, GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S))); - break; - default: - throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); - } - - if(tex.isNeedCompareModeUpdate()){ - // R to Texture compare mode - if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off) { - glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(target, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); - if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual) { - glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_GEQUAL); - } else { - glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } - }else{ - //restoring default value - glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - tex.compareModeUpdated(); - } - } - - /** - * Uploads the given image to the GL driver. - * - * @param img The image to upload - * @param type How the data in the image argument should be interpreted. - * @param unit The texture slot to be used to upload the image, not important - */ - public void updateTexImageData(Image img, Texture.Type type, int unit) { - int texId = img.getId(); - if (texId == -1) { - // create texture - glGenTextures(intBuf1); - texId = intBuf1.get(0); - img.setId(texId); - objManager.registerObject(img); - - statistics.onNewTexture(); - } - - // bind texture - int target = convertTextureType(type, img.getMultiSamples(), -1); - if (context.boundTextureUnit != unit) { - glActiveTexture(GL_TEXTURE0 + unit); - context.boundTextureUnit = unit; - } - if (context.boundTextures[unit] != img) { - glBindTexture(target, texId); - context.boundTextures[unit] = img; - - statistics.onTextureUse(img, true); - } - - if (!img.hasMipmaps() && img.isGeneratedMipmapsRequired()) { - // Image does not have mipmaps, but they are required. - // Generate from base level. - - if (!caps.contains(Caps.OpenGL30) && !caps.contains(Caps.OpenGLES20)) { - glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE); - img.setMipmapsGenerated(true); - } else { - // For OpenGL3 and up. - // We'll generate mipmaps via glGenerateMipmapEXT (see below) - } - } else if (img.hasMipmaps()) { - // Image already has mipmaps, set the max level based on the - // number of mipmaps we have. - glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, img.getMipMapSizes().length - 1); - } else { - // Image does not have mipmaps and they are not required. - // Specify that that the texture has no mipmaps. - glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0); - } - - int imageSamples = img.getMultiSamples(); - if (imageSamples > 1) { - if (img.getFormat().isDepthFormat()) { - img.setMultiSamples(Math.min(maxDepthTexSamples, imageSamples)); - } else { - img.setMultiSamples(Math.min(maxColorTexSamples, imageSamples)); - } - } - - // Yes, some OpenGL2 cards (GeForce 5) still dont support NPOT. - if (!caps.contains(Caps.NonPowerOfTwoTextures) && img.isNPOT()) { - if (img.getData(0) == null) { - throw new RendererException("non-power-of-2 framebuffer textures are not supported by the video hardware"); - } else { - MipMapGenerator.resizeToPowerOf2(img); - } - } - - // Check if graphics card doesn't support multisample textures - if (!caps.contains(Caps.TextureMultisample)) { - if (img.getMultiSamples() > 1) { - throw new RendererException("Multisample textures not supported by graphics hardware"); - } - } - - if (target == GL_TEXTURE_CUBE_MAP) { - // Check max texture size before upload - if (img.getWidth() > maxCubeTexSize || img.getHeight() > maxCubeTexSize) { - throw new RendererException("Cannot upload cubemap " + img + ". The maximum supported cubemap resolution is " + maxCubeTexSize); - } - if (img.getWidth() != img.getHeight()) { - throw new RendererException("Cubemaps must have square dimensions"); - } - } else { - if (img.getWidth() > maxTexSize || img.getHeight() > maxTexSize) { - throw new RendererException("Cannot upload texture " + img + ". The maximum supported texture resolution is " + maxTexSize); - } - } - - if (target == GL_TEXTURE_CUBE_MAP) { - List data = img.getData(); - if (data.size() != 6) { - logger.log(Level.WARNING, "Invalid texture: {0}\n" - + "Cubemap textures must contain 6 data units.", img); - return; - } - for (int i = 0; i < 6; i++) { - TextureUtil.uploadTexture(caps, img, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, linearizeSrgbImages); - } - } else if (target == GL_TEXTURE_2D_ARRAY_EXT) { - if (!caps.contains(Caps.TextureArray)) { - throw new RendererException("Texture arrays not supported by graphics hardware"); - } - - List data = img.getData(); - - // -1 index specifies prepare data for 2D Array - TextureUtil.uploadTexture(caps, img, target, -1, 0, linearizeSrgbImages); - - for (int i = 0; i < data.size(); i++) { - // upload each slice of 2D array in turn - // this time with the appropriate index - TextureUtil.uploadTexture(caps, img, target, i, 0, linearizeSrgbImages); - } - } else { - TextureUtil.uploadTexture(caps, img, target, 0, 0, linearizeSrgbImages); - } - - if (img.getMultiSamples() != imageSamples) { - img.setMultiSamples(imageSamples); - } - - if (caps.contains(Caps.OpenGL30)) { - if (!img.hasMipmaps() && img.isGeneratedMipmapsRequired() && img.getData() != null) { - // XXX: Required for ATI - glEnable(target); - glGenerateMipmapEXT(target); - glDisable(target); - img.setMipmapsGenerated(true); - } - } - - img.clearUpdateNeeded(); - } - - public void setTexture(int unit, Texture tex) { - Image image = tex.getImage(); - if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) { - updateTexImageData(image, tex.getType(), unit); - } - - int texId = image.getId(); - assert texId != -1; - - Image[] textures = context.boundTextures; - - int type = convertTextureType(tex.getType(), image.getMultiSamples(), -1); -// if (!context.textureIndexList.moveToNew(unit)) { -// if (context.boundTextureUnit != unit){ -// glActiveTexture(GL_TEXTURE0 + unit); -// context.boundTextureUnit = unit; -// } -// glEnable(type); -// } - - if (context.boundTextureUnit != unit) { - glActiveTexture(GL_TEXTURE0 + unit); - context.boundTextureUnit = unit; - } - if (textures[unit] != image) { - glBindTexture(type, texId); - textures[unit] = image; - - statistics.onTextureUse(image, true); - } else { - statistics.onTextureUse(image, false); - } - - setupTextureParams(tex); - } - - public void modifyTexture(Texture tex, Image pixels, int x, int y) { - setTexture(0, tex); - TextureUtil.uploadSubTexture(caps, pixels, convertTextureType(tex.getType(), pixels.getMultiSamples(), -1), 0, x, y, linearizeSrgbImages); - } - - public void clearTextureUnits() { -// IDList textureList = context.textureIndexList; -// Image[] textures = context.boundTextures; -// for (int i = 0; i < textureList.oldLen; i++) { -// int idx = textureList.oldList[i]; -// if (context.boundTextureUnit != idx){ -// glActiveTexture(GL_TEXTURE0 + idx); -// context.boundTextureUnit = idx; -// } -// glDisable(convertTextureType(textures[idx].getType())); -// textures[idx] = null; -// } -// context.textureIndexList.copyNewToOld(); - } - - public void deleteImage(Image image) { - int texId = image.getId(); - if (texId != -1) { - intBuf1.put(0, texId); - intBuf1.position(0).limit(1); - glDeleteTextures(intBuf1); - image.resetObject(); - - statistics.onDeleteTexture(); - } - } - - /*********************************************************************\ - |* Vertex Buffers and Attributes *| - \*********************************************************************/ - private int convertUsage(Usage usage) { - switch (usage) { - case Static: - return GL_STATIC_DRAW; - case Dynamic: - return GL_DYNAMIC_DRAW; - case Stream: - return GL_STREAM_DRAW; - default: - throw new UnsupportedOperationException("Unknown usage type."); - } - } - - private int convertFormat(Format format) { - switch (format) { - case Byte: - return GL_BYTE; - case UnsignedByte: - return GL_UNSIGNED_BYTE; - case Short: - return GL_SHORT; - case UnsignedShort: - return GL_UNSIGNED_SHORT; - case Int: - return GL_INT; - case UnsignedInt: - return GL_UNSIGNED_INT; - case Float: - return GL_FLOAT; - case Double: - return GL_DOUBLE; - default: - throw new UnsupportedOperationException("Unknown buffer format."); - - } - } - - public void updateBufferData(VertexBuffer vb) { - int bufId = vb.getId(); - boolean created = false; - if (bufId == -1) { - // create buffer - glGenBuffers(intBuf1); - bufId = intBuf1.get(0); - vb.setId(bufId); - objManager.registerObject(vb); - - //statistics.onNewVertexBuffer(); - - created = true; - } - - // bind buffer - int target; - if (vb.getBufferType() == VertexBuffer.Type.Index) { - target = GL_ELEMENT_ARRAY_BUFFER; - if (context.boundElementArrayVBO != bufId) { - glBindBuffer(target, bufId); - context.boundElementArrayVBO = bufId; - //statistics.onVertexBufferUse(vb, true); - } else { - //statistics.onVertexBufferUse(vb, false); - } - } else { - target = GL_ARRAY_BUFFER; - if (context.boundArrayVBO != bufId) { - glBindBuffer(target, bufId); - context.boundArrayVBO = bufId; - //statistics.onVertexBufferUse(vb, true); - } else { - //statistics.onVertexBufferUse(vb, false); - } - } - - int usage = convertUsage(vb.getUsage()); - vb.getData().rewind(); - - if (created || vb.hasDataSizeChanged()) { - // upload data based on format - switch (vb.getFormat()) { - case Byte: - case UnsignedByte: - glBufferData(target, (ByteBuffer) vb.getData(), usage); - break; - // case Half: - case Short: - case UnsignedShort: - glBufferData(target, (ShortBuffer) vb.getData(), usage); - break; - case Int: - case UnsignedInt: - glBufferData(target, (IntBuffer) vb.getData(), usage); - break; - case Float: - glBufferData(target, (FloatBuffer) vb.getData(), usage); - break; - case Double: - glBufferData(target, (DoubleBuffer) vb.getData(), usage); - break; - default: - throw new UnsupportedOperationException("Unknown buffer format."); - } - } else { - // Invalidate buffer data (orphan) before uploading new data. - - - switch (vb.getFormat()) { - case Byte: - case UnsignedByte: - glBufferSubData(target, 0, (ByteBuffer) vb.getData()); - break; - case Short: - case UnsignedShort: - glBufferSubData(target, 0, (ShortBuffer) vb.getData()); - break; - case Int: - case UnsignedInt: - glBufferSubData(target, 0, (IntBuffer) vb.getData()); - break; - case Float: - glBufferSubData(target, 0, (FloatBuffer) vb.getData()); - break; - case Double: - glBufferSubData(target, 0, (DoubleBuffer) vb.getData()); - break; - default: - throw new UnsupportedOperationException("Unknown buffer format."); - } - } - - vb.clearUpdateNeeded(); - } - - public void deleteBuffer(VertexBuffer vb) { - int bufId = vb.getId(); - if (bufId != -1) { - // delete buffer - intBuf1.put(0, bufId); - intBuf1.position(0).limit(1); - glDeleteBuffers(intBuf1); - vb.resetObject(); - - //statistics.onDeleteVertexBuffer(); - } - } - - public void clearVertexAttribs() { - IDList attribList = context.attribIndexList; - for (int i = 0; i < attribList.oldLen; i++) { - int idx = attribList.oldList[i]; - glDisableVertexAttribArray(idx); - if (context.boundAttribs[idx].isInstanced()) { - glVertexAttribDivisorARB(idx, 0); - } - context.boundAttribs[idx] = null; - } - context.attribIndexList.copyNewToOld(); - } - - public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) { - if (vb.getBufferType() == VertexBuffer.Type.Index) { - throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib"); - } - - int programId = context.boundShaderProgram; - - if (programId > 0) { - Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); - int loc = attrib.getLocation(); - if (loc == -1) { - return; // not defined - } - if (loc == -2) { - stringBuf.setLength(0); - stringBuf.append("in").append(vb.getBufferType().name()).append('\0'); - updateNameBuffer(); - loc = glGetAttribLocation(programId, nameBuf); - - // not really the name of it in the shader (inPosition\0) but - // the internal name of the enum (Position). - if (loc < 0) { - attrib.setLocation(-1); - return; // not available in shader. - } else { - attrib.setLocation(loc); - } - } - - if (vb.isInstanced()) { - if (!caps.contains(Caps.MeshInstancing)) { - throw new RendererException("Instancing is required, " - + "but not supported by the " - + "graphics hardware"); - } - } - int slotsRequired = 1; - if (vb.getNumComponents() > 4) { - if (vb.getNumComponents() % 4 != 0) { - throw new RendererException("Number of components in multi-slot " - + "buffers must be divisible by 4"); - } - slotsRequired = vb.getNumComponents() / 4; - } - - if (vb.isUpdateNeeded() && idb == null) { - updateBufferData(vb); - } - - VertexBuffer[] attribs = context.boundAttribs; - for (int i = 0; i < slotsRequired; i++) { - if (!context.attribIndexList.moveToNew(loc + i)) { - glEnableVertexAttribArray(loc + i); - //System.out.println("Enabled ATTRIB IDX: "+loc); - } - } - if (attribs[loc] != vb) { - // NOTE: Use id from interleaved buffer if specified - int bufId = idb != null ? idb.getId() : vb.getId(); - assert bufId != -1; - if (context.boundArrayVBO != bufId) { - glBindBuffer(GL_ARRAY_BUFFER, bufId); - context.boundArrayVBO = bufId; - //statistics.onVertexBufferUse(vb, true); - } else { - //statistics.onVertexBufferUse(vb, false); - } - - if (slotsRequired == 1) { - glVertexAttribPointer(loc, - vb.getNumComponents(), - convertFormat(vb.getFormat()), - vb.isNormalized(), - vb.getStride(), - vb.getOffset()); - } else { - for (int i = 0; i < slotsRequired; i++) { - // The pointer maps the next 4 floats in the slot. - // E.g. - // P1: XXXX____________XXXX____________ - // P2: ____XXXX____________XXXX________ - // P3: ________XXXX____________XXXX____ - // P4: ____________XXXX____________XXXX - // stride = 4 bytes in float * 4 floats in slot * num slots - // offset = 4 bytes in float * 4 floats in slot * slot index - glVertexAttribPointer(loc + i, - 4, - convertFormat(vb.getFormat()), - vb.isNormalized(), - 4 * 4 * slotsRequired, - 4 * 4 * i); - } - } - - for (int i = 0; i < slotsRequired; i++) { - int slot = loc + i; - if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) { - // non-instanced -> instanced - glVertexAttribDivisorARB(slot, vb.getInstanceSpan()); - } else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) { - // instanced -> non-instanced - glVertexAttribDivisorARB(slot, 0); - } - attribs[slot] = vb; - } - } - } else { - throw new IllegalStateException("Cannot render mesh without shader bound"); - } - } - - public void setVertexAttrib(VertexBuffer vb) { - setVertexAttrib(vb, null); - } - - public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) { - boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); - if (useInstancing) { - glDrawArraysInstancedARB(convertElementMode(mode), 0, - vertCount, count); - } else { - glDrawArrays(convertElementMode(mode), 0, vertCount); - } - } - - public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { - if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { - throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); - } - - if (indexBuf.isUpdateNeeded()) { - updateBufferData(indexBuf); - } - - int bufId = indexBuf.getId(); - assert bufId != -1; - - if (context.boundElementArrayVBO != bufId) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufId); - context.boundElementArrayVBO = bufId; - //statistics.onVertexBufferUse(indexBuf, true); - } else { - //statistics.onVertexBufferUse(indexBuf, true); - } - - int vertCount = mesh.getVertexCount(); - boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); - - if (mesh.getMode() == Mode.Hybrid) { - int[] modeStart = mesh.getModeStart(); - int[] elementLengths = mesh.getElementLengths(); - - int elMode = convertElementMode(Mode.Triangles); - int fmt = convertFormat(indexBuf.getFormat()); - int elSize = indexBuf.getFormat().getComponentSize(); - int listStart = modeStart[0]; - int stripStart = modeStart[1]; - int fanStart = modeStart[2]; - int curOffset = 0; - for (int i = 0; i < elementLengths.length; i++) { - if (i == stripStart) { - elMode = convertElementMode(Mode.TriangleStrip); - } else if (i == fanStart) { - elMode = convertElementMode(Mode.TriangleFan); - } - int elementLength = elementLengths[i]; - - if (useInstancing) { - glDrawElementsInstancedARB(elMode, - elementLength, - fmt, - curOffset, - count); - } else { - glDrawRangeElements(elMode, - 0, - vertCount, - elementLength, - fmt, - curOffset); - } - - curOffset += elementLength * elSize; - } - } else { - if (useInstancing) { - glDrawElementsInstancedARB(convertElementMode(mesh.getMode()), - indexBuf.getData().limit(), - convertFormat(indexBuf.getFormat()), - 0, - count); - } else { - glDrawRangeElements(convertElementMode(mesh.getMode()), - 0, - vertCount, - indexBuf.getData().limit(), - convertFormat(indexBuf.getFormat()), - 0); - } - } - } - - /*********************************************************************\ - |* Render Calls *| - \*********************************************************************/ - public int convertElementMode(Mesh.Mode mode) { - switch (mode) { - case Points: - return GL_POINTS; - case Lines: - return GL_LINES; - case LineLoop: - return GL_LINE_LOOP; - case LineStrip: - return GL_LINE_STRIP; - case Triangles: - return GL_TRIANGLES; - case TriangleFan: - return GL_TRIANGLE_FAN; - case TriangleStrip: - return GL_TRIANGLE_STRIP; - default: - throw new UnsupportedOperationException("Unrecognized mesh mode: " + mode); - } - } - - public void updateVertexArray(Mesh mesh, VertexBuffer instanceData) { - int id = mesh.getId(); - if (id == -1) { - IntBuffer temp = intBuf1; - glGenVertexArrays(temp); - id = temp.get(0); - mesh.setId(id); - } - - if (context.boundVertexArray != id) { - glBindVertexArray(id); - context.boundVertexArray = id; - } - - VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); - if (interleavedData != null && interleavedData.isUpdateNeeded()) { - updateBufferData(interleavedData); - } - - if (instanceData != null) { - setVertexAttrib(instanceData, null); - } - - for (VertexBuffer vb : mesh.getBufferList().getArray()) { - if (vb.getBufferType() == Type.InterleavedData - || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers - || vb.getBufferType() == Type.Index) { - continue; - } - - if (vb.getStride() == 0) { - // not interleaved - setVertexAttrib(vb); - } else { - // interleaved - setVertexAttrib(vb, interleavedData); - } - } - } - - private void renderMeshVertexArray(Mesh mesh, int lod, int count, VertexBuffer instanceData) { - if (mesh.getId() == -1) { - updateVertexArray(mesh, instanceData); - } else { - // TODO: Check if it was updated - } - - if (context.boundVertexArray != mesh.getId()) { - glBindVertexArray(mesh.getId()); - context.boundVertexArray = mesh.getId(); - } - -// IntMap buffers = mesh.getBuffers(); - VertexBuffer indices; - if (mesh.getNumLodLevels() > 0) { - indices = mesh.getLodLevel(lod); - } else { - indices = mesh.getBuffer(Type.Index); - } - if (indices != null) { - drawTriangleList(indices, mesh, count); - } else { - drawTriangleArray(mesh.getMode(), count, mesh.getVertexCount()); - } - clearVertexAttribs(); - clearTextureUnits(); - } - - private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { - - // Here while count is still passed in. Can be removed when/if - // the method is collapsed again. -pspeed - count = Math.max(mesh.getInstanceCount(), count); - - VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); - if (interleavedData != null && interleavedData.isUpdateNeeded()) { - updateBufferData(interleavedData); - } - - VertexBuffer indices; - if (mesh.getNumLodLevels() > 0) { - indices = mesh.getLodLevel(lod); - } else { - indices = mesh.getBuffer(Type.Index); - } - - if (instanceData != null) { - for (VertexBuffer vb : instanceData) { - setVertexAttrib(vb, null); - } - } - - for (VertexBuffer vb : mesh.getBufferList().getArray()) { - if (vb.getBufferType() == Type.InterleavedData - || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers - || vb.getBufferType() == Type.Index) { - continue; - } - - if (vb.getStride() == 0) { - // not interleaved - setVertexAttrib(vb); - } else { - // interleaved - setVertexAttrib(vb, interleavedData); - } - } - - if (indices != null) { - drawTriangleList(indices, mesh, count); - } else { - drawTriangleArray(mesh.getMode(), count, mesh.getVertexCount()); - } - clearVertexAttribs(); - clearTextureUnits(); - } - - public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { - if (mesh.getVertexCount() == 0) { - return; - } - - if (context.pointSprite && mesh.getMode() != Mode.Points) { - // XXX: Hack, disable point sprite mode if mesh not in point mode - if (context.boundTextures[0] != null) { - if (context.boundTextureUnit != 0) { - glActiveTexture(GL_TEXTURE0); - context.boundTextureUnit = 0; - } - glDisable(GL_POINT_SPRITE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); - context.pointSprite = false; - } - } - - if (context.pointSize != mesh.getPointSize()) { - glPointSize(mesh.getPointSize()); - context.pointSize = mesh.getPointSize(); - } - if (context.lineWidth != mesh.getLineWidth()) { - glLineWidth(mesh.getLineWidth()); - context.lineWidth = mesh.getLineWidth(); - } - - statistics.onMeshDrawn(mesh, lod, count); -// if (ctxCaps.GL_ARB_vertex_array_object){ -// renderMeshVertexArray(mesh, lod, count); -// }else{ - renderMeshDefault(mesh, lod, count, instanceData); -// } - } - - public void setMainFrameBufferSrgb(boolean enableSrgb) { - // Gamma correction - - if (!caps.contains(Caps.Srgb)) { - // Not supported, sorry. - - logger.warning("sRGB framebuffer is not supported " + - "by video hardware, but was requested."); - - return; - } - - setFrameBuffer(null); - - if (enableSrgb) { - if (!glGetBoolean(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT)) { - logger.warning("Driver claims that default framebuffer " - + "is not sRGB capable. Enabling anyway."); - } - - - - glEnable(GL_FRAMEBUFFER_SRGB_EXT); - - logger.log(Level.FINER, "SRGB FrameBuffer enabled (Gamma Correction)"); - } else { - glDisable(GL_FRAMEBUFFER_SRGB_EXT); - } - } - - public void setLinearizeSrgbImages(boolean linearize) { - if (caps.contains(Caps.Srgb)) { - linearizeSrgbImages = linearize; - } - } -} diff --git a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java b/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java deleted file mode 100644 index 41dddd6ae..000000000 --- a/jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java +++ /dev/null @@ -1,514 +0,0 @@ -/* - * 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.lwjgl; - -import com.jme3.renderer.Caps; -import com.jme3.renderer.RendererException; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.image.ColorSpace; -import java.nio.ByteBuffer; -import java.util.EnumSet; -import java.util.logging.Level; -import java.util.logging.Logger; -import static org.lwjgl.opengl.ARBDepthBufferFloat.*; -import static org.lwjgl.opengl.ARBES3Compatibility.*; -import static org.lwjgl.opengl.ARBHalfFloatPixel.*; -import static org.lwjgl.opengl.ARBTextureFloat.*; -import static org.lwjgl.opengl.ARBTextureMultisample.*; -import static org.lwjgl.opengl.EXTPackedDepthStencil.*; -import static org.lwjgl.opengl.EXTPackedFloat.*; -import static org.lwjgl.opengl.EXTTextureArray.*; -import static org.lwjgl.opengl.EXTTextureCompressionS3TC.*; -import static org.lwjgl.opengl.EXTTextureSRGB.*; -import static org.lwjgl.opengl.EXTTextureSharedExponent.*; -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL12.*; -import static org.lwjgl.opengl.GL13.*; -import static org.lwjgl.opengl.GL14.*; - -/** - * - * Should not be used, has been replaced by Unified Rendering Architechture. - * @deprecated - */ -@Deprecated -class TextureUtil { - - 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, GL_ALPHA8, GL_ALPHA, GL_UNSIGNED_BYTE, false); - - // Luminance formats - setFormat(Format.Luminance8, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE, false); - setFormat(Format.Luminance16F, GL_LUMINANCE16F_ARB, GL_LUMINANCE, GL_HALF_FLOAT_ARB, false); - setFormat(Format.Luminance32F, GL_LUMINANCE32F_ARB, GL_LUMINANCE, GL_FLOAT, false); - - // Luminance alpha formats - setFormat(Format.Luminance8Alpha8, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, false); - setFormat(Format.Luminance16FAlpha16F, GL_LUMINANCE_ALPHA16F_ARB, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_ARB, false); - - // Depth formats - setFormat(Format.Depth, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, false); - setFormat(Format.Depth16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, false); - setFormat(Format.Depth24, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false); - setFormat(Format.Depth32, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false); - setFormat(Format.Depth32F, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, false); - - // Depth stencil formats - setFormat(Format.Depth24Stencil8, GL_DEPTH24_STENCIL8_EXT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, false); - - // RGB formats - setFormat(Format.BGR8, GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE, false); - setFormat(Format.ARGB8, GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, false); - setFormat(Format.BGRA8, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, false); - setFormat(Format.RGB8, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, false); - setFormat(Format.RGB16F, GL_RGB16F_ARB, GL_RGB, GL_HALF_FLOAT_ARB, false); - setFormat(Format.RGB32F, GL_RGB32F_ARB, GL_RGB, GL_FLOAT, false); - - // Special RGB formats - setFormat(Format.RGB111110F, GL_R11F_G11F_B10F_EXT, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV_EXT, false); - setFormat(Format.RGB9E5, GL_RGB9_E5_EXT, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV_EXT, false); - setFormat(Format.RGB16F_to_RGB111110F, GL_R11F_G11F_B10F_EXT, GL_RGB, GL_HALF_FLOAT_ARB, false); - setFormat(Format.RGB16F_to_RGB9E5, GL_RGB9_E5_EXT, GL_RGB, GL_HALF_FLOAT_ARB, false); - - // RGBA formats - setFormat(Format.ABGR8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false); - setFormat(Format.RGB5A1, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, false); - setFormat(Format.RGBA8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false); - setFormat(Format.RGBA16F, GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT_ARB, false); - setFormat(Format.RGBA32F, GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT, false); - - // DXT formats - setFormat(Format.DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE, true); - setFormat(Format.DXT1A, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); - setFormat(Format.DXT3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); - setFormat(Format.DXT5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); - - // ETC1 support on regular OpenGL requires ES3 compatibility extension. - // NOTE: ETC2 is backwards compatible with ETC1, so we can - // upload ETC1 textures as ETC2. - setFormat(Format.ETC1, GL_COMPRESSED_RGB8_ETC2, GL_RGB, GL_UNSIGNED_BYTE, true); - } - - //sRGB formats - private static final GLImageFormat sRGB_RGB8 = new GLImageFormat(GL_SRGB8_EXT, GL_RGB, GL_UNSIGNED_BYTE, false); - private static final GLImageFormat sRGB_RGBA8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_RGBA, GL_UNSIGNED_BYTE, false); - private static final GLImageFormat sRGB_Luminance8 = new GLImageFormat(GL_SLUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE, false); - private static final GLImageFormat sRGB_LuminanceAlpha8 = new GLImageFormat(GL_SLUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, false); - private static final GLImageFormat sRGB_BGR8 = new GLImageFormat(GL_SRGB8_EXT, GL_BGR, GL_UNSIGNED_BYTE, false); - private static final GLImageFormat sRGB_ABGR8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false); - private static final GLImageFormat sRGB_ARGB8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, false); - private static final GLImageFormat sRGB_BGRA8 = new GLImageFormat(GL_SRGB8_ALPHA8_EXT, GL_BGRA, GL_UNSIGNED_BYTE, false); - private static final GLImageFormat sRGB_DXT1 = new GLImageFormat(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,GL_RGB, GL_UNSIGNED_BYTE, true); - private static final GLImageFormat sRGB_DXT1A = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); - private static final GLImageFormat sRGB_DXT3 = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); - private static final GLImageFormat sRGB_DXT5 = new GLImageFormat(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true); - - public static GLImageFormat getImageFormat(EnumSet caps, Format fmt, boolean isSrgb){ - switch (fmt){ - case ETC1: - if (!caps.contains(Caps.TextureCompressionETC1)) { - return null; - } - break; - case DXT1: - case DXT1A: - case DXT3: - case DXT5: - if (!caps.contains(Caps.TextureCompressionS3TC)) { - return null; - } - break; - case Depth24Stencil8: - if (!caps.contains(Caps.PackedDepthStencilBuffer)){ - return null; - } - break; - case Luminance16F: - case Luminance16FAlpha16F: - case Luminance32F: - case RGB16F: - case RGB32F: - case RGBA16F: - case RGBA32F: - if (!caps.contains(Caps.FloatTexture)){ - return null; - } - break; - case Depth32F: - if (!caps.contains(Caps.FloatDepthBuffer)){ - return null; - } - break; - case RGB9E5: - case RGB16F_to_RGB9E5: - if (!caps.contains(Caps.SharedExponentTexture)){ - return null; - } - break; - case RGB111110F: - case RGB16F_to_RGB111110F: - if (!caps.contains(Caps.PackedFloatTexture)){ - return null; - } - break; - } - if (isSrgb) { - return getSrgbFormat(fmt); - } else { - return formatToGL[fmt.ordinal()]; - } - } - - public static GLImageFormat getImageFormatWithError(EnumSet caps, Format fmt, boolean isSrgb) { - GLImageFormat glFmt = getImageFormat(caps, fmt, isSrgb); - if (glFmt == null) { - throw new RendererException("Image format '" + fmt + "' is unsupported by the video hardware."); - } - return glFmt; - } - - private static GLImageFormat getSrgbFormat(Format fmt){ - switch (fmt) { - case RGB8: - return sRGB_RGB8; - case RGBA8: - return sRGB_RGBA8; - case BGR8: - return sRGB_BGR8; - case ABGR8: - return sRGB_ABGR8; - case ARGB8: - return sRGB_ARGB8; - case BGRA8: - return sRGB_BGRA8; - case Luminance8: - return sRGB_Luminance8; - case Luminance8Alpha8: - return sRGB_LuminanceAlpha8; - case DXT1: - return sRGB_DXT1; - case DXT1A: - return sRGB_DXT1A; - case DXT3: - return sRGB_DXT3; - case DXT5: - return sRGB_DXT5; - default: - Logger.getLogger(TextureUtil.class.getName()).log(Level.WARNING, "Format {0} has no sRGB equivalent, using linear format.", fmt.toString()); - return formatToGL[fmt.ordinal()]; - } - } - - public static void uploadTexture(EnumSet caps, - Image image, - int target, - int index, - int border, - boolean linearizeSrgb){ - - Image.Format fmt = image.getFormat(); - GLImageFormat glFmt = getImageFormatWithError(caps, fmt, image.getColorSpace() == ColorSpace.sRGB && linearizeSrgb); - - 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) { - glPixelStorei(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 == GL_TEXTURE_3D){ - glCompressedTexImage3D(target, - i, - glFmt.internalFormat, - mipWidth, - mipHeight, - mipDepth, - border, - data); - } else if (target == GL_TEXTURE_2D_ARRAY_EXT) { - // Upload compressed texture array slice - glCompressedTexSubImage3D(target, - i, - 0, - 0, - index, - mipWidth, - mipHeight, - 1, - glFmt.internalFormat, - data); - }else{ - //all other targets use 2D: array, cubemap, 2d - glCompressedTexImage2D(target, - i, - glFmt.internalFormat, - mipWidth, - mipHeight, - border, - data); - } - }else{ - if (target == GL_TEXTURE_3D){ - glTexImage3D(target, - i, - glFmt.internalFormat, - mipWidth, - mipHeight, - mipDepth, - border, - glFmt.format, - glFmt.dataType, - data); - }else if (target == GL_TEXTURE_2D_ARRAY_EXT){ - // prepare data for 2D array - // or upload slice - if (index == -1){ - glTexImage3D(target, - i, - glFmt.internalFormat, - mipWidth, - mipHeight, - image.getData().size(), //# of slices - border, - glFmt.format, - glFmt.dataType, - data); - }else{ - glTexSubImage3D(target, - i, // level - 0, // xoffset - 0, // yoffset - index, // zoffset - mipWidth, // width - mipHeight, // height - 1, // depth - glFmt.format, - glFmt.dataType, - data); - } - }else{ - if (subtex){ - if (samples > 1){ - throw new IllegalStateException("Cannot update multisample textures"); - } - - glTexSubImage2D(target, - i, - 0, 0, - mipWidth, mipHeight, - glFmt.format, - glFmt.dataType, - data); - }else{ - if (samples > 1){ - glTexImage2DMultisample(target, - samples, - glFmt.internalFormat, - mipWidth, - mipHeight, - true); - }else{ - glTexImage2D(target, - i, - glFmt.internalFormat, - mipWidth, - mipHeight, - border, - glFmt.format, - glFmt.dataType, - data); - } - } - } - } - - pos += mipSizes[i]; - } - } - - /** - * Update the texture currently bound to target at with data from the given Image at position x and y. The parameter - * index is used as the zoffset in case a 3d texture or texture 2d array is being updated. - * - * @param image Image with the source data (this data will be put into the texture) - * @param target the target texture - * @param index the mipmap level to update - * @param x the x position where to put the image in the texture - * @param y the y position where to put the image in the texture - */ - public static void uploadSubTexture( - EnumSet caps, - Image image, - int target, - int index, - int x, - int y, - boolean linearizeSrgb) { - Image.Format fmt = image.getFormat(); - GLImageFormat glFmt = getImageFormatWithError(caps, fmt, image.getColorSpace() == ColorSpace.sRGB && linearizeSrgb); - - ByteBuffer data = null; - if (index >= 0 && image.getData() != null && image.getData().size() > 0) { - data = image.getData(index); - } - - int width = image.getWidth(); - int height = image.getHeight(); - int depth = image.getDepth(); - - if (data != null) { - glPixelStorei(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 }; - } - } - - 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]); - } - - // to remove the cumbersome if/then/else stuff below we'll update the pos right here and use continue after each - // gl*Image call in an attempt to unclutter things a bit - pos += mipSizes[i]; - - int glFmtInternal = glFmt.internalFormat; - int glFmtFormat = glFmt.format; - int glFmtDataType = glFmt.dataType; - - if (glFmt.compressed && data != null){ - if (target == GL_TEXTURE_3D){ - glCompressedTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtInternal, data); - continue; - } - - // all other targets use 2D: array, cubemap, 2d - glCompressedTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtInternal, data); - continue; - } - - if (target == GL_TEXTURE_3D){ - glTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtFormat, glFmtDataType, data); - continue; - } - - if (target == GL_TEXTURE_2D_ARRAY_EXT){ - // prepare data for 2D array or upload slice - if (index == -1){ - glTexSubImage3D(target, i, x, y, index, mipWidth, mipHeight, mipDepth, glFmtFormat, glFmtDataType, data); - continue; - } - - glTexSubImage3D(target, i, x, y, index, width, height, 1, glFmtFormat, glFmtDataType, data); - continue; - } - - if (samples > 1){ - throw new IllegalStateException("Cannot update multisample textures"); - } - - glTexSubImage2D(target, i, x, y, mipWidth, mipHeight, glFmtFormat, glFmtDataType, data); - } - } -} diff --git a/jme3-networking/src/main/java/com/jme3/network/service/rpc/msg/RpcCallMessage.java b/jme3-networking/src/main/java/com/jme3/network/service/rpc/msg/RpcCallMessage.java index 70f12f1e0..11c5db591 100644 --- a/jme3-networking/src/main/java/com/jme3/network/service/rpc/msg/RpcCallMessage.java +++ b/jme3-networking/src/main/java/com/jme3/network/service/rpc/msg/RpcCallMessage.java @@ -92,7 +92,7 @@ public class RpcCallMessage extends AbstractMessage { + (isAsync() ? ", async" : ", sync") + ", objId=" + objId + ", procId=" + procId - + ", args.length=" + args.length + + ", args.length=" + (args == null ? 0 : args.length) + "]"; } } diff --git a/local.properties b/local.properties new file mode 100644 index 000000000..27e823fff --- /dev/null +++ b/local.properties @@ -0,0 +1 @@ +sdk.dir=C:\\AndroidSDK \ No newline at end of file diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java index 50b6d5cfe..00d15bb2f 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java @@ -11,6 +11,7 @@ import com.jme3.gde.core.scene.controller.SceneToolController; import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; import com.jme3.gde.scenecomposer.tools.PickManager; +import com.jme3.gde.scenecomposer.tools.shortcuts.ShortcutManager; import com.jme3.input.event.KeyInputEvent; import com.jme3.light.Light; import com.jme3.light.PointLight; @@ -31,6 +32,7 @@ import com.jme3.scene.control.Control; import com.jme3.scene.shape.Quad; import com.jme3.texture.Texture; import java.util.concurrent.Callable; +import org.openide.util.Lookup; /** * @@ -184,7 +186,12 @@ public class SceneComposerToolController extends SceneToolController { * @param camera */ public void doEditToolActivatedPrimary(Vector2f mouseLoc, boolean pressed, Camera camera) { - if (editTool != null) { + ShortcutManager scm = Lookup.getDefault().lookup(ShortcutManager.class); + + if (scm.isActive()) { + scm.getActiveShortcut().setCamera(camera); + scm.getActiveShortcut().actionPrimary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } else if (editTool != null) { editTool.setCamera(camera); editTool.actionPrimary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); } @@ -198,36 +205,66 @@ public class SceneComposerToolController extends SceneToolController { * @param camera */ public void doEditToolActivatedSecondary(Vector2f mouseLoc, boolean pressed, Camera camera) { - if (editTool != null) { + ShortcutManager scm = Lookup.getDefault().lookup(ShortcutManager.class); + + if (scm.isActive()) { + scm.getActiveShortcut().setCamera(camera); + scm.getActiveShortcut().actionSecondary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } else if (editTool != null) { editTool.setCamera(camera); editTool.actionSecondary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); } } public void doEditToolMoved(Vector2f mouseLoc, Camera camera) { - if (editTool != null) { + ShortcutManager scm = Lookup.getDefault().lookup(ShortcutManager.class); + + if (scm.isActive()) { + scm.getActiveShortcut().setCamera(camera); + scm.getActiveShortcut().mouseMoved(mouseLoc, rootNode, editorController.getCurrentDataObject(), selectedSpatial); + } else if (editTool != null) { editTool.setCamera(camera); editTool.mouseMoved(mouseLoc, rootNode, editorController.getCurrentDataObject(), selectedSpatial); } } public void doEditToolDraggedPrimary(Vector2f mouseLoc, boolean pressed, Camera camera) { - if (editTool != null) { + ShortcutManager scm = Lookup.getDefault().lookup(ShortcutManager.class); + + if (scm.isActive()) { + scm.getActiveShortcut().setCamera(camera); + scm.getActiveShortcut().draggedPrimary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } else if (editTool != null) { editTool.setCamera(camera); editTool.draggedPrimary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); } } public void doEditToolDraggedSecondary(Vector2f mouseLoc, boolean pressed, Camera camera) { - if (editTool != null) { + ShortcutManager scm = Lookup.getDefault().lookup(ShortcutManager.class); + + if (scm.isActive()) { + scm.getActiveShortcut().setCamera(null); + scm.getActiveShortcut().draggedSecondary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } else if (editTool != null) { editTool.setCamera(camera); editTool.draggedSecondary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); } } - void doKeyPressed(KeyInputEvent kie) { - if (editTool != null) { - editTool.keyPressed(kie); + public void doKeyPressed(KeyInputEvent kie) { + ShortcutManager scm = Lookup.getDefault().lookup(ShortcutManager.class); + + if (scm.isActive()) { + scm.doKeyPressed(kie); + } else { + if (scm.activateShortcut(kie)) { + scm.getActiveShortcut().activate(manager, toolsNode, onTopToolsNode, selected, this); + } else { + if (editTool != null) { + editTool.keyPressed(kie); + } + } } } diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/MoveManager.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/MoveManager.java deleted file mode 100644 index d7b92db91..000000000 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/MoveManager.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package com.jme3.gde.scenecomposer.tools; - -import com.jme3.bullet.control.CharacterControl; -import com.jme3.bullet.control.RigidBodyControl; -import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; -import com.jme3.gde.scenecomposer.SceneEditTool; -import com.jme3.math.FastMath; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; -import com.jme3.renderer.Camera; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.jme3.scene.shape.Quad; -import org.openide.util.lookup.ServiceProvider; - -/** - * - * @author Nehon - */ -@ServiceProvider(service = MoveManager.class) -public class MoveManager { - - private Vector3f startLoc; - private Vector3f startWorldLoc; - private Vector3f lastLoc; - private Vector3f offset; - private Node alternativePickTarget = null; - private Node plane; - private Spatial spatial; - protected static final Quaternion XY = new Quaternion().fromAngleAxis(0, new Vector3f(1, 0, 0)); - protected static final Quaternion YZ = new Quaternion().fromAngleAxis(-FastMath.PI / 2, new Vector3f(0, 1, 0)); - protected static final Quaternion XZ = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0)); - //temp vars - private Quaternion rot = new Quaternion(); - private Vector3f newPos = new Vector3f(); - - public MoveManager() { - float size = 1000; - Geometry g = new Geometry("plane", new Quad(size, size)); - g.setLocalTranslation(-size / 2, -size / 2, 0); - plane = new Node(); - plane.attachChild(g); - } - - public Vector3f getOffset() { - return offset; - } - - public void reset() { - offset = null; - startLoc = null; - startWorldLoc = null; - lastLoc = null; - spatial = null; - alternativePickTarget = null; - } - - public void initiateMove(Spatial selectedSpatial, Quaternion planeRotation, boolean local) { - spatial = selectedSpatial; - startLoc = selectedSpatial.getLocalTranslation().clone(); - startWorldLoc = selectedSpatial.getWorldTranslation().clone(); - if (local) { - rot.set(selectedSpatial.getWorldRotation()); - plane.setLocalRotation(rot.multLocal(planeRotation)); - } else { - rot.set(planeRotation); - } - - plane.setLocalRotation(rot); - plane.setLocalTranslation(startWorldLoc); - - } - - public void updatePlaneRotation(Quaternion planeRotation) { - plane.setLocalRotation(rot); - } - - public boolean move(Camera camera, Vector2f screenCoord) { - return move(camera, screenCoord, Vector3f.UNIT_XYZ, false); - } - - public boolean move(Camera camera, Vector2f screenCoord, Vector3f constraintAxis, boolean gridSnap) { - Node toPick = alternativePickTarget == null ? plane : alternativePickTarget; - - Vector3f planeHit = SceneEditTool.pickWorldLocation(camera, screenCoord, toPick, alternativePickTarget == null ? null : spatial); - if (planeHit == null) { - return false; - } - - Spatial parent = spatial.getParent(); - //we are moving the root node, there is a slight chance that something went wrong. - if (parent == null) { - return false; - } - - //offset in world space - if (offset == null) { - offset = planeHit.subtract(spatial.getWorldTranslation()); // get the offset when we start so it doesn't jump - } - - newPos.set(planeHit).subtractLocal(offset); - - //constraining the translation with the contraintAxis. - Vector3f tmp = startWorldLoc.mult(Vector3f.UNIT_XYZ.subtract(constraintAxis)); - newPos.multLocal(constraintAxis).addLocal(tmp); - worldToLocalMove(gridSnap); - return true; - } - - private void worldToLocalMove(boolean gridSnap) { - //snap to grid (grid is assumed 1 WU per cell) - if (gridSnap) { - newPos.set(Math.round(newPos.x), Math.round(newPos.y), Math.round(newPos.z)); - } - - //computing the inverse world transform to get the new localtranslation - newPos.subtractLocal(spatial.getParent().getWorldTranslation()); - newPos = spatial.getParent().getWorldRotation().inverse().normalizeLocal().multLocal(newPos); - newPos.divideLocal(spatial.getParent().getWorldScale()); - - lastLoc = newPos; - spatial.setLocalTranslation(newPos); - - RigidBodyControl control = spatial.getControl(RigidBodyControl.class); - if (control != null) { - control.setPhysicsLocation(spatial.getWorldTranslation()); - } - CharacterControl character = spatial.getControl(CharacterControl.class); - if (character != null) { - character.setPhysicsLocation(spatial.getWorldTranslation()); - } - } - - public boolean moveAcross(Vector3f constraintAxis, float value, boolean gridSnap) { - newPos.set(startWorldLoc).addLocal(constraintAxis.mult(value)); - Spatial parent = spatial.getParent(); - //we are moving the root node, there is a slight chance that something went wrong. - if (parent == null) { - return false; - } - worldToLocalMove(gridSnap); - return true; - } - - public MoveUndo makeUndo() { - return new MoveUndo(spatial, startLoc, lastLoc); - } - - public void setAlternativePickTarget(Node alternativePickTarget) { - this.alternativePickTarget = alternativePickTarget; - } - - protected class MoveUndo extends AbstractUndoableSceneEdit { - - private Spatial spatial; - private Vector3f before = new Vector3f(), after = new Vector3f(); - - MoveUndo(Spatial spatial, Vector3f before, Vector3f after) { - this.spatial = spatial; - this.before.set(before); - if (after != null) { - this.after.set(after); - } - } - - @Override - public void sceneUndo() { - spatial.setLocalTranslation(before); - RigidBodyControl control = spatial.getControl(RigidBodyControl.class); - if (control != null) { - control.setPhysicsLocation(spatial.getWorldTranslation()); - } - CharacterControl character = spatial.getControl(CharacterControl.class); - if (character != null) { - character.setPhysicsLocation(spatial.getWorldTranslation()); - } - // toolController.selectedSpatialTransformed(); - } - - @Override - public void sceneRedo() { - spatial.setLocalTranslation(after); - RigidBodyControl control = spatial.getControl(RigidBodyControl.class); - if (control != null) { - control.setPhysicsLocation(spatial.getWorldTranslation()); - } - CharacterControl character = spatial.getControl(CharacterControl.class); - if (character != null) { - character.setPhysicsLocation(spatial.getWorldTranslation()); - } - //toolController.selectedSpatialTransformed(); - } - - public void setAfter(Vector3f after) { - this.after.set(after); - } - } -} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/PickManager.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/PickManager.java index 22fa8478a..af4f11fe5 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/PickManager.java +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/PickManager.java @@ -33,9 +33,9 @@ public class PickManager { private Spatial spatial; private SceneComposerToolController.TransformationType transformationType; - protected static final Quaternion PLANE_XY = new Quaternion().fromAngleAxis(0, new Vector3f(1, 0, 0)); - protected static final Quaternion PLANE_YZ = new Quaternion().fromAngleAxis(-FastMath.PI / 2, new Vector3f(0, 1, 0));//YAW090 - protected static final Quaternion PLANE_XZ = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0)); //PITCH090 + public static final Quaternion PLANE_XY = new Quaternion().fromAngleAxis(0, new Vector3f(1, 0, 0)); + public static final Quaternion PLANE_YZ = new Quaternion().fromAngleAxis(-FastMath.PI / 2, new Vector3f(0, 1, 0));//YAW090 + public static final Quaternion PLANE_XZ = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0)); //PITCH090 public PickManager() { @@ -75,7 +75,7 @@ public class PickManager { origineRotation = new Quaternion(Quaternion.IDENTITY); } else if (transformationType == SceneComposerToolController.TransformationType.camera) { rot.set(camera.getRotation()); - origineRotation = camera.getRotation().clone(); + origineRotation = camera.getRotation(); } plane.setLocalRotation(rot); } @@ -87,10 +87,6 @@ public class PickManager { * @return true if the the new picked location is set, else return false. */ public boolean updatePick(Camera camera, Vector2f screenCoord) { - if(transformationType == SceneComposerToolController.TransformationType.camera){ - origineRotation = camera.getRotation(); - plane.setLocalRotation(camera.getRotation()); - } finalPickLoc = SceneEditTool.pickWorldLocation(camera, screenCoord, plane, null); return finalPickLoc != null; } diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/RotateTool.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/RotateTool.java index 21e9a56d8..e5a125771 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/RotateTool.java +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/RotateTool.java @@ -25,7 +25,6 @@ import org.openide.util.Lookup; public class RotateTool extends SceneEditTool { private Vector3f pickedMarker; - private Vector2f lastScreenCoord; private Quaternion startRotate; private Quaternion lastRotate; private boolean wasDragging = false; @@ -48,9 +47,8 @@ public class RotateTool extends SceneEditTool { if (!pressed) { setDefaultAxisMarkerColors(); pickedMarker = null; // mouse released, reset selection - lastScreenCoord = null; if (wasDragging) { - actionPerformed(new ScaleUndo(toolController.getSelectedSpatial(), startRotate, lastRotate)); + actionPerformed(new RotateUndo(toolController.getSelectedSpatial(), startRotate, lastRotate)); wasDragging = false; } pickManager.reset(); @@ -100,10 +98,9 @@ public class RotateTool extends SceneEditTool { if (!pressed) { setDefaultAxisMarkerColors(); pickedMarker = null; // mouse released, reset selection - lastScreenCoord = null; if (wasDragging) { - actionPerformed(new ScaleUndo(toolController.getSelectedSpatial(), startRotate, lastRotate)); + actionPerformed(new RotateUndo(toolController.getSelectedSpatial(), startRotate, lastRotate)); wasDragging = false; } pickManager.reset(); @@ -138,12 +135,12 @@ public class RotateTool extends SceneEditTool { } } - private class ScaleUndo extends AbstractUndoableSceneEdit { + private class RotateUndo extends AbstractUndoableSceneEdit { private Spatial spatial; private Quaternion before, after; - ScaleUndo(Spatial spatial, Quaternion before, Quaternion after) { + RotateUndo(Spatial spatial, Quaternion before, Quaternion after) { this.spatial = spatial; this.before = before; this.after = after; diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java index 43d3cba3a..87f3c283f 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java @@ -8,425 +8,51 @@ import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent; import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; -import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; import com.jme3.gde.scenecomposer.SceneEditTool; -import com.jme3.input.KeyInput; -import com.jme3.input.event.KeyInputEvent; -import com.jme3.math.FastMath; -import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.terrain.Terrain; import org.openide.loaders.DataObject; -import org.openide.util.Lookup; /** - * This duplicates the Blender manipulate tool. - * It supports quick access to Grab, Rotate, and Scale operations - * by typing one of the following keys: 'g', 'r', or 's' - * Those keys can be followed by an axis key to specify what axis - * to perform the transformation: x, y, z - * Then, after the operation and axis are selected, you can type in a - * number and then hit 'enter' to complete the transformation. - * - * Ctrl+Shift+D will duplicate an object - * X will delete an object - * - * ITEMS TO FINISH: - * 1) fixed scale and rotation values by holding Ctrl and dragging mouse - * BUGS: - * 1) window always needs focus from primary click when it should focus from secondary and middle mouse - * + * This duplicates the Blender manipulate tool. It supports quick access to + * Grab, Rotate, and Scale operations by typing one of the following keys: 'g', + * 'r', or 's' Those keys can be followed by an axis key to specify what axis to + * perform the transformation: x, y, z Then, after the operation and axis are + * selected, you can type in a number and then hit 'enter' to complete the + * transformation. + * + * Ctrl+Shift+D will duplicate an object X will delete an object + * + * ITEMS TO FINISH: 1) fixed scale and rotation values by holding Ctrl and + * dragging mouse BUGS: 1) window always needs focus from primary click when it + * should focus from secondary and middle mouse + * * @author Brent Owens */ public class SelectTool extends SceneEditTool { - private enum State { - - translate, rotate, scale - }; - private State currentState = null; - private Vector3f currentAxis = Vector3f.UNIT_XYZ; - private StringBuilder numberBuilder = new StringBuilder(); // gets appended with numbers - private Quaternion startRot; - private Vector3f startTrans; - private Vector3f startScale; - private boolean wasDraggingL = false; private boolean wasDraggingR = false; private boolean wasDownR = false; - private boolean ctrlDown = false; - private boolean shiftDown = false; - private boolean altDown = false; - private MoveManager.MoveUndo moving; - private ScaleUndo scaling; - private RotateUndo rotating; - private Vector2f startMouseCoord; // for scaling and rotation - private Vector2f startSelectedCoord; // for scaling and rotation - private float lastRotAngle; // used for rotation /** - * This is stateful: - * First it checks for a command (rotate, translate, delete, etc..) - * Then it checks for an axis (x,y,z) - * Then it checks for a number (user typed a number - * Then, finally, it checks if Enter was hit. - * + * This is stateful: First it checks for a command (rotate, translate, + * delete, etc..) Then it checks for an axis (x,y,z) Then it checks for a + * number (user typed a number Then, finally, it checks if Enter was hit. + * * If either of the commands was actioned, the preceeding states/axis/amount - * will be reset. For example if the user types: G Y 2 R - * Then it will: - * 1) Set state as 'Translate' for the G (grab) - * 2) Set the axis as 'Y'; it will translate along the Y axis - * 3) Distance will be 2, when the 2 key is hit - * 4) Distance, Axis, and state are then reset because a new state was set: Rotate - * it won't actually translate because 'Enter' was not hit and 'R' reset the state. - * + * will be reset. For example if the user types: G Y 2 R Then it will: 1) + * Set state as 'Translate' for the G (grab) 2) Set the axis as 'Y'; it will + * translate along the Y axis 3) Distance will be 2, when the 2 key is hit + * 4) Distance, Axis, and state are then reset because a new state was set: + * Rotate it won't actually translate because 'Enter' was not hit and 'R' + * reset the state. + * */ - @Override - public void keyPressed(KeyInputEvent kie) { - - checkModificatorKeys(kie); // alt,shift,ctrl - Spatial selected = toolController.getSelectedSpatial(); - - if (selected == null) { - return; // only do anything if a spatial is selected - } - // key released - if (kie.isPressed()) { - boolean commandUsed = checkCommandKey(kie); - boolean stateChange = checkStateKey(kie); - boolean axisChange = checkAxisKey(kie); - boolean numberChange = checkNumberKey(kie); - boolean enterHit = checkEnterHit(kie); - boolean escHit = checkEscHit(kie); - - if (commandUsed) { - return; // commands take priority - } - if (stateChange) { - currentAxis = Vector3f.UNIT_XYZ; - numberBuilder = new StringBuilder(); - recordInitialState(selected); - } else if (axisChange) { - } else if (numberChange) { - } else if (enterHit) { - if (currentState != null && numberBuilder.length() > 0) { - applyKeyedChangeState(selected); - clearState(false); - } - } - - - // ----------------------- - // reset conditions below: - - if (escHit) { - if (moving != null) { - moving.sceneUndo(); - } - - moving = null; - clearState(); - } - - if (!stateChange && !axisChange && !numberChange && !enterHit && !escHit) { - // nothing valid was hit, reset the state - //clearState(); // this will be - } - } - } - - /** - * Abort any manipulations - */ - private void clearState() { - clearState(true); - } - - private void clearState(boolean resetSelected) { - Spatial selected = toolController.getSelectedSpatial(); - if (resetSelected && selected != null) { - // reset the transforms - if (startRot != null) { - selected.setLocalRotation(startRot); - } - if (startTrans != null) { - selected.setLocalTranslation(startTrans); - } - if (startScale != null) { - selected.setLocalScale(startScale); - } - } - currentState = null; - currentAxis = Vector3f.UNIT_XYZ; - numberBuilder = new StringBuilder(); - startRot = null; - startTrans = null; - startScale = null; - startMouseCoord = null; - startSelectedCoord = null; - lastRotAngle = 0; - } - - private void recordInitialState(Spatial selected) { - startRot = selected.getLocalRotation().clone(); - startTrans = selected.getLocalTranslation().clone(); - startScale = selected.getLocalScale().clone(); - } - - /** - * Applies the changes entered by a number, not by mouse. - * Translate: adds the value to the current local translation - * Rotate: rotates by X degrees - * Scale: scale the current scale by X amount - */ - private void applyKeyedChangeState(Spatial selected) { - Float value = null; - try { - value = new Float(numberBuilder.toString()); - } catch (NumberFormatException e) { - return; - } - - if (currentState == State.translate) { - MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class); - moveManager.moveAcross(currentAxis, value, toolController.isSnapToGrid()); - moving.setAfter(selected.getLocalTranslation()); - actionPerformed(moving); - moving = null; - } else if (currentState == State.scale) { - float x = 1, y = 1, z = 1; - if (currentAxis == Vector3f.UNIT_X) { - x = value; - } else if (currentAxis == Vector3f.UNIT_Y) { - y = value; - } else if (currentAxis == Vector3f.UNIT_Z) { - z = value; - } else if (currentAxis == Vector3f.UNIT_XYZ) { - x = value; - y = value; - z = value; - } - Vector3f before = selected.getLocalScale().clone(); - Vector3f after = selected.getLocalScale().multLocal(x, y, z); - selected.setLocalScale(after); - actionPerformed(new ScaleUndo(selected, before, after)); - } else if (currentState == State.rotate) { - float x = 0, y = 0, z = 0; - if (currentAxis == Vector3f.UNIT_X) { - x = 1; - } else if (currentAxis == Vector3f.UNIT_Y) { - y = 1; - } else if (currentAxis == Vector3f.UNIT_Z) { - z = 1; - } - Vector3f axis = new Vector3f(x, y, z); - Quaternion initialRot = selected.getLocalRotation().clone(); - Quaternion rot = new Quaternion(); - rot = rot.fromAngleAxis(value * FastMath.DEG_TO_RAD, axis); - selected.setLocalRotation(selected.getLocalRotation().mult(rot)); - RotateUndo undo = new RotateUndo(selected, initialRot, rot); - actionPerformed(undo); - toolController.updateSelection(null);// force a re-draw of the bbox shape - toolController.updateSelection(selected); - - } - clearState(false); - } - - private void checkModificatorKeys(KeyInputEvent kie) { - if (kie.getKeyCode() == KeyInput.KEY_LCONTROL || kie.getKeyCode() == KeyInput.KEY_RCONTROL) { - ctrlDown = kie.isPressed(); - } - - if (kie.getKeyCode() == KeyInput.KEY_LSHIFT || kie.getKeyCode() == KeyInput.KEY_RSHIFT) { - shiftDown = kie.isPressed(); - } - - if (kie.getKeyCode() == KeyInput.KEY_LMENU || kie.getKeyCode() == KeyInput.KEY_RMENU) { - altDown = kie.isPressed(); - } - } - - private boolean checkCommandKey(KeyInputEvent kie) { - if (kie.getKeyCode() == KeyInput.KEY_D) { - if (shiftDown) { - duplicateSelected(); - return true; - } - } - // X will only delete if the user isn't already transforming - if (currentState == null && kie.getKeyCode() == KeyInput.KEY_X) { - if (!ctrlDown && !shiftDown) { - deleteSelected(); - return true; - } - } - return false; - } - - private boolean checkStateKey(KeyInputEvent kie) { - Spatial selected = toolController.getSelectedSpatial(); - if (kie.getKeyCode() == KeyInput.KEY_G && !ctrlDown) { - currentState = State.translate; - MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class); - moveManager.reset(); - Quaternion rot = camera.getRotation().mult(new Quaternion().fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y)); - moveManager.initiateMove(selected, rot, false); - moving = moveManager.makeUndo(); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_R && !ctrlDown) { - currentState = State.rotate; - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_S && !ctrlDown) { - currentState = State.scale; - return true; - } - return false; - } - - private boolean checkAxisKey(KeyInputEvent kie) { - if (kie.getKeyCode() == KeyInput.KEY_X) { - currentAxis = Vector3f.UNIT_X; - checkMovePlane(MoveManager.XY, MoveManager.XZ); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_Y) { - currentAxis = Vector3f.UNIT_Y; - checkMovePlane(MoveManager.XY, MoveManager.YZ); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_Z) { - currentAxis = Vector3f.UNIT_Z; - checkMovePlane(MoveManager.XZ, MoveManager.YZ); - return true; - } - return false; - } - - private void checkMovePlane(Quaternion rot1, Quaternion rot2) { - if (currentState == State.translate) { - MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class); - Quaternion rot = camera.getRotation().mult(new Quaternion().fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y)); - Quaternion planRot = null; - if (rot.dot(rot1) < rot.dot(rot2)) { - planRot = rot1; - } else { - planRot = rot2; - } - moveManager.updatePlaneRotation(planRot); - } - } - - private boolean checkNumberKey(KeyInputEvent kie) { - if (kie.getKeyCode() == KeyInput.KEY_MINUS) { - if (numberBuilder.length() > 0) { - if (numberBuilder.charAt(0) == '-') { - numberBuilder.replace(0, 1, ""); - } else { - numberBuilder.insert(0, '-'); - } - } else { - numberBuilder.append('-'); - } - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_0 || kie.getKeyCode() == KeyInput.KEY_NUMPAD0) { - numberBuilder.append('0'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_1 || kie.getKeyCode() == KeyInput.KEY_NUMPAD1) { - numberBuilder.append('1'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_2 || kie.getKeyCode() == KeyInput.KEY_NUMPAD2) { - numberBuilder.append('2'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_3 || kie.getKeyCode() == KeyInput.KEY_NUMPAD3) { - numberBuilder.append('3'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_4 || kie.getKeyCode() == KeyInput.KEY_NUMPAD4) { - numberBuilder.append('4'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_5 || kie.getKeyCode() == KeyInput.KEY_NUMPAD5) { - numberBuilder.append('5'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_6 || kie.getKeyCode() == KeyInput.KEY_NUMPAD6) { - numberBuilder.append('6'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_7 || kie.getKeyCode() == KeyInput.KEY_NUMPAD7) { - numberBuilder.append('7'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_8 || kie.getKeyCode() == KeyInput.KEY_NUMPAD8) { - numberBuilder.append('8'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_9 || kie.getKeyCode() == KeyInput.KEY_NUMPAD9) { - numberBuilder.append('9'); - return true; - } else if (kie.getKeyCode() == KeyInput.KEY_PERIOD) { - if (numberBuilder.indexOf(".") == -1) { // if it doesn't exist yet - if (numberBuilder.length() == 0 - || (numberBuilder.length() == 1 && numberBuilder.charAt(0) == '-')) { - numberBuilder.append("0."); - } else { - numberBuilder.append("."); - } - } - return true; - } - - return false; - } - - private boolean checkEnterHit(KeyInputEvent kie) { - if (kie.getKeyCode() == KeyInput.KEY_RETURN) { - return true; - } - return false; - } - - private boolean checkEscHit(KeyInputEvent kie) { - if (kie.getKeyCode() == KeyInput.KEY_ESCAPE) { - return true; - } - return false; - } - @Override public void actionPrimary(Vector2f screenCoord, boolean pressed, final JmeNode rootNode, DataObject dataObject) { - if (!pressed) { - Spatial selected = toolController.getSelectedSpatial(); - // left mouse released - if (!wasDraggingL) { - // left mouse pressed - if (currentState != null) { - // finish manipulating the spatial - if (moving != null) { - moving.setAfter(selected.getLocalTranslation()); - actionPerformed(moving); - moving = null; - clearState(false); - } else if (scaling != null) { - scaling.after = selected.getLocalScale().clone(); - actionPerformed(scaling); - scaling = null; - clearState(false); - toolController.rebuildSelectionBox(); - } else if (rotating != null) { - rotating.after = selected.getLocalRotation().clone(); - actionPerformed(rotating); - rotating = null; - clearState(false); - } - } else { - // mouse released and wasn't dragging, place cursor - final Vector3f result = pickWorldLocation(getCamera(), screenCoord, rootNode); - if (result != null) { - if (toolController.isSnapToGrid()) { - result.set(Math.round(result.x), result.y, Math.round(result.z)); - } - toolController.setCursorLocation(result); - } - } - } - wasDraggingL = false; - } + } @Override @@ -435,19 +61,7 @@ public class SelectTool extends SceneEditTool { Spatial selected = toolController.getSelectedSpatial(); // mouse down - if (moving != null) { - moving.sceneUndo(); - moving = null; - clearState(); - } else if (scaling != null) { - scaling.sceneUndo(); - scaling = null; - clearState(); - } else if (rotating != null) { - rotating.sceneUndo(); - rotating = null; - clearState(); - } else if (!wasDraggingR && !wasDownR) { // wasn't dragging and was not down already + if (!wasDraggingR && !wasDownR) { // wasn't dragging and was not down already // pick on the spot Spatial s = pickWorldSpatial(camera, screenCoord, rootNode); if (!toolController.selectTerrain() && isTerrain(s)) { @@ -498,8 +112,8 @@ public class SelectTool extends SceneEditTool { } /** - * Climb up the spatial until we find the first node parent. - * TODO: use userData to determine the actual model's parent. + * Climb up the spatial until we find the first node parent. TODO: use + * userData to determine the actual model's parent. */ private Spatial findModelNodeParent(Spatial child) { if (child == null) { @@ -519,14 +133,10 @@ public class SelectTool extends SceneEditTool { @Override public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject currentDataObject, JmeSpatial selectedSpatial) { - if (currentState != null) { - handleMouseManipulate(screenCoord, currentState, currentAxis, rootNode, currentDataObject, selectedSpatial); - } } @Override public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { - wasDraggingL = pressed; } @Override @@ -535,252 +145,8 @@ public class SelectTool extends SceneEditTool { } /** - * Manipulate the spatial - */ - private void handleMouseManipulate(Vector2f screenCoord, - State state, - Vector3f axis, - JmeNode rootNode, - DataObject currentDataObject, - JmeSpatial selectedSpatial) { - if (state == State.translate) { - doMouseTranslate(axis, screenCoord, rootNode, selectedSpatial); - } else if (state == State.scale) { - doMouseScale(axis, screenCoord, rootNode, selectedSpatial); - } else if (state == State.rotate) { - doMouseRotate(axis, screenCoord, rootNode, selectedSpatial); - } - - } - - private void doMouseTranslate(Vector3f axis, Vector2f screenCoord, JmeNode rootNode, JmeSpatial selectedSpatial) { - MoveManager moveManager = Lookup.getDefault().lookup(MoveManager.class); - if (toolController.isSnapToScene()) { - moveManager.setAlternativePickTarget(rootNode.getLookup().lookup(Node.class)); - } - // free form translation - moveManager.move(camera, screenCoord, axis, toolController.isSnapToGrid()); - } - - private void doMouseScale(Vector3f axis, Vector2f screenCoord, JmeNode rootNode, JmeSpatial selectedSpatial) { - Spatial selected = toolController.getSelectedSpatial(); - // scale based on the original mouse position and original model-to-screen position - // and compare that to the distance from the new mouse position and the original distance - if (startMouseCoord == null) { - startMouseCoord = screenCoord.clone(); - } - if (startSelectedCoord == null) { - Vector3f screen = getCamera().getScreenCoordinates(selected.getWorldTranslation()); - startSelectedCoord = new Vector2f(screen.x, screen.y); - } - - if (scaling == null) { - scaling = new ScaleUndo(selected, selected.getLocalScale().clone(), null); - } - - float origDist = startMouseCoord.distanceSquared(startSelectedCoord); - float newDist = screenCoord.distanceSquared(startSelectedCoord); - if (origDist == 0) { - origDist = 1; - } - float ratio = newDist / origDist; - Vector3f prev = selected.getLocalScale(); - if (axis == Vector3f.UNIT_X) { - selected.setLocalScale(ratio, prev.y, prev.z); - } else if (axis == Vector3f.UNIT_Y) { - selected.setLocalScale(prev.x, ratio, prev.z); - } else if (axis == Vector3f.UNIT_Z) { - selected.setLocalScale(prev.x, prev.y, ratio); - } else { - selected.setLocalScale(ratio, ratio, ratio); - } - } - - private void doMouseRotate(Vector3f axis, Vector2f screenCoord, JmeNode rootNode, JmeSpatial selectedSpatial) { - Spatial selected = toolController.getSelectedSpatial(); - if (startMouseCoord == null) { - startMouseCoord = screenCoord.clone(); - } - if (startSelectedCoord == null) { - Vector3f screen = getCamera().getScreenCoordinates(selected.getWorldTranslation()); - startSelectedCoord = new Vector2f(screen.x, screen.y); - } - - if (rotating == null) { - rotating = new RotateUndo(selected, selected.getLocalRotation().clone(), null); - } - - Vector2f origRot = startMouseCoord.subtract(startSelectedCoord); - Vector2f newRot = screenCoord.subtract(startSelectedCoord); - float newRotAngle = origRot.angleBetween(newRot); - float temp = newRotAngle; - - if (lastRotAngle != 0) { - newRotAngle -= lastRotAngle; - } - - lastRotAngle = temp; - - Quaternion rotate = new Quaternion(); - if (axis != Vector3f.UNIT_XYZ) { - rotate = rotate.fromAngleAxis(newRotAngle, selected.getWorldRotation().inverse().mult(axis)); - } else { - rotate = rotate.fromAngleAxis(newRotAngle, selected.getWorldRotation().inverse().mult(getCamera().getDirection().mult(-1).normalizeLocal())); - } - selected.setLocalRotation(selected.getLocalRotation().mult(rotate)); - - - } - - private void duplicateSelected() { - Spatial selected = toolController.getSelectedSpatial(); - if (selected == null) { - return; - } - Spatial clone = selected.clone(); - clone.move(1, 0, 1); - - selected.getParent().attachChild(clone); - actionPerformed(new DuplicateUndo(clone, selected.getParent())); - selected = clone; - final Spatial cloned = clone; - final JmeNode rootNode = toolController.getRootNode(); - refreshSelected(rootNode, selected.getParent()); - - java.awt.EventQueue.invokeLater(new Runnable() { - - @Override - public void run() { - if (cloned != null) { - SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{rootNode.getChild(cloned)}); - SceneExplorerTopComponent.findInstance().setSelectedNode(rootNode.getChild(cloned)); - } - } - }); - - // set to automatically 'grab'/'translate' the new cloned model - toolController.updateSelection(selected); - currentState = State.translate; - currentAxis = Vector3f.UNIT_XYZ; - } - - private void deleteSelected() { - Spatial selected = toolController.getSelectedSpatial(); - if (selected == null) { - return; - } - Node parent = selected.getParent(); - selected.removeFromParent(); - actionPerformed(new DeleteUndo(selected, parent)); - - selected = null; - toolController.updateSelection(selected); - - final JmeNode rootNode = toolController.getRootNode(); - refreshSelected(rootNode, parent); - } - - private void refreshSelected(final JmeNode jmeRootNode, final Node parent) { - java.awt.EventQueue.invokeLater(new Runnable() { - - @Override - public void run() { - jmeRootNode.getChild(parent).refresh(false); - } - }); - } - - private class ScaleUndo extends AbstractUndoableSceneEdit { - - private Spatial spatial; - private Vector3f before, after; - - ScaleUndo(Spatial spatial, Vector3f before, Vector3f after) { - this.spatial = spatial; - this.before = before; - this.after = after; - } - - @Override - public void sceneUndo() { - spatial.setLocalScale(before); - } - - @Override - public void sceneRedo() { - spatial.setLocalScale(after); - } - } - - private class RotateUndo extends AbstractUndoableSceneEdit { - - private Spatial spatial; - private Quaternion before, after; - - RotateUndo(Spatial spatial, Quaternion before, Quaternion after) { - this.spatial = spatial; - this.before = before; - this.after = after; - } - - @Override - public void sceneUndo() { - spatial.setLocalRotation(before); - } - - @Override - public void sceneRedo() { - spatial.setLocalRotation(after); - } - } - - private class DeleteUndo extends AbstractUndoableSceneEdit { - - private Spatial spatial; - private Node parent; - - DeleteUndo(Spatial spatial, Node parent) { - this.spatial = spatial; - this.parent = parent; - } - - @Override - public void sceneUndo() { - parent.attachChild(spatial); - } - - @Override - public void sceneRedo() { - spatial.removeFromParent(); - } - } - - private class DuplicateUndo extends AbstractUndoableSceneEdit { - - private Spatial spatial; - private Node parent; - - DuplicateUndo(Spatial spatial, Node parent) { - this.spatial = spatial; - this.parent = parent; - } - - @Override - public void sceneUndo() { - spatial.removeFromParent(); - } - - @Override - public void sceneRedo() { - parent.attachChild(spatial); - } - } - - /** - * Check if the selected item is a Terrain - * It will climb up the parent tree to see if - * a parent is terrain too. - * Recursive call. + * Check if the selected item is a Terrain It will climb up the parent tree + * to see if a parent is terrain too. Recursive call. */ protected boolean isTerrain(Spatial s) { if (s == null) { diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DeleteShortcut.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DeleteShortcut.java new file mode 100644 index 000000000..cc13ece1d --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DeleteShortcut.java @@ -0,0 +1,123 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer.tools.shortcuts; + +import com.jme3.asset.AssetManager; +import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent; +import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; +import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; +import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; +import com.jme3.gde.scenecomposer.SceneComposerToolController; +import com.jme3.input.KeyInput; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.math.Vector2f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import org.openide.loaders.DataObject; +import org.openide.util.Lookup; + +/** + * + * @author dokthar + */ +public class DeleteShortcut extends ShortcutTool { + + @Override + public boolean isActivableBy(KeyInputEvent kie) { + if (kie.getKeyCode() == KeyInput.KEY_X && kie.isPressed()) { + if (Lookup.getDefault().lookup(ShortcutManager.class).isShiftDown()) { + return true; + } + } + return false; + } + + @Override + public void cancel() { + terminate(); + } + + @Override + public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { + super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates. + hideMarker(); + if (selectedSpatial != null) { + delete(); + } + terminate(); + } + + private void delete() { + Spatial selected = toolController.getSelectedSpatial(); + + Node parent = selected.getParent(); + selected.removeFromParent(); + actionPerformed(new DeleteUndo(selected, parent)); + + selected = null; + toolController.updateSelection(selected); + + final JmeNode rootNode = toolController.getRootNode(); + refreshSelected(rootNode, parent); + } + + private void refreshSelected(final JmeNode jmeRootNode, final Node parent) { + java.awt.EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + jmeRootNode.getChild(parent).refresh(false); + } + }); + } + + @Override + public void keyPressed(KeyInputEvent kie) { + + } + + @Override + public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + } + + @Override + public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + } + + @Override + public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { + } + + @Override + public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + } + + @Override + public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + } + + private class DeleteUndo extends AbstractUndoableSceneEdit { + + private Spatial spatial; + private Node parent; + + DeleteUndo(Spatial spatial, Node parent) { + this.spatial = spatial; + this.parent = parent; + } + + @Override + public void sceneUndo() { + parent.attachChild(spatial); + } + + @Override + public void sceneRedo() { + spatial.removeFromParent(); + } + } +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java new file mode 100644 index 000000000..d98eb6ee9 --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java @@ -0,0 +1,141 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer.tools.shortcuts; + +import com.jme3.asset.AssetManager; +import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent; +import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; +import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; +import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; +import com.jme3.gde.scenecomposer.SceneComposerToolController; +import com.jme3.input.KeyInput; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.math.Vector2f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import org.openide.loaders.DataObject; +import org.openide.util.Lookup; + +/** + * + * @author dokthar + */ +public class DuplicateShortcut extends ShortcutTool { + + @Override + public boolean isActivableBy(KeyInputEvent kie) { + if (kie.getKeyCode() == KeyInput.KEY_D && kie.isPressed()) { + if (Lookup.getDefault().lookup(ShortcutManager.class).isShiftDown()) { + return true; + } + } + return false; + } + + @Override + public void cancel() { + terminate(); + } + + @Override + public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { + super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates. + hideMarker(); + if (selectedSpatial != null) { + duplicate(); + terminate(); + + //then enable move shortcut + toolController.doKeyPressed(new KeyInputEvent(KeyInput.KEY_G, 'g', true, false)); + } else { + terminate(); + } + } + + private void duplicate() { + Spatial selected = toolController.getSelectedSpatial(); + + Spatial clone = selected.clone(); + clone.move(1, 0, 1); + + selected.getParent().attachChild(clone); + actionPerformed(new DuplicateUndo(clone, selected.getParent())); + selected = clone; + final Spatial cloned = clone; + final JmeNode rootNode = toolController.getRootNode(); + refreshSelected(rootNode, selected.getParent()); + + java.awt.EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + if (cloned != null) { + SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{rootNode.getChild(cloned)}); + SceneExplorerTopComponent.findInstance().setSelectedNode(rootNode.getChild(cloned)); + } + } + }); + + toolController.updateSelection(selected); + } + + private void refreshSelected(final JmeNode jmeRootNode, final Node parent) { + java.awt.EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + jmeRootNode.getChild(parent).refresh(false); + } + }); + } + + @Override + public void keyPressed(KeyInputEvent kie) { + + } + + @Override + public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + } + + @Override + public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + } + + @Override + public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { + } + + @Override + public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + } + + @Override + public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + } + + private class DuplicateUndo extends AbstractUndoableSceneEdit { + + private Spatial spatial; + private Node parent; + + DuplicateUndo(Spatial spatial, Node parent) { + this.spatial = spatial; + this.parent = parent; + } + + @Override + public void sceneUndo() { + spatial.removeFromParent(); + } + + @Override + public void sceneRedo() { + parent.attachChild(spatial); + } + } +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/MoveShortcut.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/MoveShortcut.java new file mode 100644 index 000000000..6291ab932 --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/MoveShortcut.java @@ -0,0 +1,227 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer.tools.shortcuts; + +import com.jme3.asset.AssetManager; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; +import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; +import com.jme3.gde.scenecomposer.SceneComposerToolController; +import com.jme3.gde.scenecomposer.tools.PickManager; +import com.jme3.input.KeyInput; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import org.openide.loaders.DataObject; +import org.openide.util.Lookup; + +/** + * + * @author dokthar + */ +public class MoveShortcut extends ShortcutTool { + + private Vector3f currentAxis; + private StringBuilder numberBuilder; + private Spatial spatial; + private PickManager pickManager; + private boolean pickEnabled; + private Vector3f startPosition; + private Vector3f finalPosition; + + @Override + + public boolean isActivableBy(KeyInputEvent kie) { + return kie.getKeyCode() == KeyInput.KEY_G; + } + + @Override + public void cancel() { + spatial.setLocalTranslation(startPosition); + terminate(); + } + + private void apply() { + actionPerformed(new MoveUndo(toolController.getSelectedSpatial(), startPosition, finalPosition)); + terminate(); + } + + private void init(Spatial selectedSpatial) { + spatial = selectedSpatial; + startPosition = spatial.getLocalTranslation().clone(); + currentAxis = Vector3f.UNIT_XYZ; + pickManager = Lookup.getDefault().lookup(PickManager.class); + pickEnabled = false; + } + + @Override + public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { + super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates. + hideMarker(); + numberBuilder = new StringBuilder(); + if (selectedSpatial == null) { + terminate(); + } else { + init(selectedSpatial); + } + } + + @Override + public void keyPressed(KeyInputEvent kie) { + if (kie.isPressed()) { + Lookup.getDefault().lookup(ShortcutManager.class).activateShortcut(kie); + + Vector3f axis = new Vector3f(); + boolean axisChanged = ShortcutManager.checkAxisKey(kie, axis); + if (axisChanged) { + currentAxis = axis; + } + boolean numberChanged = ShortcutManager.checkNumberKey(kie, numberBuilder); + boolean enterHit = ShortcutManager.checkEnterHit(kie); + boolean escHit = ShortcutManager.checkEscHit(kie); + + if (escHit) { + cancel(); + } else if (enterHit) { + apply(); + } else if (axisChanged && pickEnabled) { + //update pick manager + + if (currentAxis.equals(Vector3f.UNIT_X)) { + pickManager.setTransformation(PickManager.PLANE_XY, getTransformType(), camera); + } else if (currentAxis.equals(Vector3f.UNIT_Y)) { + pickManager.setTransformation(PickManager.PLANE_YZ, getTransformType(), camera); + } else if (currentAxis.equals(Vector3f.UNIT_Z)) { + pickManager.setTransformation(PickManager.PLANE_XZ, getTransformType(), camera); + } + } else if (axisChanged || numberChanged) { + //update transformation + float number = ShortcutManager.getNumberKey(numberBuilder); + Vector3f translation = currentAxis.mult(number); + finalPosition = startPosition.add(translation); + spatial.setLocalTranslation(finalPosition); + + } + + } + } + + @Override + public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + if (pressed) { + apply(); + } + } + + @Override + public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + if (pressed) { + cancel(); + } + } + + @Override + public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { + + if (!pickEnabled) { + if (currentAxis.equals(Vector3f.UNIT_XYZ)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), camera.getRotation(), SceneComposerToolController.TransformationType.camera, camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_X)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XY, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_Y)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_YZ, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_Z)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XZ, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else { + return; + } + } + + if (pickManager.updatePick(camera, screenCoord)) { + //pick update success + Vector3f diff; + + if (currentAxis.equals(Vector3f.UNIT_XYZ)) { + diff = pickManager.getTranslation(); + } else { + diff = pickManager.getTranslation(currentAxis); + } + Vector3f position = startPosition.add(diff); + finalPosition = position; + toolController.getSelectedSpatial().setLocalTranslation(position); + updateToolsTransformation(); + } + } + + @Override + public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + if (pressed) { + apply(); + } + } + + @Override + public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + if (pressed) { + cancel(); + } + } + + private class MoveUndo extends AbstractUndoableSceneEdit { + + private Spatial spatial; + private Vector3f before = new Vector3f(), after = new Vector3f(); + + MoveUndo(Spatial spatial, Vector3f before, Vector3f after) { + this.spatial = spatial; + this.before.set(before); + if (after != null) { + this.after.set(after); + } + } + + @Override + public void sceneUndo() { + spatial.setLocalTranslation(before); + RigidBodyControl control = spatial.getControl(RigidBodyControl.class); + if (control != null) { + control.setPhysicsLocation(spatial.getWorldTranslation()); + } + CharacterControl character = spatial.getControl(CharacterControl.class); + if (character != null) { + character.setPhysicsLocation(spatial.getWorldTranslation()); + } + // toolController.selectedSpatialTransformed(); + } + + @Override + public void sceneRedo() { + spatial.setLocalTranslation(after); + RigidBodyControl control = spatial.getControl(RigidBodyControl.class); + if (control != null) { + control.setPhysicsLocation(spatial.getWorldTranslation()); + } + CharacterControl character = spatial.getControl(CharacterControl.class); + if (character != null) { + character.setPhysicsLocation(spatial.getWorldTranslation()); + } + //toolController.selectedSpatialTransformed(); + } + + public void setAfter(Vector3f after) { + this.after.set(after); + } + } + +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/RotateShortcut.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/RotateShortcut.java new file mode 100644 index 000000000..8b9ffe404 --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/RotateShortcut.java @@ -0,0 +1,189 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer.tools.shortcuts; + +import com.jme3.asset.AssetManager; +import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; +import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; +import com.jme3.gde.scenecomposer.SceneComposerToolController; +import com.jme3.gde.scenecomposer.tools.PickManager; +import com.jme3.input.KeyInput; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import org.openide.loaders.DataObject; +import org.openide.util.Lookup; + +/** + * + * @author dokthar + */ +public class RotateShortcut extends ShortcutTool { + + private Vector3f currentAxis; + private StringBuilder numberBuilder; + private Spatial spatial; + private PickManager pickManager; + private boolean pickEnabled; + private Quaternion startRotation; + private Quaternion finalRotation; + + @Override + + public boolean isActivableBy(KeyInputEvent kie) { + return kie.getKeyCode() == KeyInput.KEY_R; + } + + @Override + public void cancel() { + spatial.setLocalRotation(startRotation); + terminate(); + } + + private void apply() { + actionPerformed(new RotateUndo(toolController.getSelectedSpatial(), startRotation, finalRotation)); + terminate(); + } + + private void init(Spatial selectedSpatial) { + spatial = selectedSpatial; + startRotation = spatial.getLocalRotation().clone(); + currentAxis = Vector3f.UNIT_XYZ; + pickManager = Lookup.getDefault().lookup(PickManager.class); + pickEnabled = false; + } + + @Override + public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { + super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates. + hideMarker(); + numberBuilder = new StringBuilder(); + if (selectedSpatial == null) { + terminate(); + } else { + init(selectedSpatial); + } + } + + @Override + public void keyPressed(KeyInputEvent kie) { + if (kie.isPressed()) { + Lookup.getDefault().lookup(ShortcutManager.class).activateShortcut(kie); + + Vector3f axis = new Vector3f(); + boolean axisChanged = ShortcutManager.checkAxisKey(kie, axis); + if (axisChanged) { + currentAxis = axis; + } + boolean numberChanged = ShortcutManager.checkNumberKey(kie, numberBuilder); + boolean enterHit = ShortcutManager.checkEnterHit(kie); + boolean escHit = ShortcutManager.checkEscHit(kie); + + if (escHit) { + cancel(); + } else if (enterHit) { + apply(); + } else if (axisChanged && pickEnabled) { + pickEnabled = false; + spatial.setLocalRotation(startRotation.clone()); + } else if (axisChanged || numberChanged) { + //update transformation + /* float number = ShortcutManager.getNumberKey(numberBuilder); + Vector3f translation = currentAxis.mult(number); + finalPosition = startPosition.add(translation); + spatial.setLocalTranslation(finalPosition); + */ + } + + } + } + + @Override + public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + if (pressed) { + apply(); + } + } + + @Override + public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + if (pressed) { + cancel(); + } + } + + @Override + public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { + + if (!pickEnabled) { + if (currentAxis.equals(Vector3f.UNIT_XYZ)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), camera.getRotation(), SceneComposerToolController.TransformationType.camera, camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_X)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_YZ, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_Y)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XZ, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_Z)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XY, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else { + return; + } + } + + if (pickManager.updatePick(camera, screenCoord)) { + + Quaternion rotation = startRotation.mult(pickManager.getRotation(startRotation.inverse())); + toolController.getSelectedSpatial().setLocalRotation(rotation); + finalRotation = rotation; + updateToolsTransformation(); + } + } + + @Override + public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + if (pressed) { + apply(); + } + } + + @Override + public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + if (pressed) { + cancel(); + } + } + + private class RotateUndo extends AbstractUndoableSceneEdit { + + private Spatial spatial; + private Quaternion before, after; + + RotateUndo(Spatial spatial, Quaternion before, Quaternion after) { + this.spatial = spatial; + this.before = before; + this.after = after; + } + + @Override + public void sceneUndo() { + spatial.setLocalRotation(before); + toolController.selectedSpatialTransformed(); + } + + @Override + public void sceneRedo() { + spatial.setLocalRotation(after); + toolController.selectedSpatialTransformed(); + } + } +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ScaleShortcut.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ScaleShortcut.java new file mode 100644 index 000000000..8fa18858f --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ScaleShortcut.java @@ -0,0 +1,199 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer.tools.shortcuts; + +import com.jme3.asset.AssetManager; +import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; +import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; +import com.jme3.gde.scenecomposer.SceneComposerToolController; +import com.jme3.gde.scenecomposer.tools.PickManager; +import com.jme3.input.KeyInput; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import org.openide.loaders.DataObject; +import org.openide.util.Lookup; + +/** + * + * @author dokthar + */ +public class ScaleShortcut extends ShortcutTool { + + private Vector3f currentAxis; + private StringBuilder numberBuilder; + private Spatial spatial; + private PickManager pickManager; + private boolean pickEnabled; + private Vector3f startScale; + private Vector3f finalScale; + + @Override + + public boolean isActivableBy(KeyInputEvent kie) { + return kie.getKeyCode() == KeyInput.KEY_S; + } + + @Override + public void cancel() { + spatial.setLocalScale(startScale); + terminate(); + } + + private void apply() { + actionPerformed(new ScaleUndo(toolController.getSelectedSpatial(), startScale, finalScale)); + terminate(); + } + + private void init(Spatial selectedSpatial) { + spatial = selectedSpatial; + startScale = spatial.getLocalScale().clone(); + currentAxis = Vector3f.UNIT_XYZ; + pickManager = Lookup.getDefault().lookup(PickManager.class); + pickEnabled = false; + } + + @Override + public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { + super.activate(manager, toolNode, onTopToolNode, selectedSpatial, toolController); //To change body of generated methods, choose Tools | Templates. + hideMarker(); + numberBuilder = new StringBuilder(); + if (selectedSpatial == null) { + terminate(); + } else { + init(selectedSpatial); + } + } + + @Override + public void keyPressed(KeyInputEvent kie) { + if (kie.isPressed()) { + Lookup.getDefault().lookup(ShortcutManager.class).activateShortcut(kie); + + Vector3f axis = new Vector3f(); + boolean axisChanged = ShortcutManager.checkAxisKey(kie, axis); + if (axisChanged) { + currentAxis = axis; + } + boolean numberChanged = ShortcutManager.checkNumberKey(kie, numberBuilder); + boolean enterHit = ShortcutManager.checkEnterHit(kie); + boolean escHit = ShortcutManager.checkEscHit(kie); + + if (escHit) { + cancel(); + } else if (enterHit) { + apply(); + } else if (axisChanged && pickEnabled) { + pickEnabled = false; + } else if (axisChanged || numberChanged) { + //update transformation + /* float number = ShortcutManager.getNumberKey(numberBuilder); + Vector3f translation = currentAxis.mult(number); + finalPosition = startPosition.add(translation); + spatial.setLocalTranslation(finalPosition); + */ + } + + } + } + + @Override + public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + if (pressed) { + apply(); + } + } + + @Override + public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { + if (pressed) { + cancel(); + } + } + + @Override + public void mouseMoved(Vector2f screenCoord, JmeNode rootNode, DataObject dataObject, JmeSpatial selectedSpatial) { + + if (!pickEnabled) { + if (currentAxis.equals(Vector3f.UNIT_XYZ)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), camera.getRotation(), SceneComposerToolController.TransformationType.camera, camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_X)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XY, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_Y)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_YZ, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else if (currentAxis.equals(Vector3f.UNIT_Z)) { + pickManager.initiatePick(toolController.getSelectedSpatial(), PickManager.PLANE_XZ, getTransformType(), camera, screenCoord); + pickEnabled = true; + } else { + return; + } + } + + if (pickManager.updatePick(camera, screenCoord)) { + Vector3f scale = startScale; + if (currentAxis.equals(Vector3f.UNIT_XYZ)) { + Vector3f constraintAxis = pickManager.getStartOffset().normalize(); + float diff = pickManager.getTranslation(constraintAxis).dot(constraintAxis); + diff *= 0.5f; + scale = startScale.add(new Vector3f(diff, diff, diff)); + } else { + // Get the translation in the spatial Space + Quaternion worldToSpatial = toolController.getSelectedSpatial().getWorldRotation().inverse(); + Vector3f diff = pickManager.getTranslation(worldToSpatial.mult(currentAxis)); + diff.multLocal(0.5f); + scale = startScale.add(diff); + } + finalScale = scale; + toolController.getSelectedSpatial().setLocalScale(scale); + updateToolsTransformation(); + } + } + + @Override + public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + if (pressed) { + apply(); + } + } + + @Override + public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { + if (pressed) { + cancel(); + } + } + + private class ScaleUndo extends AbstractUndoableSceneEdit { + + private Spatial spatial; + private Vector3f before, after; + + ScaleUndo(Spatial spatial, Vector3f before, Vector3f after) { + this.spatial = spatial; + this.before = before; + this.after = after; + } + + @Override + public void sceneUndo() { + spatial.setLocalScale(before); + toolController.selectedSpatialTransformed(); + } + + @Override + public void sceneRedo() { + spatial.setLocalScale(after); + toolController.selectedSpatialTransformed(); + } + } +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ShortcutManager.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ShortcutManager.java new file mode 100644 index 000000000..187293e92 --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ShortcutManager.java @@ -0,0 +1,335 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer.tools.shortcuts; + +import com.jme3.gde.scenecomposer.SceneEditTool; +import com.jme3.input.KeyInput; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.math.Vector3f; +import java.util.ArrayList; +import org.openide.util.Lookup; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author dokthar + */ +@ServiceProvider(service = ShortcutManager.class) +public class ShortcutManager { + + private ShortcutTool currentShortcut; + private ArrayList shortcutList; + private boolean ctrlDown = false; + private boolean shiftDown = false; + private boolean altDown = false; + + public ShortcutManager() { + shortcutList = new ArrayList(); + shortcutList.add(new MoveShortcut()); + shortcutList.add(new RotateShortcut()); + shortcutList.add(new ScaleShortcut()); + shortcutList.add(new DuplicateShortcut()); + shortcutList.add(new DeleteShortcut()); + } + + /* + Methodes + */ + /** + * This MUST be called by the shortcut tool once the modifications are done. + */ + public void terminate() { + currentShortcut = null; + } + + /** + * + * @return true if a shortCutTool is active, else return false. + */ + public boolean isActive() { + return currentShortcut != null; + } + + /** + * @return the ctrlDown + */ + public boolean isCtrlDown() { + return ctrlDown; + } + + /** + * @return the shiftDown + */ + public boolean isShiftDown() { + return shiftDown; + } + + /** + * @return the altDown + */ + public boolean isAltDown() { + return altDown; + } + + /** + * Set the current shortcut to shortcut. cancel the current + * shortcut if it was still active + * + * @param shortcut the ShortCutTool to set + */ + public void setShortCut(ShortcutTool shortcut) { + if (isActive()) { + currentShortcut.cancel(); + } + currentShortcut = shortcut; + } + + /** + * Get the shortcut that can be enable with the given kei, the current + * shortcut cannot be enable twice. This also check for command key used to + * provide isCtrlDown(), isShiftDown() and isAltDown(). + * + * @param kie the KeyInputEvent + * @return the activable shortcut else return null + */ + public ShortcutTool getActivableShortcut(KeyInputEvent kie) { + if (checkCommandeKey(kie)) { + return null; + } + for (ShortcutTool s : shortcutList) { + if (s != currentShortcut) { + if (s.isActivableBy(kie)) { + return s; + } + } + } + return null; + } + + /** + * + * @return the current active shortcut + */ + public ShortcutTool getActiveShortcut() { + return currentShortcut; + } + + /** + * + * @param kie the KeyInputEvent + * @return true if the given Kei can enable a sortcut, else false + */ + public boolean canActivateShortcut(KeyInputEvent kie) { + return getActivableShortcut(kie) != null; + } + + /** + * Set the current shortcut with the shortcut one that can be enable with + * the given key + * + * @param kie the KeyInputEvent + * @return true is the shortcut changed, else false + */ + public boolean activateShortcut(KeyInputEvent kie) { + ShortcutTool newShortcut = getActivableShortcut(kie); + if (newShortcut != null) { + currentShortcut = newShortcut; + } + return newShortcut != null; + } + + /** + * This should be called to trigger the currentShortcut.keyPressed() method. + * This also check for command key used to provide isCtrlDown(), + * isShiftDown() and isAltDown(). + * + * @param kie + */ + public void doKeyPressed(KeyInputEvent kie) { + if (checkCommandeKey(kie)) { + //return; + } else if (isActive()) { + currentShortcut.keyPressed(kie); + } + } + + private boolean checkCommandeKey(KeyInputEvent kie) { + if (checkCtrlHit(kie)) { + ctrlDown = kie.isPressed(); + return true; + } else if (checkAltHit(kie)) { + altDown = kie.isPressed(); + return true; + } else if (checkShiftHit(kie)) { + shiftDown = kie.isPressed(); + return true; + } + return false; + } + + /* + STATIC + */ + /** + * + * @param kie + * @return true if the given kie is KEY_RETURN + */ + public static boolean checkEnterHit(KeyInputEvent kie) { + if (kie.getKeyCode() == KeyInput.KEY_RETURN) { + return true; + } + return false; + } + + /** + * + * @param kie + * @return true if the given kie is KEY_ESCAPE + */ + public static boolean checkEscHit(KeyInputEvent kie) { + if (kie.getKeyCode() == KeyInput.KEY_ESCAPE) { + return true; + } + return false; + } + + /** + * + * @param kie + * @return true if the given kie is KEY_LCONTROL || KEY_RCONTROL + */ + public static boolean checkCtrlHit(KeyInputEvent kie) { + if (kie.getKeyCode() == KeyInput.KEY_LCONTROL || kie.getKeyCode() == KeyInput.KEY_RCONTROL) { + return true; + } + return false; + } + + /** + * + * @param kie + * @return true if the given kie is KEY_LSHIFT || KEY_RSHIFT + */ + public static boolean checkShiftHit(KeyInputEvent kie) { + if (kie.getKeyCode() == KeyInput.KEY_LSHIFT || kie.getKeyCode() == KeyInput.KEY_RSHIFT) { + return true; + } + return false; + } + + /** + * + * @param kie + * @return true if the given kie is KEY_LMENU || KEY_RMENU + */ + public static boolean checkAltHit(KeyInputEvent kie) { + if (kie.getKeyCode() == KeyInput.KEY_LMENU || kie.getKeyCode() == KeyInput.KEY_RMENU) { + return true; + } + return false; + } + + /** + * store the number kie into the numberBuilder + * + * @param kie + * @param numberBuilder + * @return true if the given kie is handled as a number key event + */ + public static boolean checkNumberKey(KeyInputEvent kie, StringBuilder numberBuilder) { + if (kie.getKeyCode() == KeyInput.KEY_MINUS) { + if (numberBuilder.length() > 0) { + if (numberBuilder.charAt(0) == '-') { + numberBuilder.replace(0, 1, ""); + } else { + numberBuilder.insert(0, '-'); + } + } else { + numberBuilder.append('-'); + } + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_0 || kie.getKeyCode() == KeyInput.KEY_NUMPAD0) { + numberBuilder.append('0'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_1 || kie.getKeyCode() == KeyInput.KEY_NUMPAD1) { + numberBuilder.append('1'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_2 || kie.getKeyCode() == KeyInput.KEY_NUMPAD2) { + numberBuilder.append('2'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_3 || kie.getKeyCode() == KeyInput.KEY_NUMPAD3) { + numberBuilder.append('3'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_4 || kie.getKeyCode() == KeyInput.KEY_NUMPAD4) { + numberBuilder.append('4'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_5 || kie.getKeyCode() == KeyInput.KEY_NUMPAD5) { + numberBuilder.append('5'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_6 || kie.getKeyCode() == KeyInput.KEY_NUMPAD6) { + numberBuilder.append('6'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_7 || kie.getKeyCode() == KeyInput.KEY_NUMPAD7) { + numberBuilder.append('7'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_8 || kie.getKeyCode() == KeyInput.KEY_NUMPAD8) { + numberBuilder.append('8'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_9 || kie.getKeyCode() == KeyInput.KEY_NUMPAD9) { + numberBuilder.append('9'); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_PERIOD) { + if (numberBuilder.indexOf(".") == -1) { // if it doesn't exist yet + if (numberBuilder.length() == 0 + || (numberBuilder.length() == 1 && numberBuilder.charAt(0) == '-')) { + numberBuilder.append("0."); + } else { + numberBuilder.append("."); + } + } + return true; + } + + return false; + } + + /** + * + * @param numberBuilder the StringBuilder storing the float number + * @return the float value created from the given StringBuilder + */ + public static float getNumberKey(StringBuilder numberBuilder) { + if (numberBuilder.length() == 0) { + return 0; + } else { + return new Float(numberBuilder.toString()); + } + } + + /** + * Check for axis input for key X,Y,Z and store the corresponding UNIT_ into + * the axisStore + * + * @param kie + * @param axisStore + * @return true if the given kie is handled as a Axis input + */ + public static boolean checkAxisKey(KeyInputEvent kie, Vector3f axisStore) { + if (kie.getKeyCode() == KeyInput.KEY_X) { + axisStore.set(Vector3f.UNIT_X); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_Y) { + axisStore.set(Vector3f.UNIT_Y); + return true; + } else if (kie.getKeyCode() == KeyInput.KEY_Z) { + axisStore.set(Vector3f.UNIT_Z); + return true; + } + return false; + } + +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ShortcutTool.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ShortcutTool.java new file mode 100644 index 000000000..9b094fc1d --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/ShortcutTool.java @@ -0,0 +1,29 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer.tools.shortcuts; + +import com.jme3.gde.scenecomposer.SceneEditTool; +import com.jme3.input.event.KeyInputEvent; +import org.openide.util.Lookup; + +/** + * + * @author dokthar + */ +public abstract class ShortcutTool extends SceneEditTool { + + public abstract boolean isActivableBy(KeyInputEvent kie); + + public abstract void cancel(); + + protected final void terminate() { + Lookup.getDefault().lookup(ShortcutManager.class).terminate(); + } + + @Override + public abstract void keyPressed(KeyInputEvent kie); + +} diff --git a/settings.gradle b/settings.gradle index 346532460..89b8fc075 100644 --- a/settings.gradle +++ b/settings.gradle @@ -35,6 +35,10 @@ include 'jme3-testdata' // Example projects include 'jme3-examples' +if(buildAndroidExamples == "true"){ + include 'jme3-android-examples' +} + if(buildSdkProject == "true"){ include 'sdk' }