From 73c3f39e460fa5ca1e5909430fce540586ec48ae Mon Sep 17 00:00:00 2001 From: Alrik Date: Wed, 8 Apr 2015 12:58:25 +0200 Subject: [PATCH 01/27] - add test case --- .../post/TestBloomAlphaThreshold.java | 178 ++++++++++++++++++ .../src/main/resources/Textures/glass.dds | Bin 0 -> 349680 bytes 2 files changed, 178 insertions(+) create mode 100644 jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java create mode 100644 jme3-testdata/src/main/resources/Textures/glass.dds diff --git a/jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java b/jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java new file mode 100644 index 000000000..7e8608882 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java @@ -0,0 +1,178 @@ +/* + * 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 jme3test.post; + +import com.jme3.app.SimpleApplication; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.DirectionalLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.post.filters.BloomFilter; +import com.jme3.post.filters.BloomFilter.GlowMode; +import com.jme3.renderer.queue.RenderQueue.ShadowMode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.WireFrustum; +import com.jme3.scene.shape.Box; +import com.jme3.util.SkyFactory; + +public class TestBloomAlphaThreshold extends SimpleApplication +{ + + float angle; + Spatial lightMdl; + Spatial teapot; + Geometry frustumMdl; + WireFrustum frustum; + boolean active = true; + FilterPostProcessor fpp; + + public static void main(String[] args) + { + TestBloomAlphaThreshold app = new TestBloomAlphaThreshold(); + app.start(); + } + + @Override + public void simpleInitApp() + { + // put the camera in a bad position + cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -10)); + cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); + // cam.setFrustumFar(1000); + + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + + mat.setFloat("Shininess", 15f); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Ambient", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); + mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); + mat.setColor("GlowColor", ColorRGBA.Green); + + Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + matSoil.setFloat("Shininess", 15f); + matSoil.setBoolean("UseMaterialColors", true); + matSoil.setColor("Ambient", ColorRGBA.Gray); + matSoil.setColor("Diffuse", ColorRGBA.Black); + matSoil.setColor("Specular", ColorRGBA.Gray); + + teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); + teapot.setLocalTranslation(0, 0, 10); + + teapot.setMaterial(mat); + teapot.setShadowMode(ShadowMode.CastAndReceive); + teapot.setLocalScale(10.0f); + rootNode.attachChild(teapot); + + Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700)); + soil.setMaterial(matSoil); + soil.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(soil); + + Material matBox = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + matBox.setTexture("ColorMap", assetManager.loadTexture("Textures/glass.dds")); + matBox.setFloat("AlphaDiscardThreshold", 0.5f); + + Geometry box = new Geometry("box", new Box(new Vector3f(-3.5f, 10, -2), 2, 2, 2)); + box.setMaterial(matBox); + // box.setShadowMode(ShadowMode.CastAndReceive); + rootNode.attachChild(box); + + DirectionalLight light = new DirectionalLight(); + light.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); + light.setColor(ColorRGBA.White.mult(1.5f)); + rootNode.addLight(light); + + // load sky + Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/FullskiesBlueClear03.dds", false); + sky.setCullHint(Spatial.CullHint.Never); + rootNode.attachChild(sky); + + fpp = new FilterPostProcessor(assetManager); + int numSamples = getContext().getSettings().getSamples(); + if (numSamples > 0) + { + fpp.setNumSamples(numSamples); + } + + BloomFilter bloom = new BloomFilter(GlowMode.Objects); + bloom.setDownSamplingFactor(2); + bloom.setBlurScale(1.37f); + bloom.setExposurePower(3.30f); + bloom.setExposureCutOff(0.2f); + bloom.setBloomIntensity(2.45f); + BloomUI ui = new BloomUI(inputManager, bloom); + + viewPort.addProcessor(fpp); + fpp.addFilter(bloom); + initInputs(); + + } + + private void initInputs() + { + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + + ActionListener acl = new ActionListener() + { + + @Override + public void onAction(String name, boolean keyPressed, float tpf) + { + if (name.equals("toggle") && keyPressed) + { + if (active) + { + active = false; + viewPort.removeProcessor(fpp); + } + else + { + active = true; + viewPort.addProcessor(fpp); + } + } + } + }; + + inputManager.addListener(acl, "toggle"); + + } + +} diff --git a/jme3-testdata/src/main/resources/Textures/glass.dds b/jme3-testdata/src/main/resources/Textures/glass.dds new file mode 100644 index 0000000000000000000000000000000000000000..5344df36434ade40191ce74ea6d7c11a02f67a35 GIT binary patch literal 349680 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 Date: Thu, 9 Apr 2015 08:58:04 +0200 Subject: [PATCH 02/27] - revert commit to master --- .../post/TestBloomAlphaThreshold.java | 178 ------------------ .../src/main/resources/Textures/glass.dds | Bin 349680 -> 0 bytes 2 files changed, 178 deletions(-) delete mode 100644 jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java delete mode 100644 jme3-testdata/src/main/resources/Textures/glass.dds diff --git a/jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java b/jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java deleted file mode 100644 index 7e8608882..000000000 --- a/jme3-examples/src/main/java/jme3test/post/TestBloomAlphaThreshold.java +++ /dev/null @@ -1,178 +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 jme3test.post; - -import com.jme3.app.SimpleApplication; -import com.jme3.input.KeyInput; -import com.jme3.input.controls.ActionListener; -import com.jme3.input.controls.KeyTrigger; -import com.jme3.light.DirectionalLight; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector3f; -import com.jme3.post.FilterPostProcessor; -import com.jme3.post.filters.BloomFilter; -import com.jme3.post.filters.BloomFilter.GlowMode; -import com.jme3.renderer.queue.RenderQueue.ShadowMode; -import com.jme3.scene.Geometry; -import com.jme3.scene.Spatial; -import com.jme3.scene.debug.WireFrustum; -import com.jme3.scene.shape.Box; -import com.jme3.util.SkyFactory; - -public class TestBloomAlphaThreshold extends SimpleApplication -{ - - float angle; - Spatial lightMdl; - Spatial teapot; - Geometry frustumMdl; - WireFrustum frustum; - boolean active = true; - FilterPostProcessor fpp; - - public static void main(String[] args) - { - TestBloomAlphaThreshold app = new TestBloomAlphaThreshold(); - app.start(); - } - - @Override - public void simpleInitApp() - { - // put the camera in a bad position - cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -10)); - cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); - // cam.setFrustumFar(1000); - - Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); - - mat.setFloat("Shininess", 15f); - mat.setBoolean("UseMaterialColors", true); - mat.setColor("Ambient", ColorRGBA.Yellow.mult(0.2f)); - mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); - mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); - mat.setColor("GlowColor", ColorRGBA.Green); - - Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); - matSoil.setFloat("Shininess", 15f); - matSoil.setBoolean("UseMaterialColors", true); - matSoil.setColor("Ambient", ColorRGBA.Gray); - matSoil.setColor("Diffuse", ColorRGBA.Black); - matSoil.setColor("Specular", ColorRGBA.Gray); - - teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); - teapot.setLocalTranslation(0, 0, 10); - - teapot.setMaterial(mat); - teapot.setShadowMode(ShadowMode.CastAndReceive); - teapot.setLocalScale(10.0f); - rootNode.attachChild(teapot); - - Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700)); - soil.setMaterial(matSoil); - soil.setShadowMode(ShadowMode.CastAndReceive); - rootNode.attachChild(soil); - - Material matBox = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - matBox.setTexture("ColorMap", assetManager.loadTexture("Textures/glass.dds")); - matBox.setFloat("AlphaDiscardThreshold", 0.5f); - - Geometry box = new Geometry("box", new Box(new Vector3f(-3.5f, 10, -2), 2, 2, 2)); - box.setMaterial(matBox); - // box.setShadowMode(ShadowMode.CastAndReceive); - rootNode.attachChild(box); - - DirectionalLight light = new DirectionalLight(); - light.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); - light.setColor(ColorRGBA.White.mult(1.5f)); - rootNode.addLight(light); - - // load sky - Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/FullskiesBlueClear03.dds", false); - sky.setCullHint(Spatial.CullHint.Never); - rootNode.attachChild(sky); - - fpp = new FilterPostProcessor(assetManager); - int numSamples = getContext().getSettings().getSamples(); - if (numSamples > 0) - { - fpp.setNumSamples(numSamples); - } - - BloomFilter bloom = new BloomFilter(GlowMode.Objects); - bloom.setDownSamplingFactor(2); - bloom.setBlurScale(1.37f); - bloom.setExposurePower(3.30f); - bloom.setExposureCutOff(0.2f); - bloom.setBloomIntensity(2.45f); - BloomUI ui = new BloomUI(inputManager, bloom); - - viewPort.addProcessor(fpp); - fpp.addFilter(bloom); - initInputs(); - - } - - private void initInputs() - { - inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); - - ActionListener acl = new ActionListener() - { - - @Override - public void onAction(String name, boolean keyPressed, float tpf) - { - if (name.equals("toggle") && keyPressed) - { - if (active) - { - active = false; - viewPort.removeProcessor(fpp); - } - else - { - active = true; - viewPort.addProcessor(fpp); - } - } - } - }; - - inputManager.addListener(acl, "toggle"); - - } - -} diff --git a/jme3-testdata/src/main/resources/Textures/glass.dds b/jme3-testdata/src/main/resources/Textures/glass.dds deleted file mode 100644 index 5344df36434ade40191ce74ea6d7c11a02f67a35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 349680 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 Date: Sun, 24 May 2015 16:09:41 +0200 Subject: [PATCH 03/27] Added: GL_MAX_VERTEX_UNIFORM_COMPONENTS --- jme3-core/src/main/java/com/jme3/renderer/Limits.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/renderer/Limits.java b/jme3-core/src/main/java/com/jme3/renderer/Limits.java index b10c539b8..7df9bc76b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Limits.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Limits.java @@ -75,4 +75,6 @@ public enum Limits { ColorTextureSamples, DepthTextureSamples, + + VertexUniformComponents, } From 14e4f2bfb3d986806bfd7a12e092a8bfd6d31f87 Mon Sep 17 00:00:00 2001 From: zzuegg Date: Sun, 24 May 2015 16:12:28 +0200 Subject: [PATCH 04/27] Added: GL_MAX_VERTEX_UNIFORM_COMPONENTS --- jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java | 1 + .../src/main/java/com/jme3/renderer/opengl/GLRenderer.java | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index 76eedb521..21eedab52 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -99,6 +99,7 @@ public interface GL { public static final int GL_MAX_TEXTURE_SIZE = 0xD33; public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869; public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; + public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A; public static final int GL_MIRRORED_REPEAT = 0x8370; public static final int GL_NEAREST = 0x2600; public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; 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 3f14bdb10..caf472543 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 @@ -196,7 +196,7 @@ public class GLRenderer implements Renderer { } int glslVer = extractVersion(gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)); - + switch (glslVer) { default: if (glslVer < 400) { @@ -249,7 +249,7 @@ public class GLRenderer implements Renderer { } limits.put(Limits.FragmentTextureUnits, getInteger(GL.GL_MAX_TEXTURE_IMAGE_UNITS)); - + // gl.glGetInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16); // vertexUniforms = intBuf16.get(0); // logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); @@ -257,7 +257,7 @@ public class GLRenderer implements Renderer { // gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); // fragUniforms = intBuf16.get(0); // logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); - + limits.put(Limits.VertexUniformComponents,getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS)); limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS)); limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE)); limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE)); From e2d8fe829359dd6028d6810efddbf671d9980231 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sun, 31 May 2015 16:00:55 -0400 Subject: [PATCH 05/27] GLRenderer: support luminance / alpha textures in core profile --- .../java/com/jme3/renderer/opengl/GL.java | 2 + .../java/com/jme3/renderer/opengl/GL3.java | 13 ++++++- .../java/com/jme3/renderer/opengl/GL4.java | 2 +- .../jme3/renderer/opengl/GLImageFormat.java | 21 ++++++++++ .../jme3/renderer/opengl/GLImageFormats.java | 28 ++++++++++++++ .../com/jme3/renderer/opengl/GLRenderer.java | 2 +- .../com/jme3/renderer/opengl/TextureUtil.java | 38 +++++++++++++++++-- 7 files changed, 99 insertions(+), 7 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index 76eedb521..12f14c8aa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -74,6 +74,7 @@ public interface GL { public static final int GL_FRONT_AND_BACK = 0x408; public static final int GL_GEQUAL = 0x206; public static final int GL_GREATER = 0x204; + public static final int GL_GREEN = 0x1904; public static final int GL_INCR = 0x1E02; public static final int GL_INCR_WRAP = 0x8507; public static final int GL_INFO_LOG_LENGTH = 0x8B84; @@ -114,6 +115,7 @@ public interface GL { public static final int GL_OUT_OF_MEMORY = 0x505; public static final int GL_POINTS = 0x0; public static final int GL_POLYGON_OFFSET_FILL = 0x8037; + public static final int GL_RED = 0x1903; public static final int GL_RENDERER = 0x1F01; public static final int GL_REPEAT = 0x2901; public static final int GL_REPLACE = 0x1E01; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java index 190ed4547..2a7c38bb9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java @@ -34,7 +34,7 @@ package com.jme3.renderer.opengl; import java.nio.IntBuffer; /** - * GL functions only available on vanilla desktop OpenGL 3.0. + * GL functions only available on vanilla desktop OpenGL 3.0+. * * @author Kirill Vainer */ @@ -43,6 +43,17 @@ public interface GL3 extends GL2 { public static final int GL_DEPTH_STENCIL_ATTACHMENT = 0x821A; public static final int GL_GEOMETRY_SHADER = 0x8DD9; public static final int GL_NUM_EXTENSIONS = 0x821D; + public static final int GL_R8 = 0x8229; + public static final int GL_R16F = 0x822D; + public static final int GL_R32F = 0x822E; + public static final int GL_RG16F = 0x822F; + public static final int GL_RG32F = 0x8230; + public static final int GL_RG = 0x8227; + public static final int GL_RG8 = 0x822B; + public static final int GL_TEXTURE_SWIZZLE_A = 0x8E45; + public static final int GL_TEXTURE_SWIZZLE_B = 0x8E44; + public static final int GL_TEXTURE_SWIZZLE_G = 0x8E43; + public static final int GL_TEXTURE_SWIZZLE_R = 0x8E42; public void glBindFragDataLocation(int param1, int param2, String param3); /// GL3+ public void glBindVertexArray(int param1); /// GL3+ diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java index ce982eebf..058bc00ec 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java @@ -34,7 +34,7 @@ package com.jme3.renderer.opengl; import java.nio.IntBuffer; /** - * GL functions only available on vanilla desktop OpenGL 3.0. + * GL functions only available on vanilla desktop OpenGL 4.0. * * @author Kirill Vainer */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormat.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormat.java index 71d95f59b..8e65fbdef 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormat.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormat.java @@ -42,6 +42,7 @@ public final class GLImageFormat { public final int format; public final int dataType; public final boolean compressed; + public final boolean swizzleRequired; /** * Constructor for formats. @@ -55,6 +56,7 @@ public final class GLImageFormat { this.format = format; this.dataType = dataType; this.compressed = false; + this.swizzleRequired = false; } /** @@ -63,11 +65,30 @@ public final class GLImageFormat { * @param internalFormat OpenGL internal format * @param format OpenGL format * @param dataType OpenGL datatype + * @param compressed Format is compressed */ public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) { this.internalFormat = internalFormat; this.format = format; this.dataType = dataType; this.compressed = compressed; + this.swizzleRequired = false; + } + + /** + * Constructor for formats. + * + * @param internalFormat OpenGL internal format + * @param format OpenGL format + * @param dataType OpenGL datatype + * @param compressed Format is compressed + * @param swizzleRequired Need to use texture swizzle to upload texture + */ + public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed, boolean swizzleRequired) { + this.internalFormat = internalFormat; + this.format = format; + this.dataType = dataType; + this.compressed = compressed; + this.swizzleRequired = swizzleRequired; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java index a7ef9f52d..ab80b9e2a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java @@ -52,6 +52,13 @@ public final class GLImageFormats { formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType); } + private static void formatSwiz(GLImageFormat[][] formatToGL, Image.Format format, + int glInternalFormat, + int glFormat, + int glDataType){ + formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, false, true); + } + private static void formatSrgb(GLImageFormat[][] formatToGL, Image.Format format, int glInternalFormat, int glFormat, @@ -60,6 +67,14 @@ public final class GLImageFormats { formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType); } + private static void formatSrgbSwiz(GLImageFormat[][] formatToGL, Image.Format format, + int glInternalFormat, + int glFormat, + int glDataType) + { + formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, false, true); + } + private static void formatComp(GLImageFormat[][] formatToGL, Image.Format format, int glCompressedFormat, int glFormat, @@ -88,6 +103,19 @@ public final class GLImageFormats { public static GLImageFormat[][] getFormatsForCaps(EnumSet caps) { GLImageFormat[][] formatToGL = new GLImageFormat[2][Image.Format.values().length]; + // Core Profile Formats (supported by both OpenGL Core 3.3 and OpenGL ES 3.0+) + if (caps.contains(Caps.CoreProfile)) { + formatSwiz(formatToGL, Format.Alpha8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE); + formatSwiz(formatToGL, Format.Luminance8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE); + formatSwiz(formatToGL, Format.Luminance8Alpha8, GL3.GL_RG8, GL3.GL_RG, GL.GL_UNSIGNED_BYTE); + formatSwiz(formatToGL, Format.Luminance16F, GL3.GL_R16F, GL.GL_RED, GLExt.GL_HALF_FLOAT_ARB); + formatSwiz(formatToGL, Format.Luminance32F, GL3.GL_R32F, GL.GL_RED, GL.GL_FLOAT); + formatSwiz(formatToGL, Format.Luminance16FAlpha16F, GL3.GL_RG16F, GL3.GL_RG, GLExt.GL_HALF_FLOAT_ARB); + + formatSrgbSwiz(formatToGL, Format.Luminance8, GLExt.GL_SRGB8_EXT, GL.GL_RED, GL.GL_UNSIGNED_BYTE); + formatSrgbSwiz(formatToGL, Format.Luminance8Alpha8, GLExt.GL_SRGB8_ALPHA8_EXT, GL3.GL_RG, GL.GL_UNSIGNED_BYTE); + } + if (caps.contains(Caps.OpenGL20)) { if (!caps.contains(Caps.CoreProfile)) { format(formatToGL, Format.Alpha8, GL2.GL_ALPHA8, GL.GL_ALPHA, GL.GL_UNSIGNED_BYTE); 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 3f14bdb10..23527d1ab 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 @@ -106,7 +106,7 @@ public class GLRenderer implements Renderer { this.gl4 = gl instanceof GL4 ? (GL4)gl : null; this.glfbo = glfbo; this.glext = glext; - this.texUtil = new TextureUtil(gl, gl2, glext, context); + this.texUtil = new TextureUtil(gl, gl2, glext); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java index 37ffe5ed3..a2f21ceaa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java @@ -54,14 +54,12 @@ final class TextureUtil { private final GL gl; private final GL2 gl2; private final GLExt glext; - private final RenderContext context; private GLImageFormat[][] formats; - - public TextureUtil(GL gl, GL2 gl2, GLExt glext, RenderContext context) { + + public TextureUtil(GL gl, GL2 gl2, GLExt glext) { this.gl = gl; this.gl2 = gl2; this.glext = glext; - this.context = context; } public void initialize(EnumSet caps) { @@ -103,6 +101,33 @@ final class TextureUtil { return glFmt; } + private void setupTextureSwizzle(int target, Format format) { + // Needed for OpenGL 3.3 to support luminance / alpha formats + switch (format) { + case Alpha8: + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_ZERO); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_ZERO); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_ZERO); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_RED); + break; + case Luminance8: + case Luminance16F: + case Luminance32F: + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_RED); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_RED); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_RED); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_ONE); + break; + case Luminance8Alpha8: + case Luminance16FAlpha16F: + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_RED); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_RED); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_RED); + gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_GREEN); + break; + } + } + private void uploadTextureLevel(GLImageFormat format, int target, int level, int slice, int sliceCount, int width, int height, int depth, int samples, ByteBuffer data) { if (format.compressed && data != null) { if (target == GL2.GL_TEXTURE_3D) { @@ -242,6 +267,11 @@ final class TextureUtil { } int samples = image.getMultiSamples(); + + // For OGL3 core: setup texture swizzle. + if (oglFormat.swizzleRequired) { + setupTextureSwizzle(target, jmeFormat); + } for (int i = 0; i < mipSizes.length; i++) { int mipWidth = Math.max(1, width >> i); From 7fa735fdb1d15c36171bf9044dc2bc8aa45d97d4 Mon Sep 17 00:00:00 2001 From: Riccardo Balbo Date: Thu, 18 Jun 2015 16:26:36 +0200 Subject: [PATCH 06/27] Remove root slash from the asset path --- .../src/plugins/java/com/jme3/asset/plugins/ZipLocator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jme3-core/src/plugins/java/com/jme3/asset/plugins/ZipLocator.java b/jme3-core/src/plugins/java/com/jme3/asset/plugins/ZipLocator.java index d20816f34..22e7cc244 100644 --- a/jme3-core/src/plugins/java/com/jme3/asset/plugins/ZipLocator.java +++ b/jme3-core/src/plugins/java/com/jme3/asset/plugins/ZipLocator.java @@ -82,6 +82,7 @@ public class ZipLocator implements AssetLocator { public AssetInfo locate(AssetManager manager, AssetKey key) { String name = key.getName(); + if(name.startsWith("/"))name=name.substring(1); ZipEntry entry = zipfile.getEntry(name); if (entry == null) return null; From f7a4fe9f2513ac0fa5f78b7aca12606efaa75da5 Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Thu, 18 Jun 2015 23:51:17 +0200 Subject: [PATCH 07/27] Improvement of the Inverse Kinematics Constraint. --- jme3-blender/build.gradle | 5 +- .../blender/constraints/Constraint.java | 4 +- .../definitions/ConstraintDefinition.java | 6 + .../ConstraintDefinitionFactory.java | 12 +- .../definitions/ConstraintDefinitionIK.java | 268 +++++++++--------- .../plugins/blender/math/DQuaternion.java | 128 +++++++++ .../plugins/blender/math/DTransform.java | 26 +- .../scene/plugins/blender/math/Matrix.java | 214 ++++++++++++++ 8 files changed, 510 insertions(+), 153 deletions(-) create mode 100644 jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java diff --git a/jme3-blender/build.gradle b/jme3-blender/build.gradle index 1b42c7109..a556d7a65 100644 --- a/jme3-blender/build.gradle +++ b/jme3-blender/build.gradle @@ -6,4 +6,7 @@ dependencies { compile project(':jme3-core') compile project(':jme3-desktop') compile project(':jme3-effects') -} + compile ('org.ejml:core:0.27') + compile ('org.ejml:dense64:0.27') + compile ('org.ejml:simple:0.27') +} \ No newline at end of file diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java index 91cfd2f3f..f2268199c 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java @@ -64,7 +64,7 @@ public abstract class Constraint { Pointer pData = (Pointer) constraintStructure.getFieldValue("data"); if (pData.isNotNull()) { Structure data = pData.fetchData().get(0); - constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(data, ownerOMA, blenderContext); + constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(data, name, ownerOMA, blenderContext); Pointer pTar = (Pointer) data.getFieldValue("tar"); if (pTar != null && pTar.isNotNull()) { targetOMA = pTar.getOldMemoryAddress(); @@ -77,7 +77,7 @@ public abstract class Constraint { } } else { // Null constraint has no data, so create it here - constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(null, null, blenderContext); + constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(null, name, null, blenderContext); } ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue()); ipo = influenceIpo; diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java index 346554052..a1f3a7316 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java @@ -30,6 +30,8 @@ public abstract class ConstraintDefinition { protected Set alteredOmas; /** The variable that determines if the constraint will alter the track in any way. */ protected boolean trackToBeChanged = true; + /** The name of the constraint. */ + protected String constraintName; /** * Loads a constraint definition based on the constraint definition @@ -53,6 +55,10 @@ public abstract class ConstraintDefinition { constraintHelper = (ConstraintHelper) (blenderContext == null ? null : blenderContext.getHelper(ConstraintHelper.class)); this.ownerOMA = ownerOMA; } + + public void setConstraintName(String constraintName) { + this.constraintName = constraintName; + } /** * @return determines if the definition of the constraint will change the bone in any way; in most cases diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionFactory.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionFactory.java index cbf727290..c1d69fe06 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionFactory.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionFactory.java @@ -92,7 +92,7 @@ public class ConstraintDefinitionFactory { * this exception is thrown when the blender file is somehow * corrupted */ - public static ConstraintDefinition createConstraintDefinition(Structure constraintStructure, Long ownerOMA, BlenderContext blenderContext) throws BlenderFileException { + public static ConstraintDefinition createConstraintDefinition(Structure constraintStructure, String constraintName, Long ownerOMA, BlenderContext blenderContext) throws BlenderFileException { if (constraintStructure == null) { return new ConstraintDefinitionNull(null, ownerOMA, blenderContext); } @@ -100,7 +100,9 @@ public class ConstraintDefinitionFactory { Class constraintDefinitionClass = CONSTRAINT_CLASSES.get(constraintClassName); if (constraintDefinitionClass != null) { try { - return (ConstraintDefinition) constraintDefinitionClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, blenderContext); + ConstraintDefinition def = (ConstraintDefinition) constraintDefinitionClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, blenderContext); + def.setConstraintName(constraintName); + return def; } catch (IllegalArgumentException e) { throw new BlenderFileException(e.getLocalizedMessage(), e); } catch (SecurityException e) { @@ -113,9 +115,9 @@ public class ConstraintDefinitionFactory { throw new BlenderFileException(e.getLocalizedMessage(), e); } } else { - String constraintName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName); - if (constraintName != null) { - return new UnsupportedConstraintDefinition(constraintName); + String unsupportedConstraintClassName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName); + if (unsupportedConstraintClassName != null) { + return new UnsupportedConstraintDefinition(unsupportedConstraintClassName); } else { throw new BlenderFileException("Unknown constraint type: " + constraintClassName); } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java index 35a4e5618..820a283b3 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java @@ -1,36 +1,32 @@ package com.jme3.scene.plugins.blender.constraints.definitions; import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Set; + +import org.ejml.simple.SimpleMatrix; import com.jme3.animation.Bone; import com.jme3.math.Transform; -import com.jme3.math.Vector3f; import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.animations.BoneContext; +import com.jme3.scene.plugins.blender.constraints.ConstraintHelper; import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.math.DQuaternion; import com.jme3.scene.plugins.blender.math.DTransform; +import com.jme3.scene.plugins.blender.math.Matrix; import com.jme3.scene.plugins.blender.math.Vector3d; -/** - * The Inverse Kinematics constraint. - * - * @author Wesley Shillingford (wezrule) - * @author Marcin Roguski (Kaelthas) - */ public class ConstraintDefinitionIK extends ConstraintDefinition { - private static final float MIN_DISTANCE = 0.0001f; + private static final float MIN_DISTANCE = 0.001f; private static final int FLAG_USE_TAIL = 0x01; private static final int FLAG_POSITION = 0x20; + private BonesChain bones; /** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */ private int bonesAffected; - /** The total length of the bone chain. Useful for optimisation of computations speed in some cases. */ - private double chainLength; /** Indicates if the tail of the bone should be used or not. */ private boolean useTail; /** The amount of iterations of the algorithm. */ @@ -51,122 +47,85 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { } } + @Override + public Set getAlteredOmas() { + return bones.alteredOmas; + } + @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { if (influence == 0 || !trackToBeChanged || targetTransform == null) { return;// no need to do anything } + DQuaternion q = new DQuaternion(); Vector3d t = new Vector3d(targetTransform.getTranslation()); - List bones = this.loadBones(); + bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, blenderContext); if (bones.size() == 0) { return;// no need to do anything } double distanceFromTarget = Double.MAX_VALUE; - int iterations = this.iterations; - if (bones.size() == 1) { - iterations = 1;// if only one bone is in the chain then only one iteration that will properly rotate it will be needed - } else { - // if the target cannot be rached by the bones' chain then the chain will become straight and point towards the target - // in this case only one iteration will be needed, computed from the root to top bone - BoneContext rootBone = bones.get(bones.size() - 1); - Transform rootBoneTransform = constraintHelper.getTransform(rootBone.getArmatureObjectOMA(), rootBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); - if (t.distance(new Vector3d(rootBoneTransform.getTranslation())) >= chainLength) { - Collections.reverse(bones); - - for (BoneContext boneContext : bones) { - Bone bone = boneContext.getBone(); - DTransform boneTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD)); - - Vector3d e = boneTransform.getTranslation().add(boneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(boneContext.getLength()));// effector - Vector3d j = boneTransform.getTranslation(); // current join position - - Vector3d currentDir = e.subtractLocal(j).normalizeLocal(); - Vector3d target = t.subtract(j).normalizeLocal(); - double angle = currentDir.angleBetween(target); - if (angle != 0) { - Vector3d cross = currentDir.crossLocal(target).normalizeLocal(); - q.fromAngleAxis(angle, cross); - - if(bone.equals(this.getOwner())) { - if (boneContext.isLockX()) { - q.set(0, q.getY(), q.getZ(), q.getW()); - } - if (boneContext.isLockY()) { - q.set(q.getX(), 0, q.getZ(), q.getW()); - } - if (boneContext.isLockZ()) { - q.set(q.getX(), q.getY(), 0, q.getW()); - } - } - - boneTransform.getRotation().set(q.multLocal(boneTransform.getRotation())); - constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneTransform.toTransform()); - } - } - - iterations = 0; + Vector3d target = new Vector3d(targetTransform.getTranslation()); + Vector3d[] rotationVectors = new Vector3d[bones.size()]; + BoneContext topBone = bones.get(0); + for (int i = 1; i <= iterations; ++i) { + DTransform topBoneTransform = bones.getWorldTransform(topBone); + Vector3d e = topBoneTransform.getTranslation().add(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector + distanceFromTarget = e.distance(t); + if (distanceFromTarget <= MIN_DISTANCE) { + break; } - } - List bestSolution = new ArrayList(bones.size()); - double bestSolutionDistance = Double.MAX_VALUE; - BoneContext topBone = bones.get(0); - for (int i = 0; i < iterations && distanceFromTarget > MIN_DISTANCE; ++i) { - for (BoneContext boneContext : bones) { - Bone bone = boneContext.getBone(); - DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); - DTransform boneWorldTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD)); + Matrix deltaP = new Matrix(3, 1); + deltaP.setColumn(target.subtract(e), 0); - Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector + Matrix J = new Matrix(3, bones.size()); + int column = 0; + for (BoneContext boneContext : bones) { + DTransform boneWorldTransform = bones.getWorldTransform(boneContext); Vector3d j = boneWorldTransform.getTranslation(); // current join position + Vector3d vectorFromJointToEffector = e.subtract(j); + rotationVectors[column] = vectorFromJointToEffector.cross(target.subtract(j)).normalize(); + Vector3d col = rotationVectors[column].cross(vectorFromJointToEffector); + J.setColumn(col, column++); + } + Matrix J_1 = J.pseudoinverse(); - Vector3d currentDir = e.subtractLocal(j).normalizeLocal(); - Vector3d target = t.subtract(j).normalizeLocal(); - double angle = currentDir.angleBetween(target); - if (angle != 0) { - Vector3d cross = currentDir.crossLocal(target).normalizeLocal(); - q.fromAngleAxis(angle, cross); - - if(bone.equals(this.getOwner())) { - if (boneContext.isLockX()) { - q.set(0, q.getY(), q.getZ(), q.getW()); - } - if (boneContext.isLockY()) { - q.set(q.getX(), 0, q.getZ(), q.getW()); - } - if (boneContext.isLockZ()) { - q.set(q.getX(), q.getY(), 0, q.getW()); - } - } + SimpleMatrix deltaThetas = J_1.mult(deltaP); - boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation())); - constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform.toTransform()); - } else { - iterations = 0; - break; - } - } + for (int j = 0; j < deltaThetas.numRows(); ++j) { + double angle = deltaThetas.get(j, 0); + Vector3d rotationVector = rotationVectors[j]; - DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); - Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector - distanceFromTarget = e.distance(t); - - if(distanceFromTarget < bestSolutionDistance) { - bestSolutionDistance = distanceFromTarget; - bestSolution.clear(); - for(BoneContext boneContext : bones) { - bestSolution.add(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); + q.fromAngleAxis(angle, rotationVector); + BoneContext boneContext = bones.get(j); + Bone bone = boneContext.getBone(); + if (bone.equals(this.getOwner())) { + if (boneContext.isLockX()) { + q.set(0, q.getY(), q.getZ(), q.getW()); + } + if (boneContext.isLockY()) { + q.set(q.getX(), 0, q.getZ(), q.getW()); + } + if (boneContext.isLockZ()) { + q.set(q.getX(), q.getY(), 0, q.getW()); + } } + + DTransform boneTransform = bones.getWorldTransform(boneContext); + boneTransform.getRotation().set(q.mult(boneTransform.getRotation())); + bones.setWorldTransform(boneContext, boneTransform); } } - - // applying best solution - for(int i=0;i= 0; --i) { BoneContext boneContext = bones.get(i); - constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, bestSolution.get(i)); + DTransform transform = bones.getWorldTransform(boneContext); + constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, transform.toTransform()); } + bones.reset(); } @Override @@ -174,49 +133,12 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { return "Inverse kinematics"; } - /** - * @return the bone contexts of all bones that will be used in this constraint computations - */ - private List loadBones() { - List bones = new ArrayList(); - Bone bone = (Bone) this.getOwner(); - if (bone == null) { - return bones; - } - if (!useTail) { - bone = bone.getParent(); - } - chainLength = 0; - while (bone != null) { - BoneContext boneContext = blenderContext.getBoneContext(bone); - chainLength += boneContext.getLength(); - bones.add(boneContext); - alteredOmas.add(boneContext.getBoneOma()); - if (bonesAffected != 0 && bones.size() >= bonesAffected) { - break; - } - // need to add spaces between bones to the chain length - Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); - Vector3f boneWorldTranslation = boneWorldTransform.getTranslation(); - - bone = bone.getParent(); - - if (bone != null) { - boneContext = blenderContext.getBoneContext(bone); - Transform parentWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); - Vector3f parentWorldTranslation = parentWorldTransform.getTranslation(); - chainLength += boneWorldTranslation.distance(parentWorldTranslation); - } - } - return bones; - } - @Override public boolean isTrackToBeChanged() { if (trackToBeChanged) { // need to check the bone structure too (when constructor was called not all of the bones might have been loaded yet) // that is why it is also checked here - List bones = this.loadBones(); + bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, blenderContext); trackToBeChanged = bones.size() > 0; } return trackToBeChanged; @@ -226,4 +148,68 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { public boolean isTargetRequired() { return true; } + + private static class BonesChain extends ArrayList { + private static final long serialVersionUID = -1850524345643600718L; + + private Set alteredOmas = new HashSet(); + private List originalBonesMatrices = new ArrayList(); + private List bonesMatrices = new ArrayList(); + + public BonesChain(Bone bone, boolean useTail, int bonesAffected, BlenderContext blenderContext) { + if (bone != null) { + ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class); + if (!useTail) { + bone = bone.getParent(); + } + while (bone != null && this.size() < bonesAffected) { + BoneContext boneContext = blenderContext.getBoneContext(bone); + this.add(boneContext); + alteredOmas.add(boneContext.getBoneOma()); + + Space space = this.size() < bonesAffected ? Space.CONSTRAINT_SPACE_LOCAL : Space.CONSTRAINT_SPACE_WORLD; + Transform transform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), space); + originalBonesMatrices.add(new DTransform(transform).toMatrix()); + + bone = bone.getParent(); + } + this.reset(); + } + } + + public DTransform getWorldTransform(BoneContext bone) { + int index = this.indexOf(bone); + return this.getWorldMatrix(index).toTransform(); + } + + public void setWorldTransform(BoneContext bone, DTransform transform) { + int index = this.indexOf(bone); + Matrix boneMatrix = transform.toMatrix(); + + if (index < this.size() - 1) { + // computing the current bone local transform + Matrix parentWorldMatrix = this.getWorldMatrix(index + 1); + SimpleMatrix m = parentWorldMatrix.invert().mult(boneMatrix); + boneMatrix = new Matrix(m); + } + bonesMatrices.set(index, boneMatrix); + } + + public Matrix getWorldMatrix(int index) { + if (index == this.size() - 1) { + return new Matrix(bonesMatrices.get(this.size() - 1)); + } + + SimpleMatrix result = this.getWorldMatrix(index + 1); + result = result.mult(bonesMatrices.get(index)); + return new Matrix(result); + } + + public void reset() { + bonesMatrices.clear(); + for (Matrix m : originalBonesMatrices) { + bonesMatrices.add(new Matrix(m)); + } + } + } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java index 359abf057..9739ccd4b 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java @@ -164,6 +164,134 @@ public final class DQuaternion implements Savable, Cloneable, java.io.Serializab w = 1; } + /** + * norm returns the norm of this quaternion. This is the dot + * product of this quaternion with itself. + * + * @return the norm of the quaternion. + */ + public double norm() { + return w * w + x * x + y * y + z * z; + } + + public DQuaternion fromRotationMatrix(double m00, double m01, double m02, + double m10, double m11, double m12, double m20, double m21, double m22) { + // first normalize the forward (F), up (U) and side (S) vectors of the rotation matrix + // so that the scale does not affect the rotation + double lengthSquared = m00 * m00 + m10 * m10 + m20 * m20; + if (lengthSquared != 1f && lengthSquared != 0f) { + lengthSquared = 1.0 / Math.sqrt(lengthSquared); + m00 *= lengthSquared; + m10 *= lengthSquared; + m20 *= lengthSquared; + } + lengthSquared = m01 * m01 + m11 * m11 + m21 * m21; + if (lengthSquared != 1 && lengthSquared != 0f) { + lengthSquared = 1.0 / Math.sqrt(lengthSquared); + m01 *= lengthSquared; + m11 *= lengthSquared; + m21 *= lengthSquared; + } + lengthSquared = m02 * m02 + m12 * m12 + m22 * m22; + if (lengthSquared != 1f && lengthSquared != 0f) { + lengthSquared = 1.0 / Math.sqrt(lengthSquared); + m02 *= lengthSquared; + m12 *= lengthSquared; + m22 *= lengthSquared; + } + + // Use the Graphics Gems code, from + // ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z + // *NOT* the "Matrix and Quaternions FAQ", which has errors! + + // the trace is the sum of the diagonal elements; see + // http://mathworld.wolfram.com/MatrixTrace.html + double t = m00 + m11 + m22; + + // we protect the division by s by ensuring that s>=1 + if (t >= 0) { // |w| >= .5 + double s = Math.sqrt(t + 1); // |s|>=1 ... + w = 0.5f * s; + s = 0.5f / s; // so this division isn't bad + x = (m21 - m12) * s; + y = (m02 - m20) * s; + z = (m10 - m01) * s; + } else if (m00 > m11 && m00 > m22) { + double s = Math.sqrt(1.0 + m00 - m11 - m22); // |s|>=1 + x = s * 0.5f; // |x| >= .5 + s = 0.5f / s; + y = (m10 + m01) * s; + z = (m02 + m20) * s; + w = (m21 - m12) * s; + } else if (m11 > m22) { + double s = Math.sqrt(1.0 + m11 - m00 - m22); // |s|>=1 + y = s * 0.5f; // |y| >= .5 + s = 0.5f / s; + x = (m10 + m01) * s; + z = (m21 + m12) * s; + w = (m02 - m20) * s; + } else { + double s = Math.sqrt(1.0 + m22 - m00 - m11); // |s|>=1 + z = s * 0.5f; // |z| >= .5 + s = 0.5f / s; + x = (m02 + m20) * s; + y = (m21 + m12) * s; + w = (m10 - m01) * s; + } + + return this; + } + + /** + * toRotationMatrix converts this quaternion to a rotational + * matrix. The result is stored in result. 4th row and 4th column values are + * untouched. Note: the result is created from a normalized version of this quat. + * + * @param result + * The Matrix4f to store the result in. + * @return the rotation matrix representation of this quaternion. + */ + public Matrix toRotationMatrix(Matrix result) { + Vector3d originalScale = new Vector3d(); + + result.toScaleVector(originalScale); + result.setScale(1, 1, 1); + double norm = this.norm(); + // we explicitly test norm against one here, saving a division + // at the cost of a test and branch. Is it worth it? + double s = norm == 1f ? 2f : norm > 0f ? 2f / norm : 0; + + // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs + // will be used 2-4 times each. + double xs = x * s; + double ys = y * s; + double zs = z * s; + double xx = x * xs; + double xy = x * ys; + double xz = x * zs; + double xw = w * xs; + double yy = y * ys; + double yz = y * zs; + double yw = w * ys; + double zz = z * zs; + double zw = w * zs; + + // using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here + result.set(0, 0, 1 - (yy + zz)); + result.set(0, 1, xy - zw); + result.set(0, 2, xz + yw); + result.set(1, 0, xy + zw); + result.set(1, 1, 1 - (xx + zz)); + result.set(1, 2, yz - xw); + result.set(2, 0, xz - yw); + result.set(2, 1, yz + xw); + result.set(2, 2, 1 - (xx + yy)); + + result.setScale(originalScale); + + return result; + } + /** * fromAngleAxis sets this quaternion to the values specified * by an angle and an axis of rotation. This method creates an object, so diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java index ed31a4c98..28fcda0c7 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java @@ -31,11 +31,15 @@ */ package com.jme3.scene.plugins.blender.math; -import com.jme3.export.*; -import com.jme3.math.Transform; - import java.io.IOException; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.math.Transform; + /** * Started Date: Jul 16, 2004
*
@@ -57,6 +61,12 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl private Vector3d translation; private Vector3d scale; + public DTransform() { + translation = new Vector3d(); + rotation = new DQuaternion(); + scale = new Vector3d(); + } + public DTransform(Transform transform) { translation = new Vector3d(transform.getTranslation()); rotation = new DQuaternion(transform.getRotation()); @@ -66,7 +76,15 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl public Transform toTransform() { return new Transform(translation.toVector3f(), rotation.toQuaternion(), scale.toVector3f()); } - + + public Matrix toMatrix() { + Matrix m = Matrix.identity(4); + m.setTranslation(translation); + m.setRotationQuaternion(rotation); + m.setScale(scale); + return m; + } + /** * Sets this translation to the given value. * @param trans diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java new file mode 100644 index 000000000..5ea580b84 --- /dev/null +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java @@ -0,0 +1,214 @@ +package com.jme3.scene.plugins.blender.math; + +import java.text.DecimalFormat; + +import org.ejml.ops.CommonOps; +import org.ejml.simple.SimpleMatrix; +import org.ejml.simple.SimpleSVD; + +import com.jme3.math.FastMath; + +/** + * Encapsulates a 4x4 matrix + * + * + */ +public class Matrix extends SimpleMatrix { + private static final long serialVersionUID = 2396600537315902559L; + + public Matrix(int rows, int cols) { + super(rows, cols); + } + + /** + * Copy constructor + */ + public Matrix(SimpleMatrix m) { + super(m); + } + + public Matrix(double[][] data) { + super(data); + } + + public static Matrix identity(int size) { + Matrix result = new Matrix(size, size); + CommonOps.setIdentity(result.mat); + return result; + } + + public Matrix pseudoinverse() { + return this.pseudoinverse(1); + } + + @SuppressWarnings("unchecked") + public Matrix pseudoinverse(double lambda) { + SimpleSVD simpleSVD = this.svd(); + + SimpleMatrix U = simpleSVD.getU(); + SimpleMatrix S = simpleSVD.getW(); + SimpleMatrix V = simpleSVD.getV(); + + int N = Math.min(this.numRows(),this.numCols()); + double maxSingular = 0; + for( int i = 0; i < N; i++ ) { + if( S.get(i, i) > maxSingular ) { + maxSingular = S.get(i, i); + } + } + + double tolerance = FastMath.DBL_EPSILON * Math.max(this.numRows(),this.numCols()) * maxSingular; + for(int i=0;isetRotationQuaternion builds a rotation from a + * Quaternion. + * + * @param quat + * the quaternion to build the rotation from. + * @throws NullPointerException + * if quat is null. + */ + public void setRotationQuaternion(DQuaternion quat) { + quat.toRotationMatrix(this); + } + + public DTransform toTransform() { + DTransform result = new DTransform(); + result.setTranslation(this.toTranslationVector()); + result.setRotation(this.toRotationQuat()); + result.setScale(this.toScaleVector()); + return result; + } + + public Vector3d toTranslationVector() { + return new Vector3d(this.get(0, 3), this.get(1, 3), this.get(2, 3)); + } + + public DQuaternion toRotationQuat() { + DQuaternion quat = new DQuaternion(); + quat.fromRotationMatrix(this.get(0, 0), this.get(0, 1), this.get(0, 2), this.get(1, 0), this.get(1, 1), this.get(1, 2), this.get(2, 0), this.get(2, 1), this.get(2, 2)); + return quat; + } + + /** + * Retreives the scale vector from the matrix and stores it into a given + * vector. + * + * @param the + * vector where the scale will be stored + */ + public Vector3d toScaleVector() { + Vector3d result = new Vector3d(); + this.toScaleVector(result); + return result; + } + + /** + * Retreives the scale vector from the matrix and stores it into a given + * vector. + * + * @param the + * vector where the scale will be stored + */ + public void toScaleVector(Vector3d vector) { + double scaleX = Math.sqrt(this.get(0, 0) * this.get(0, 0) + this.get(1, 0) * this.get(1, 0) + this.get(2, 0) * this.get(2, 0)); + double scaleY = Math.sqrt(this.get(0, 1) * this.get(0, 1) + this.get(1, 1) * this.get(1, 1) + this.get(2, 1) * this.get(2, 1)); + double scaleZ = Math.sqrt(this.get(0, 2) * this.get(0, 2) + this.get(1, 2) * this.get(1, 2) + this.get(2, 2) * this.get(2, 2)); + vector.set(scaleX, scaleY, scaleZ); + } +} From b8fe36ed7650473097cc0f8fb58648d4cb725d1b Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Thu, 18 Jun 2015 23:00:17 -0400 Subject: [PATCH 08/27] glsllib with macros to convert glsl 1.1 shaders to 1.5 --- .../Common/ShaderLib/GLSL150Compat.glsllib | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 jme3-core/src/main/resources/Common/ShaderLib/GLSL150Compat.glsllib diff --git a/jme3-core/src/main/resources/Common/ShaderLib/GLSL150Compat.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/GLSL150Compat.glsllib new file mode 100644 index 000000000..336490696 --- /dev/null +++ b/jme3-core/src/main/resources/Common/ShaderLib/GLSL150Compat.glsllib @@ -0,0 +1,14 @@ +#if _VERSION_ >= 150 +out vec4 outFragColor; +# define texture1D texture +# define texture2D texture +# define texture3D texture +# define texture2DLod texture +# if defined VERTEX_SHADER +# define varying out +# define attribute in +# elif defined FRAGMENT_SHADER +# define varying in +# define gl_FragColor outFragColor +# endif +#endif \ No newline at end of file From 43dc7345d0ea32f2cd3d00d520c6a4b0dfb10f9c Mon Sep 17 00:00:00 2001 From: zzuegg Date: Fri, 19 Jun 2015 22:21:56 +0200 Subject: [PATCH 09/27] Changed to VertexUniformVectors --- jme3-core/src/main/java/com/jme3/renderer/Limits.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/Limits.java b/jme3-core/src/main/java/com/jme3/renderer/Limits.java index 7df9bc76b..86cddb178 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Limits.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Limits.java @@ -76,5 +76,5 @@ public enum Limits { DepthTextureSamples, - VertexUniformComponents, + VertexUniformVectors, } From 4cd0c5bffb17e8e7883c95eac03a5937c517464b Mon Sep 17 00:00:00 2001 From: zzuegg Date: Fri, 19 Jun 2015 22:22:40 +0200 Subject: [PATCH 10/27] Added MAX_VERTEX_UNIFORM_VECTORS constant //untested however --- jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java index 21eedab52..04f496332 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java @@ -100,6 +100,7 @@ public interface GL { public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869; public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A; + public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; public static final int GL_MIRRORED_REPEAT = 0x8370; public static final int GL_NEAREST = 0x2600; public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; From 8cb2be60feeeeea425759db9f3fc4d5208a91778 Mon Sep 17 00:00:00 2001 From: zzuegg Date: Fri, 19 Jun 2015 22:26:12 +0200 Subject: [PATCH 11/27] Added a switch to use VECTORS on GLES and COMPONENTS/4 on Desktop --- .../com/jme3/renderer/opengl/GLRenderer.java | 367 +++++++++--------- 1 file changed, 193 insertions(+), 174 deletions(-) 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 caf472543..2da5e28f9 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 @@ -56,6 +56,7 @@ import com.jme3.util.BufferUtils; import com.jme3.util.ListMap; import com.jme3.util.MipMapGenerator; import com.jme3.util.NativeObjectManager; + import java.nio.*; import java.util.Arrays; import java.util.EnumMap; @@ -66,6 +67,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; + import jme3tools.shader.ShaderDebug; public class GLRenderer implements Renderer { @@ -73,7 +75,7 @@ public class GLRenderer implements Renderer { private static final Logger logger = Logger.getLogger(GLRenderer.class.getName()); private static final boolean VALIDATE_SHADER = false; private static final Pattern GLVERSION_PATTERN = Pattern.compile(".*?(\\d+)\\.(\\d+).*"); - + private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); private final StringBuilder stringBuf = new StringBuilder(250); private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); @@ -83,7 +85,7 @@ public class GLRenderer implements Renderer { private final NativeObjectManager objManager = new NativeObjectManager(); private final EnumSet caps = EnumSet.noneOf(Caps.class); private final EnumMap limits = new EnumMap(Limits.class); - + private FrameBuffer mainFbOverride = null; private final Statistics statistics = new Statistics(); private int vpX, vpY, vpW, vpH; @@ -98,12 +100,12 @@ public class GLRenderer implements Renderer { private final GLExt glext; private final GLFbo glfbo; private final TextureUtil texUtil; - + public GLRenderer(GL gl, GLExt glext, GLFbo glfbo) { this.gl = gl; - this.gl2 = gl instanceof GL2 ? (GL2)gl : null; - this.gl3 = gl instanceof GL3 ? (GL3)gl : null; - this.gl4 = gl instanceof GL4 ? (GL4)gl : null; + this.gl2 = gl instanceof GL2 ? (GL2) gl : null; + this.gl3 = gl instanceof GL3 ? (GL3) gl : null; + this.gl4 = gl instanceof GL4 ? (GL4) gl : null; this.glfbo = glfbo; this.glext = glext; this.texUtil = new TextureUtil(gl, gl2, glext, context); @@ -118,7 +120,7 @@ public class GLRenderer implements Renderer { public EnumSet getCaps() { return caps; } - + // Not making public yet ... public EnumMap getLimits() { return limits; @@ -140,7 +142,7 @@ public class GLRenderer implements Renderer { } return extensionSet; } - + public static int extractVersion(String version) { Matcher m = GLVERSION_PATTERN.matcher(version); if (m.matches()) { @@ -160,17 +162,17 @@ public class GLRenderer implements Renderer { private boolean hasExtension(String extensionName) { return extensions.contains(extensionName); } - + private void loadCapabilitiesES() { caps.add(Caps.GLSL100); caps.add(Caps.OpenGLES20); - + // Important: Do not add OpenGL20 - that's the desktop capability! } - + private void loadCapabilitiesGL2() { int oglVer = extractVersion(gl.glGetString(GL.GL_VERSION)); - + if (oglVer >= 200) { caps.add(Caps.OpenGL20); if (oglVer >= 210) { @@ -194,7 +196,7 @@ public class GLRenderer implements Renderer { } } } - + int glslVer = extractVersion(gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)); switch (glslVer) { @@ -222,27 +224,27 @@ public class GLRenderer implements Renderer { caps.add(Caps.GLSL100); break; } - + // Workaround, always assume we support GLSL100 & GLSL110 // Supporting OpenGL 2.0 means supporting GLSL 1.10. caps.add(Caps.GLSL110); caps.add(Caps.GLSL100); - + // Fix issue in TestRenderToMemory when GL.GL_FRONT is the main // buffer being used. context.initialDrawBuf = getInteger(GL2.GL_DRAW_BUFFER); context.initialReadBuf = getInteger(GL2.GL_READ_BUFFER); - + // XXX: This has to be GL.GL_BACK for canvas on Mac // Since initialDrawBuf is GL.GL_FRONT for pbuffer, gotta // change this value later on ... // initialDrawBuf = GL.GL_BACK; // initialReadBuf = GL.GL_BACK; } - + private void loadCapabilitiesCommon() { extensions = loadExtensions(); - + limits.put(Limits.VertexTextureUnits, getInteger(GL.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)); if (limits.get(Limits.VertexTextureUnits) > 0) { caps.add(Caps.VertexTextureFetch); @@ -257,62 +259,66 @@ public class GLRenderer implements Renderer { // gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); // fragUniforms = intBuf16.get(0); // logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); - limits.put(Limits.VertexUniformComponents,getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS)); + if (caps.contains(Caps.OpenGLES20)) { + limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_VECTORS)); + } else { + limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4); + } limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS)); limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE)); limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE)); - if (hasExtension("GL_ARB_draw_instanced") && - hasExtension("GL_ARB_instanced_arrays")) { + if (hasExtension("GL_ARB_draw_instanced") && + hasExtension("GL_ARB_instanced_arrays")) { caps.add(Caps.MeshInstancing); } if (hasExtension("GL_OES_element_index_uint") || gl2 != null) { caps.add(Caps.IntegerIndexBuffer); } - + if (hasExtension("GL_ARB_texture_buffer_object")) { caps.add(Caps.TextureBuffer); } - + // == texture format extensions == - + boolean hasFloatTexture; hasFloatTexture = hasExtension("GL_OES_texture_half_float") && - hasExtension("GL_OES_texture_float"); - + hasExtension("GL_OES_texture_float"); + if (!hasFloatTexture) { hasFloatTexture = hasExtension("GL_ARB_texture_float") && - hasExtension("GL_ARB_half_float_pixel"); - + hasExtension("GL_ARB_half_float_pixel"); + if (!hasFloatTexture) { hasFloatTexture = caps.contains(Caps.OpenGL30); } } - + if (hasFloatTexture) { caps.add(Caps.FloatTexture); } - + if (hasExtension("GL_OES_depth_texture") || gl2 != null) { caps.add(Caps.DepthTexture); - + // TODO: GL_OES_depth24 } - - if (hasExtension("GL_OES_rgb8_rgba8") || - hasExtension("GL_ARM_rgba8") || - hasExtension("GL_EXT_texture_format_BGRA8888")) { + + if (hasExtension("GL_OES_rgb8_rgba8") || + hasExtension("GL_ARM_rgba8") || + hasExtension("GL_EXT_texture_format_BGRA8888")) { caps.add(Caps.Rgba8); } - + if (caps.contains(Caps.OpenGL30) || hasExtension("GL_OES_packed_depth_stencil")) { caps.add(Caps.PackedDepthStencilBuffer); } if (hasExtension("GL_ARB_color_buffer_float") && - hasExtension("GL_ARB_half_float_pixel")) { + hasExtension("GL_ARB_half_float_pixel")) { // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. caps.add(Caps.FloatColorBuffer); } @@ -321,44 +327,44 @@ public class GLRenderer implements Renderer { caps.add(Caps.FloatDepthBuffer); } - if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) || - caps.contains(Caps.OpenGL30)) { + if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) || + caps.contains(Caps.OpenGL30)) { // Either OpenGL3 is available or both packed_float & half_float_pixel. caps.add(Caps.PackedFloatColorBuffer); caps.add(Caps.PackedFloatTexture); } - + if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.SharedExponentTexture); } - + if (hasExtension("GL_EXT_texture_compression_s3tc")) { caps.add(Caps.TextureCompressionS3TC); } - + if (hasExtension("GL_ARB_ES3_compatibility")) { caps.add(Caps.TextureCompressionETC2); caps.add(Caps.TextureCompressionETC1); } else if (hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) { caps.add(Caps.TextureCompressionETC1); } - + // == end texture format extensions == - + if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.VertexBufferArray); } - if (hasExtension("GL_ARB_texture_non_power_of_two") || - hasExtension("GL_OES_texture_npot") || - caps.contains(Caps.OpenGL30)) { + if (hasExtension("GL_ARB_texture_non_power_of_two") || + hasExtension("GL_OES_texture_npot") || + 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."); + + "support non-power-of-2 textures. " + + "Some features might not work."); } - + if (caps.contains(Caps.OpenGLES20)) { // OpenGL ES 2 has some limited support for NPOT textures caps.add(Caps.PartialNonPowerOfTwoTextures); @@ -374,14 +380,14 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_EXT_framebuffer_object") || gl3 != null) { caps.add(Caps.FrameBuffer); - + limits.put(Limits.RenderBufferSize, getInteger(GLFbo.GL_MAX_RENDERBUFFER_SIZE_EXT)); limits.put(Limits.FrameBufferAttachments, getInteger(GLFbo.GL_MAX_COLOR_ATTACHMENTS_EXT)); - + if (hasExtension("GL_EXT_framebuffer_blit")) { caps.add(Caps.FrameBufferBlit); } - + if (hasExtension("GL_EXT_framebuffer_multisample")) { caps.add(Caps.FrameBufferMultisample); limits.put(Limits.FrameBufferSamples, getInteger(GLExt.GL_MAX_SAMPLES_EXT)); @@ -419,10 +425,10 @@ public class GLRenderer implements Renderer { } caps.add(Caps.Multisample); } - + // Supports sRGB pipeline. - if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) - || caps.contains(Caps.OpenGL30) ) { + if ((hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) + || caps.contains(Caps.OpenGL30)) { caps.add(Caps.Srgb); } @@ -430,47 +436,46 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_ARB_seamless_cube_map") || caps.contains(Caps.OpenGL32)) { caps.add(Caps.SeamlessCubemap); } - + if (caps.contains(Caps.OpenGL32) && !hasExtension("GL_ARB_compatibility")) { caps.add(Caps.CoreProfile); } - + if (hasExtension("GL_ARB_get_program_binary")) { int binaryFormats = getInteger(GLExt.GL_NUM_PROGRAM_BINARY_FORMATS); if (binaryFormats > 0) { caps.add(Caps.BinaryShader); } } - + // Print context information logger.log(Level.INFO, "OpenGL Renderer Information\n" + - " * Vendor: {0}\n" + - " * Renderer: {1}\n" + - " * OpenGL Version: {2}\n" + - " * GLSL Version: {3}\n" + - " * Profile: {4}", - new Object[]{ - gl.glGetString(GL.GL_VENDOR), - gl.glGetString(GL.GL_RENDERER), - gl.glGetString(GL.GL_VERSION), - gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION), - caps.contains(Caps.CoreProfile) ? "Core" : "Compatibility" - }); - + " * Vendor: {0}\n" + + " * Renderer: {1}\n" + + " * OpenGL Version: {2}\n" + + " * GLSL Version: {3}\n" + + " * Profile: {4}", + new Object[]{ + gl.glGetString(GL.GL_VENDOR), + gl.glGetString(GL.GL_RENDERER), + gl.glGetString(GL.GL_VERSION), + gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION), + caps.contains(Caps.CoreProfile) ? "Core" : "Compatibility" + }); + // Print capabilities (if fine logging is enabled) if (logger.isLoggable(Level.FINE)) { StringBuilder sb = new StringBuilder(); sb.append("Supported capabilities: \n"); - for (Caps cap : caps) - { + for (Caps cap : caps) { sb.append("\t").append(cap.toString()).append("\n"); } logger.log(Level.FINE, sb.toString()); } - + texUtil.initialize(caps); } - + private void loadCapabilities() { if (gl2 != null) { loadCapabilitiesGL2(); @@ -479,31 +484,31 @@ public class GLRenderer implements Renderer { } loadCapabilitiesCommon(); } - + private int getInteger(int en) { intBuf16.clear(); gl.glGetInteger(en, intBuf16); return intBuf16.get(0); } - + private boolean getBoolean(int en) { gl.glGetBoolean(en, nameBuf); - return nameBuf.get(0) != (byte)0; + return nameBuf.get(0) != (byte) 0; } - + @SuppressWarnings("fallthrough") public void initialize() { loadCapabilities(); - + // Initialize default state.. gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); - + if (caps.contains(Caps.CoreProfile)) { // Core Profile requires VAO to be bound. gl3.glGenVertexArrays(intBuf16); int vaoId = intBuf16.get(0); gl3.glBindVertexArray(vaoId); - } + } if (gl2 != null) { gl2.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE); if (!caps.contains(Caps.CoreProfile)) { @@ -535,9 +540,11 @@ public class GLRenderer implements Renderer { invalidateState(); } - /*********************************************************************\ - |* Render State *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Render State *| + * \******************************************************************** + */ public void setDepthRange(float start, float end) { gl.glDepthRange(start, end); } @@ -602,7 +609,7 @@ public class GLRenderer implements Renderer { } if (state.isDepthTest() && !context.depthTestEnabled) { - gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(convertTestFunction(context.depthFunc)); context.depthTestEnabled = true; } else if (!state.isDepthTest() && context.depthTestEnabled) { @@ -714,7 +721,7 @@ public class GLRenderer implements Renderer { case Color: case Screen: gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR); - break; + break; case Exclusion: gl.glBlendFunc(GL.GL_ONE_MINUS_DST_COLOR, GL.GL_ONE_MINUS_SRC_COLOR); break; @@ -814,9 +821,11 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Camera and World transforms *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Camera and World transforms *| + * \******************************************************************** + */ public void setViewPort(int x, int y, int w, int h) { if (x != vpX || vpY != y || vpW != w || vpH != h) { gl.glViewport(x, y, w, h); @@ -858,9 +867,11 @@ public class GLRenderer implements Renderer { gl.resetStats(); } - /*********************************************************************\ - |* Shaders *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Shaders *| + * \******************************************************************** + */ protected void updateUniformLocation(Shader shader, Uniform uniform) { int loc = gl.glGetUniformLocation(shader.getId(), uniform.getName()); if (loc < 0) { @@ -1040,12 +1051,12 @@ public class GLRenderer implements Renderer { boolean gles2 = caps.contains(Caps.OpenGLES20); String language = source.getLanguage(); - + if (gles2 && !language.equals("GLSL100")) { throw new RendererException("This shader cannot run in OpenGL ES 2. " - + "Only GLSL 1.00 shaders are supported."); + + "Only GLSL 1.00 shaders are supported."); } - + // Upload shader source. // Merge the defines and source code. stringBuf.setLength(0); @@ -1072,17 +1083,17 @@ public class GLRenderer implements Renderer { } } } - + if (linearizeSrgbImages) { stringBuf.append("#define SRGB 1\n"); } - + stringBuf.append(source.getDefines()); stringBuf.append(source.getSource()); - + intBuf1.clear(); intBuf1.put(0, stringBuf.length()); - gl.glShaderSource(id, new String[]{ stringBuf.toString() }, intBuf1); + gl.glShaderSource(id, new String[]{stringBuf.toString()}, intBuf1); gl.glCompileShader(id); gl.glGetShader(id, GL.GL_COMPILE_STATUS, intBuf1); @@ -1137,7 +1148,7 @@ public class GLRenderer implements Renderer { // If using GLSL 1.5, we bind the outputs for the user // For versions 3.3 and up, user should use layout qualifiers instead. boolean bindFragDataRequired = false; - + for (ShaderSource source : shader.getSources()) { if (source.isUpdateNeeded()) { updateShaderSourceData(source); @@ -1245,9 +1256,11 @@ public class GLRenderer implements Renderer { shader.resetObject(); } - /*********************************************************************\ - |* Framebuffers *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Framebuffers *| + * \******************************************************************** + */ public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { copyFrameBuffer(src, dst, true); } @@ -1402,7 +1415,7 @@ public class GLRenderer implements Renderer { } else if (attachmentSlot < 0 || attachmentSlot >= 16) { throw new UnsupportedOperationException("Invalid FBO attachment slot: " + attachmentSlot); } - + return GLFbo.GL_COLOR_ATTACHMENT0_EXT + attachmentSlot; } @@ -1412,7 +1425,7 @@ public class GLRenderer implements Renderer { if (image.isUpdateNeeded()) { // Check NPOT requirements checkNonPowerOfTwo(tex); - + updateTexImageData(image, tex.getType(), 0, false); // NOTE: For depth textures, sets nearest/no-mips mode @@ -1476,7 +1489,7 @@ public class GLRenderer implements Renderer { } checkFrameBufferError(); - + fb.clearUpdateNeeded(); } @@ -1569,7 +1582,7 @@ public class GLRenderer implements Renderer { // update viewport to reflect framebuffer's resolution setViewPort(0, 0, fb.getWidth(), fb.getHeight()); - + if (context.boundFBO != fb.getId()) { glfbo.glBindFramebufferEXT(GLFbo.GL_FRAMEBUFFER_EXT, fb.getId()); statistics.onFrameBufferUse(fb, true); @@ -1640,7 +1653,7 @@ public class GLRenderer implements Renderer { public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { readFrameBufferWithGLFormat(fb, byteBuf, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); } - + private void readFrameBufferWithGLFormat(FrameBuffer fb, ByteBuffer byteBuf, int glFormat, int dataType) { if (fb != null) { RenderBuffer rb = fb.getColorBuffer(); @@ -1662,8 +1675,8 @@ public class GLRenderer implements Renderer { gl.glReadPixels(vpX, vpY, vpW, vpH, glFormat, dataType, byteBuf); } - - public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { GLImageFormat glFormat = texUtil.getImageFormatWithError(format, false); readFrameBufferWithGLFormat(fb, byteBuf, glFormat.format, glFormat.dataType); } @@ -1695,15 +1708,17 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Textures *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* 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."); + throw new RendererException("Multisample textures are not supported" + + " by the video hardware."); } - + switch (type) { case TwoDimensional: if (samples > 1) { @@ -1723,8 +1738,8 @@ public class GLRenderer implements Renderer { } case ThreeDimensional: if (!caps.contains(Caps.OpenGL20)) { - throw new RendererException("3D textures are not supported" + - " by the video hardware."); + throw new RendererException("3D textures are not supported" + + " by the video hardware."); } return GL2.GL_TEXTURE_3D; case CubeMap: @@ -1752,7 +1767,7 @@ public class GLRenderer implements Renderer { } private int convertMinFilter(Texture.MinFilter filter, boolean haveMips) { - if (haveMips){ + if (haveMips) { switch (filter) { case Trilinear: return GL.GL_LINEAR_MIPMAP_LINEAR; @@ -1807,11 +1822,11 @@ public class GLRenderer implements Renderer { int target = convertTextureType(tex.getType(), image != null ? image.getMultiSamples() : 1, -1); boolean haveMips = true; - + if (image != null) { haveMips = image.isGeneratedMipmapsRequired() || image.hasMipmaps(); } - + // filter things if (image.getLastTextureState().magFilter != tex.getMagFilter()) { int magFilter = convertMagFilter(tex.getMagFilter()); @@ -1834,7 +1849,7 @@ public class GLRenderer implements Renderer { context.seamlessCubemap = false; } } - + if (tex.getAnisotropicFilter() > 1) { if (caps.contains(Caps.TextureFilterAnisotropic)) { gl.glTexParameterf(target, @@ -1867,19 +1882,19 @@ public class GLRenderer implements Renderer { throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); } - if(tex.isNeedCompareModeUpdate() && gl2 != null){ + if (tex.isNeedCompareModeUpdate() && gl2 != null) { // R to Texture compare mode if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off) { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL2.GL_COMPARE_R_TO_TEXTURE); - gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY); + gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY); if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual) { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_GEQUAL); } else { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_LEQUAL); } - }else{ - //restoring default value - gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); + } else { + //restoring default value + gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); } tex.compareModeUpdated(); } @@ -1888,10 +1903,10 @@ public class GLRenderer implements Renderer { /** * Validates if a potentially NPOT texture is supported by the hardware. *

- * Textures with power-of-2 dimensions are supported on all hardware, however + * Textures with power-of-2 dimensions are supported on all hardware, however * non-power-of-2 textures may or may not be supported depending on which * texturing features are used. - * + * * @param tex The texture to validate. * @throws RendererException If the texture is not supported by the hardware */ @@ -1900,23 +1915,23 @@ public class GLRenderer implements Renderer { // Texture is power-of-2, safe to use. return; } - + if (caps.contains(Caps.NonPowerOfTwoTextures)) { // Texture is NPOT but it is supported by video hardware. return; } - + // Maybe we have some / partial support for NPOT? if (!caps.contains(Caps.PartialNonPowerOfTwoTextures)) { // Cannot use any type of NPOT texture (uncommon) throw new RendererException("non-power-of-2 textures are not " - + "supported by the video hardware"); + + "supported by the video hardware"); } - + // Partial NPOT supported.. if (tex.getMinFilter().usesMipMapLevels()) { throw new RendererException("non-power-of-2 textures with mip-maps " - + "are not supported by the video hardware"); + + "are not supported by the video hardware"); } switch (tex.getType()) { @@ -1924,7 +1939,7 @@ public class GLRenderer implements Renderer { case ThreeDimensional: if (tex.getWrap(WrapAxis.R) != Texture.WrapMode.EdgeClamp) { throw new RendererException("repeating non-power-of-2 textures " - + "are not supported by the video hardware"); + + "are not supported by the video hardware"); } // fallthrough intentional!!! case TwoDimensionalArray: @@ -1932,22 +1947,22 @@ public class GLRenderer implements Renderer { if (tex.getWrap(WrapAxis.S) != Texture.WrapMode.EdgeClamp || tex.getWrap(WrapAxis.T) != Texture.WrapMode.EdgeClamp) { throw new RendererException("repeating non-power-of-2 textures " - + "are not supported by the video hardware"); + + "are not supported by the video hardware"); } break; default: throw new UnsupportedOperationException("unrecongized texture type"); } } - + /** * 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 + * + * @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 * @param scaleToPot If true, the image will be scaled to power-of-2 dimensions - * before being uploaded. + * before being uploaded. */ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean scaleToPot) { int texId = img.getId(); @@ -1968,7 +1983,7 @@ public class GLRenderer implements Renderer { gl.glActiveTexture(GL.GL_TEXTURE0 + unit); context.boundTextureUnit = unit; } - + gl.glBindTexture(target, texId); context.boundTextures[unit] = img; @@ -2011,12 +2026,12 @@ public class GLRenderer implements Renderer { throw new RendererException("Multisample textures are not supported by the video hardware"); } } - + // Check if graphics card doesn't support depth textures if (img.getFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) { throw new RendererException("Depth textures are not supported by the video hardware"); } - + if (target == GL.GL_TEXTURE_CUBE_MAP) { // Check max texture size before upload int cubeSize = limits.get(Limits.CubemapSize); @@ -2053,12 +2068,12 @@ public class GLRenderer implements Renderer { if (!caps.contains(Caps.TextureArray)) { throw new RendererException("Texture arrays not supported by graphics hardware"); } - + List data = imageForUpload.getData(); - + // -1 index specifies prepare data for 2D Array texUtil.uploadTexture(imageForUpload, target, -1, linearizeSrgbImages); - + for (int i = 0; i < data.size(); i++) { // upload each slice of 2D array in turn // this time with the appropriate index @@ -2087,21 +2102,21 @@ public class GLRenderer implements Renderer { if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) { // Check NPOT requirements boolean scaleToPot = false; - + try { checkNonPowerOfTwo(tex); } catch (RendererException ex) { if (logger.isLoggable(Level.WARNING)) { int nextWidth = FastMath.nearestPowerOfTwo(tex.getImage().getWidth()); int nextHeight = FastMath.nearestPowerOfTwo(tex.getImage().getHeight()); - logger.log(Level.WARNING, - "Non-power-of-2 textures are not supported! Scaling texture '" + tex.getName() + - "' of size " + tex.getImage().getWidth() + "x" + tex.getImage().getHeight() + - " to " + nextWidth + "x" + nextHeight); + logger.log(Level.WARNING, + "Non-power-of-2 textures are not supported! Scaling texture '" + tex.getName() + + "' of size " + tex.getImage().getWidth() + "x" + tex.getImage().getHeight() + + " to " + nextWidth + "x" + nextHeight); } scaleToPot = true; } - + updateTexImageData(image, tex.getType(), unit, scaleToPot); } @@ -2146,9 +2161,11 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Vertex Buffers and Attributes *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Vertex Buffers and Attributes *| + * \******************************************************************** + */ private int convertUsage(Usage usage) { switch (usage) { case Static: @@ -2222,7 +2239,7 @@ public class GLRenderer implements Renderer { //statistics.onVertexBufferUse(vb, false); } } - + int usage = convertUsage(vb.getUsage()); vb.getData().rewind(); @@ -2283,7 +2300,7 @@ public class GLRenderer implements Renderer { if (context.boundShaderProgram <= 0) { throw new IllegalStateException("Cannot render mesh without shader bound"); } - + Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); int loc = attrib.getLocation(); if (loc == -1) { @@ -2413,7 +2430,7 @@ public class GLRenderer implements Renderer { // What is this? throw new RendererException("Unexpected format for index buffer: " + indexBuf.getFormat()); } - + if (indexBuf.isUpdateNeeded()) { updateBufferData(indexBuf); } @@ -2486,9 +2503,11 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Render Calls *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Render Calls *| + * \******************************************************************** + */ public int convertElementMode(Mesh.Mode mode) { switch (mode) { case Points: @@ -2530,7 +2549,7 @@ public class GLRenderer implements Renderer { if (interleavedData != null && interleavedData.isUpdateNeeded()) { updateBufferData(interleavedData); } - + if (instanceData != null) { setVertexAttrib(instanceData, null); } @@ -2580,11 +2599,11 @@ public class GLRenderer implements Renderer { } 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); @@ -2602,7 +2621,7 @@ public class GLRenderer implements Renderer { setVertexAttrib(vb, null); } } - + for (VertexBuffer vb : mesh.getBufferList().getArray()) { if (vb.getBufferType() == Type.InterleavedData || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers @@ -2637,7 +2656,7 @@ public class GLRenderer implements Renderer { gl.glLineWidth(mesh.getLineWidth()); context.lineWidth = mesh.getLineWidth(); } - + if (gl4 != null && mesh.getMode().equals(Mode.Patch)) { gl4.glPatchParameter(mesh.getPatchVertexCount()); } @@ -2653,12 +2672,12 @@ public class GLRenderer implements Renderer { // Gamma correction if (!caps.contains(Caps.Srgb) && enableSrgb) { // Not supported, sorry. - logger.warning("sRGB framebuffer is not supported " + - "by video hardware, but was requested."); - + logger.warning("sRGB framebuffer is not supported " + + "by video hardware, but was requested."); + return; } - + setFrameBuffer(null); if (enableSrgb) { From 1e0468bdbe4a1f48a24fc426531c87a3a36c4023 Mon Sep 17 00:00:00 2001 From: zzuegg Date: Fri, 19 Jun 2015 23:07:28 +0200 Subject: [PATCH 12/27] Removed empty lines --- .../com/jme3/renderer/opengl/GLRenderer.java | 365 +++++++++--------- 1 file changed, 191 insertions(+), 174 deletions(-) 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 caf472543..23d3eea17 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 @@ -73,7 +73,7 @@ public class GLRenderer implements Renderer { private static final Logger logger = Logger.getLogger(GLRenderer.class.getName()); private static final boolean VALIDATE_SHADER = false; private static final Pattern GLVERSION_PATTERN = Pattern.compile(".*?(\\d+)\\.(\\d+).*"); - + private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); private final StringBuilder stringBuf = new StringBuilder(250); private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); @@ -83,7 +83,7 @@ public class GLRenderer implements Renderer { private final NativeObjectManager objManager = new NativeObjectManager(); private final EnumSet caps = EnumSet.noneOf(Caps.class); private final EnumMap limits = new EnumMap(Limits.class); - + private FrameBuffer mainFbOverride = null; private final Statistics statistics = new Statistics(); private int vpX, vpY, vpW, vpH; @@ -98,12 +98,12 @@ public class GLRenderer implements Renderer { private final GLExt glext; private final GLFbo glfbo; private final TextureUtil texUtil; - + public GLRenderer(GL gl, GLExt glext, GLFbo glfbo) { this.gl = gl; - this.gl2 = gl instanceof GL2 ? (GL2)gl : null; - this.gl3 = gl instanceof GL3 ? (GL3)gl : null; - this.gl4 = gl instanceof GL4 ? (GL4)gl : null; + this.gl2 = gl instanceof GL2 ? (GL2) gl : null; + this.gl3 = gl instanceof GL3 ? (GL3) gl : null; + this.gl4 = gl instanceof GL4 ? (GL4) gl : null; this.glfbo = glfbo; this.glext = glext; this.texUtil = new TextureUtil(gl, gl2, glext, context); @@ -118,7 +118,7 @@ public class GLRenderer implements Renderer { public EnumSet getCaps() { return caps; } - + // Not making public yet ... public EnumMap getLimits() { return limits; @@ -140,7 +140,7 @@ public class GLRenderer implements Renderer { } return extensionSet; } - + public static int extractVersion(String version) { Matcher m = GLVERSION_PATTERN.matcher(version); if (m.matches()) { @@ -160,17 +160,17 @@ public class GLRenderer implements Renderer { private boolean hasExtension(String extensionName) { return extensions.contains(extensionName); } - + private void loadCapabilitiesES() { caps.add(Caps.GLSL100); caps.add(Caps.OpenGLES20); - + // Important: Do not add OpenGL20 - that's the desktop capability! } - + private void loadCapabilitiesGL2() { int oglVer = extractVersion(gl.glGetString(GL.GL_VERSION)); - + if (oglVer >= 200) { caps.add(Caps.OpenGL20); if (oglVer >= 210) { @@ -194,7 +194,7 @@ public class GLRenderer implements Renderer { } } } - + int glslVer = extractVersion(gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)); switch (glslVer) { @@ -222,27 +222,27 @@ public class GLRenderer implements Renderer { caps.add(Caps.GLSL100); break; } - + // Workaround, always assume we support GLSL100 & GLSL110 // Supporting OpenGL 2.0 means supporting GLSL 1.10. caps.add(Caps.GLSL110); caps.add(Caps.GLSL100); - + // Fix issue in TestRenderToMemory when GL.GL_FRONT is the main // buffer being used. context.initialDrawBuf = getInteger(GL2.GL_DRAW_BUFFER); context.initialReadBuf = getInteger(GL2.GL_READ_BUFFER); - + // XXX: This has to be GL.GL_BACK for canvas on Mac // Since initialDrawBuf is GL.GL_FRONT for pbuffer, gotta // change this value later on ... // initialDrawBuf = GL.GL_BACK; // initialReadBuf = GL.GL_BACK; } - + private void loadCapabilitiesCommon() { extensions = loadExtensions(); - + limits.put(Limits.VertexTextureUnits, getInteger(GL.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)); if (limits.get(Limits.VertexTextureUnits) > 0) { caps.add(Caps.VertexTextureFetch); @@ -257,62 +257,66 @@ public class GLRenderer implements Renderer { // gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); // fragUniforms = intBuf16.get(0); // logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); - limits.put(Limits.VertexUniformComponents,getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS)); + if (caps.contains(Caps.OpenGLES20)) { + limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_VECTORS)); + } else { + limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4); + } limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS)); limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE)); limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE)); - if (hasExtension("GL_ARB_draw_instanced") && - hasExtension("GL_ARB_instanced_arrays")) { + if (hasExtension("GL_ARB_draw_instanced") && + hasExtension("GL_ARB_instanced_arrays")) { caps.add(Caps.MeshInstancing); } if (hasExtension("GL_OES_element_index_uint") || gl2 != null) { caps.add(Caps.IntegerIndexBuffer); } - + if (hasExtension("GL_ARB_texture_buffer_object")) { caps.add(Caps.TextureBuffer); } - + // == texture format extensions == - + boolean hasFloatTexture; hasFloatTexture = hasExtension("GL_OES_texture_half_float") && - hasExtension("GL_OES_texture_float"); - + hasExtension("GL_OES_texture_float"); + if (!hasFloatTexture) { hasFloatTexture = hasExtension("GL_ARB_texture_float") && - hasExtension("GL_ARB_half_float_pixel"); - + hasExtension("GL_ARB_half_float_pixel"); + if (!hasFloatTexture) { hasFloatTexture = caps.contains(Caps.OpenGL30); } } - + if (hasFloatTexture) { caps.add(Caps.FloatTexture); } - + if (hasExtension("GL_OES_depth_texture") || gl2 != null) { caps.add(Caps.DepthTexture); - + // TODO: GL_OES_depth24 } - - if (hasExtension("GL_OES_rgb8_rgba8") || - hasExtension("GL_ARM_rgba8") || - hasExtension("GL_EXT_texture_format_BGRA8888")) { + + if (hasExtension("GL_OES_rgb8_rgba8") || + hasExtension("GL_ARM_rgba8") || + hasExtension("GL_EXT_texture_format_BGRA8888")) { caps.add(Caps.Rgba8); } - + if (caps.contains(Caps.OpenGL30) || hasExtension("GL_OES_packed_depth_stencil")) { caps.add(Caps.PackedDepthStencilBuffer); } if (hasExtension("GL_ARB_color_buffer_float") && - hasExtension("GL_ARB_half_float_pixel")) { + hasExtension("GL_ARB_half_float_pixel")) { // XXX: Require both 16 and 32 bit float support for FloatColorBuffer. caps.add(Caps.FloatColorBuffer); } @@ -321,44 +325,44 @@ public class GLRenderer implements Renderer { caps.add(Caps.FloatDepthBuffer); } - if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) || - caps.contains(Caps.OpenGL30)) { + if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) || + caps.contains(Caps.OpenGL30)) { // Either OpenGL3 is available or both packed_float & half_float_pixel. caps.add(Caps.PackedFloatColorBuffer); caps.add(Caps.PackedFloatTexture); } - + if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.SharedExponentTexture); } - + if (hasExtension("GL_EXT_texture_compression_s3tc")) { caps.add(Caps.TextureCompressionS3TC); } - + if (hasExtension("GL_ARB_ES3_compatibility")) { caps.add(Caps.TextureCompressionETC2); caps.add(Caps.TextureCompressionETC1); } else if (hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) { caps.add(Caps.TextureCompressionETC1); } - + // == end texture format extensions == - + if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30)) { caps.add(Caps.VertexBufferArray); } - if (hasExtension("GL_ARB_texture_non_power_of_two") || - hasExtension("GL_OES_texture_npot") || - caps.contains(Caps.OpenGL30)) { + if (hasExtension("GL_ARB_texture_non_power_of_two") || + hasExtension("GL_OES_texture_npot") || + 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."); + + "support non-power-of-2 textures. " + + "Some features might not work."); } - + if (caps.contains(Caps.OpenGLES20)) { // OpenGL ES 2 has some limited support for NPOT textures caps.add(Caps.PartialNonPowerOfTwoTextures); @@ -374,14 +378,14 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_EXT_framebuffer_object") || gl3 != null) { caps.add(Caps.FrameBuffer); - + limits.put(Limits.RenderBufferSize, getInteger(GLFbo.GL_MAX_RENDERBUFFER_SIZE_EXT)); limits.put(Limits.FrameBufferAttachments, getInteger(GLFbo.GL_MAX_COLOR_ATTACHMENTS_EXT)); - + if (hasExtension("GL_EXT_framebuffer_blit")) { caps.add(Caps.FrameBufferBlit); } - + if (hasExtension("GL_EXT_framebuffer_multisample")) { caps.add(Caps.FrameBufferMultisample); limits.put(Limits.FrameBufferSamples, getInteger(GLExt.GL_MAX_SAMPLES_EXT)); @@ -419,10 +423,10 @@ public class GLRenderer implements Renderer { } caps.add(Caps.Multisample); } - + // Supports sRGB pipeline. - if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) - || caps.contains(Caps.OpenGL30) ) { + if ((hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) + || caps.contains(Caps.OpenGL30)) { caps.add(Caps.Srgb); } @@ -430,47 +434,46 @@ public class GLRenderer implements Renderer { if (hasExtension("GL_ARB_seamless_cube_map") || caps.contains(Caps.OpenGL32)) { caps.add(Caps.SeamlessCubemap); } - + if (caps.contains(Caps.OpenGL32) && !hasExtension("GL_ARB_compatibility")) { caps.add(Caps.CoreProfile); } - + if (hasExtension("GL_ARB_get_program_binary")) { int binaryFormats = getInteger(GLExt.GL_NUM_PROGRAM_BINARY_FORMATS); if (binaryFormats > 0) { caps.add(Caps.BinaryShader); } } - + // Print context information logger.log(Level.INFO, "OpenGL Renderer Information\n" + - " * Vendor: {0}\n" + - " * Renderer: {1}\n" + - " * OpenGL Version: {2}\n" + - " * GLSL Version: {3}\n" + - " * Profile: {4}", - new Object[]{ - gl.glGetString(GL.GL_VENDOR), - gl.glGetString(GL.GL_RENDERER), - gl.glGetString(GL.GL_VERSION), - gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION), - caps.contains(Caps.CoreProfile) ? "Core" : "Compatibility" - }); - + " * Vendor: {0}\n" + + " * Renderer: {1}\n" + + " * OpenGL Version: {2}\n" + + " * GLSL Version: {3}\n" + + " * Profile: {4}", + new Object[]{ + gl.glGetString(GL.GL_VENDOR), + gl.glGetString(GL.GL_RENDERER), + gl.glGetString(GL.GL_VERSION), + gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION), + caps.contains(Caps.CoreProfile) ? "Core" : "Compatibility" + }); + // Print capabilities (if fine logging is enabled) if (logger.isLoggable(Level.FINE)) { StringBuilder sb = new StringBuilder(); sb.append("Supported capabilities: \n"); - for (Caps cap : caps) - { + for (Caps cap : caps) { sb.append("\t").append(cap.toString()).append("\n"); } logger.log(Level.FINE, sb.toString()); } - + texUtil.initialize(caps); } - + private void loadCapabilities() { if (gl2 != null) { loadCapabilitiesGL2(); @@ -479,31 +482,31 @@ public class GLRenderer implements Renderer { } loadCapabilitiesCommon(); } - + private int getInteger(int en) { intBuf16.clear(); gl.glGetInteger(en, intBuf16); return intBuf16.get(0); } - + private boolean getBoolean(int en) { gl.glGetBoolean(en, nameBuf); - return nameBuf.get(0) != (byte)0; + return nameBuf.get(0) != (byte) 0; } - + @SuppressWarnings("fallthrough") public void initialize() { loadCapabilities(); - + // Initialize default state.. gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); - + if (caps.contains(Caps.CoreProfile)) { // Core Profile requires VAO to be bound. gl3.glGenVertexArrays(intBuf16); int vaoId = intBuf16.get(0); gl3.glBindVertexArray(vaoId); - } + } if (gl2 != null) { gl2.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE); if (!caps.contains(Caps.CoreProfile)) { @@ -535,9 +538,11 @@ public class GLRenderer implements Renderer { invalidateState(); } - /*********************************************************************\ - |* Render State *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Render State *| + * \******************************************************************** + */ public void setDepthRange(float start, float end) { gl.glDepthRange(start, end); } @@ -602,7 +607,7 @@ public class GLRenderer implements Renderer { } if (state.isDepthTest() && !context.depthTestEnabled) { - gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(convertTestFunction(context.depthFunc)); context.depthTestEnabled = true; } else if (!state.isDepthTest() && context.depthTestEnabled) { @@ -714,7 +719,7 @@ public class GLRenderer implements Renderer { case Color: case Screen: gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR); - break; + break; case Exclusion: gl.glBlendFunc(GL.GL_ONE_MINUS_DST_COLOR, GL.GL_ONE_MINUS_SRC_COLOR); break; @@ -814,9 +819,11 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Camera and World transforms *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Camera and World transforms *| + * \******************************************************************** + */ public void setViewPort(int x, int y, int w, int h) { if (x != vpX || vpY != y || vpW != w || vpH != h) { gl.glViewport(x, y, w, h); @@ -858,9 +865,11 @@ public class GLRenderer implements Renderer { gl.resetStats(); } - /*********************************************************************\ - |* Shaders *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Shaders *| + * \******************************************************************** + */ protected void updateUniformLocation(Shader shader, Uniform uniform) { int loc = gl.glGetUniformLocation(shader.getId(), uniform.getName()); if (loc < 0) { @@ -1040,12 +1049,12 @@ public class GLRenderer implements Renderer { boolean gles2 = caps.contains(Caps.OpenGLES20); String language = source.getLanguage(); - + if (gles2 && !language.equals("GLSL100")) { throw new RendererException("This shader cannot run in OpenGL ES 2. " - + "Only GLSL 1.00 shaders are supported."); + + "Only GLSL 1.00 shaders are supported."); } - + // Upload shader source. // Merge the defines and source code. stringBuf.setLength(0); @@ -1072,17 +1081,17 @@ public class GLRenderer implements Renderer { } } } - + if (linearizeSrgbImages) { stringBuf.append("#define SRGB 1\n"); } - + stringBuf.append(source.getDefines()); stringBuf.append(source.getSource()); - + intBuf1.clear(); intBuf1.put(0, stringBuf.length()); - gl.glShaderSource(id, new String[]{ stringBuf.toString() }, intBuf1); + gl.glShaderSource(id, new String[]{stringBuf.toString()}, intBuf1); gl.glCompileShader(id); gl.glGetShader(id, GL.GL_COMPILE_STATUS, intBuf1); @@ -1137,7 +1146,7 @@ public class GLRenderer implements Renderer { // If using GLSL 1.5, we bind the outputs for the user // For versions 3.3 and up, user should use layout qualifiers instead. boolean bindFragDataRequired = false; - + for (ShaderSource source : shader.getSources()) { if (source.isUpdateNeeded()) { updateShaderSourceData(source); @@ -1245,9 +1254,11 @@ public class GLRenderer implements Renderer { shader.resetObject(); } - /*********************************************************************\ - |* Framebuffers *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Framebuffers *| + * \******************************************************************** + */ public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { copyFrameBuffer(src, dst, true); } @@ -1402,7 +1413,7 @@ public class GLRenderer implements Renderer { } else if (attachmentSlot < 0 || attachmentSlot >= 16) { throw new UnsupportedOperationException("Invalid FBO attachment slot: " + attachmentSlot); } - + return GLFbo.GL_COLOR_ATTACHMENT0_EXT + attachmentSlot; } @@ -1412,7 +1423,7 @@ public class GLRenderer implements Renderer { if (image.isUpdateNeeded()) { // Check NPOT requirements checkNonPowerOfTwo(tex); - + updateTexImageData(image, tex.getType(), 0, false); // NOTE: For depth textures, sets nearest/no-mips mode @@ -1476,7 +1487,7 @@ public class GLRenderer implements Renderer { } checkFrameBufferError(); - + fb.clearUpdateNeeded(); } @@ -1569,7 +1580,7 @@ public class GLRenderer implements Renderer { // update viewport to reflect framebuffer's resolution setViewPort(0, 0, fb.getWidth(), fb.getHeight()); - + if (context.boundFBO != fb.getId()) { glfbo.glBindFramebufferEXT(GLFbo.GL_FRAMEBUFFER_EXT, fb.getId()); statistics.onFrameBufferUse(fb, true); @@ -1640,7 +1651,7 @@ public class GLRenderer implements Renderer { public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { readFrameBufferWithGLFormat(fb, byteBuf, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); } - + private void readFrameBufferWithGLFormat(FrameBuffer fb, ByteBuffer byteBuf, int glFormat, int dataType) { if (fb != null) { RenderBuffer rb = fb.getColorBuffer(); @@ -1662,8 +1673,8 @@ public class GLRenderer implements Renderer { gl.glReadPixels(vpX, vpY, vpW, vpH, glFormat, dataType, byteBuf); } - - public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { GLImageFormat glFormat = texUtil.getImageFormatWithError(format, false); readFrameBufferWithGLFormat(fb, byteBuf, glFormat.format, glFormat.dataType); } @@ -1695,15 +1706,17 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Textures *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* 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."); + throw new RendererException("Multisample textures are not supported" + + " by the video hardware."); } - + switch (type) { case TwoDimensional: if (samples > 1) { @@ -1723,8 +1736,8 @@ public class GLRenderer implements Renderer { } case ThreeDimensional: if (!caps.contains(Caps.OpenGL20)) { - throw new RendererException("3D textures are not supported" + - " by the video hardware."); + throw new RendererException("3D textures are not supported" + + " by the video hardware."); } return GL2.GL_TEXTURE_3D; case CubeMap: @@ -1752,7 +1765,7 @@ public class GLRenderer implements Renderer { } private int convertMinFilter(Texture.MinFilter filter, boolean haveMips) { - if (haveMips){ + if (haveMips) { switch (filter) { case Trilinear: return GL.GL_LINEAR_MIPMAP_LINEAR; @@ -1807,11 +1820,11 @@ public class GLRenderer implements Renderer { int target = convertTextureType(tex.getType(), image != null ? image.getMultiSamples() : 1, -1); boolean haveMips = true; - + if (image != null) { haveMips = image.isGeneratedMipmapsRequired() || image.hasMipmaps(); } - + // filter things if (image.getLastTextureState().magFilter != tex.getMagFilter()) { int magFilter = convertMagFilter(tex.getMagFilter()); @@ -1834,7 +1847,7 @@ public class GLRenderer implements Renderer { context.seamlessCubemap = false; } } - + if (tex.getAnisotropicFilter() > 1) { if (caps.contains(Caps.TextureFilterAnisotropic)) { gl.glTexParameterf(target, @@ -1867,19 +1880,19 @@ public class GLRenderer implements Renderer { throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); } - if(tex.isNeedCompareModeUpdate() && gl2 != null){ + if (tex.isNeedCompareModeUpdate() && gl2 != null) { // R to Texture compare mode if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off) { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL2.GL_COMPARE_R_TO_TEXTURE); - gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY); + gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY); if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual) { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_GEQUAL); } else { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_LEQUAL); } - }else{ - //restoring default value - gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); + } else { + //restoring default value + gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); } tex.compareModeUpdated(); } @@ -1888,10 +1901,10 @@ public class GLRenderer implements Renderer { /** * Validates if a potentially NPOT texture is supported by the hardware. *

- * Textures with power-of-2 dimensions are supported on all hardware, however + * Textures with power-of-2 dimensions are supported on all hardware, however * non-power-of-2 textures may or may not be supported depending on which * texturing features are used. - * + * * @param tex The texture to validate. * @throws RendererException If the texture is not supported by the hardware */ @@ -1900,23 +1913,23 @@ public class GLRenderer implements Renderer { // Texture is power-of-2, safe to use. return; } - + if (caps.contains(Caps.NonPowerOfTwoTextures)) { // Texture is NPOT but it is supported by video hardware. return; } - + // Maybe we have some / partial support for NPOT? if (!caps.contains(Caps.PartialNonPowerOfTwoTextures)) { // Cannot use any type of NPOT texture (uncommon) throw new RendererException("non-power-of-2 textures are not " - + "supported by the video hardware"); + + "supported by the video hardware"); } - + // Partial NPOT supported.. if (tex.getMinFilter().usesMipMapLevels()) { throw new RendererException("non-power-of-2 textures with mip-maps " - + "are not supported by the video hardware"); + + "are not supported by the video hardware"); } switch (tex.getType()) { @@ -1924,7 +1937,7 @@ public class GLRenderer implements Renderer { case ThreeDimensional: if (tex.getWrap(WrapAxis.R) != Texture.WrapMode.EdgeClamp) { throw new RendererException("repeating non-power-of-2 textures " - + "are not supported by the video hardware"); + + "are not supported by the video hardware"); } // fallthrough intentional!!! case TwoDimensionalArray: @@ -1932,22 +1945,22 @@ public class GLRenderer implements Renderer { if (tex.getWrap(WrapAxis.S) != Texture.WrapMode.EdgeClamp || tex.getWrap(WrapAxis.T) != Texture.WrapMode.EdgeClamp) { throw new RendererException("repeating non-power-of-2 textures " - + "are not supported by the video hardware"); + + "are not supported by the video hardware"); } break; default: throw new UnsupportedOperationException("unrecongized texture type"); } } - + /** * 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 + * + * @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 * @param scaleToPot If true, the image will be scaled to power-of-2 dimensions - * before being uploaded. + * before being uploaded. */ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean scaleToPot) { int texId = img.getId(); @@ -1968,7 +1981,7 @@ public class GLRenderer implements Renderer { gl.glActiveTexture(GL.GL_TEXTURE0 + unit); context.boundTextureUnit = unit; } - + gl.glBindTexture(target, texId); context.boundTextures[unit] = img; @@ -2011,12 +2024,12 @@ public class GLRenderer implements Renderer { throw new RendererException("Multisample textures are not supported by the video hardware"); } } - + // Check if graphics card doesn't support depth textures if (img.getFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) { throw new RendererException("Depth textures are not supported by the video hardware"); } - + if (target == GL.GL_TEXTURE_CUBE_MAP) { // Check max texture size before upload int cubeSize = limits.get(Limits.CubemapSize); @@ -2053,12 +2066,12 @@ public class GLRenderer implements Renderer { if (!caps.contains(Caps.TextureArray)) { throw new RendererException("Texture arrays not supported by graphics hardware"); } - + List data = imageForUpload.getData(); - + // -1 index specifies prepare data for 2D Array texUtil.uploadTexture(imageForUpload, target, -1, linearizeSrgbImages); - + for (int i = 0; i < data.size(); i++) { // upload each slice of 2D array in turn // this time with the appropriate index @@ -2087,21 +2100,21 @@ public class GLRenderer implements Renderer { if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) { // Check NPOT requirements boolean scaleToPot = false; - + try { checkNonPowerOfTwo(tex); } catch (RendererException ex) { if (logger.isLoggable(Level.WARNING)) { int nextWidth = FastMath.nearestPowerOfTwo(tex.getImage().getWidth()); int nextHeight = FastMath.nearestPowerOfTwo(tex.getImage().getHeight()); - logger.log(Level.WARNING, - "Non-power-of-2 textures are not supported! Scaling texture '" + tex.getName() + - "' of size " + tex.getImage().getWidth() + "x" + tex.getImage().getHeight() + - " to " + nextWidth + "x" + nextHeight); + logger.log(Level.WARNING, + "Non-power-of-2 textures are not supported! Scaling texture '" + tex.getName() + + "' of size " + tex.getImage().getWidth() + "x" + tex.getImage().getHeight() + + " to " + nextWidth + "x" + nextHeight); } scaleToPot = true; } - + updateTexImageData(image, tex.getType(), unit, scaleToPot); } @@ -2146,9 +2159,11 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Vertex Buffers and Attributes *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Vertex Buffers and Attributes *| + * \******************************************************************** + */ private int convertUsage(Usage usage) { switch (usage) { case Static: @@ -2222,7 +2237,7 @@ public class GLRenderer implements Renderer { //statistics.onVertexBufferUse(vb, false); } } - + int usage = convertUsage(vb.getUsage()); vb.getData().rewind(); @@ -2283,7 +2298,7 @@ public class GLRenderer implements Renderer { if (context.boundShaderProgram <= 0) { throw new IllegalStateException("Cannot render mesh without shader bound"); } - + Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); int loc = attrib.getLocation(); if (loc == -1) { @@ -2413,7 +2428,7 @@ public class GLRenderer implements Renderer { // What is this? throw new RendererException("Unexpected format for index buffer: " + indexBuf.getFormat()); } - + if (indexBuf.isUpdateNeeded()) { updateBufferData(indexBuf); } @@ -2486,9 +2501,11 @@ public class GLRenderer implements Renderer { } } - /*********************************************************************\ - |* Render Calls *| - \*********************************************************************/ + /** + * ******************************************************************\ + * |* Render Calls *| + * \******************************************************************** + */ public int convertElementMode(Mesh.Mode mode) { switch (mode) { case Points: @@ -2530,7 +2547,7 @@ public class GLRenderer implements Renderer { if (interleavedData != null && interleavedData.isUpdateNeeded()) { updateBufferData(interleavedData); } - + if (instanceData != null) { setVertexAttrib(instanceData, null); } @@ -2580,11 +2597,11 @@ public class GLRenderer implements Renderer { } 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); @@ -2602,7 +2619,7 @@ public class GLRenderer implements Renderer { setVertexAttrib(vb, null); } } - + for (VertexBuffer vb : mesh.getBufferList().getArray()) { if (vb.getBufferType() == Type.InterleavedData || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers @@ -2637,7 +2654,7 @@ public class GLRenderer implements Renderer { gl.glLineWidth(mesh.getLineWidth()); context.lineWidth = mesh.getLineWidth(); } - + if (gl4 != null && mesh.getMode().equals(Mode.Patch)) { gl4.glPatchParameter(mesh.getPatchVertexCount()); } @@ -2653,12 +2670,12 @@ public class GLRenderer implements Renderer { // Gamma correction if (!caps.contains(Caps.Srgb) && enableSrgb) { // Not supported, sorry. - logger.warning("sRGB framebuffer is not supported " + - "by video hardware, but was requested."); - + logger.warning("sRGB framebuffer is not supported " + + "by video hardware, but was requested."); + return; } - + setFrameBuffer(null); if (enableSrgb) { From a8b3407b469dcfff6ddd873768f7370f6e17ca49 Mon Sep 17 00:00:00 2001 From: zzuegg Date: Fri, 19 Jun 2015 23:08:00 +0200 Subject: [PATCH 13/27] Removed empty lines --- .../src/main/java/com/jme3/renderer/opengl/GLRenderer.java | 2 -- 1 file changed, 2 deletions(-) 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 2da5e28f9..23d3eea17 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 @@ -56,7 +56,6 @@ import com.jme3.util.BufferUtils; import com.jme3.util.ListMap; import com.jme3.util.MipMapGenerator; import com.jme3.util.NativeObjectManager; - import java.nio.*; import java.util.Arrays; import java.util.EnumMap; @@ -67,7 +66,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; - import jme3tools.shader.ShaderDebug; public class GLRenderer implements Renderer { From 8d0c371796851e7535d154a4a0a4ec6bdc669ad3 Mon Sep 17 00:00:00 2001 From: zzuegg Date: Fri, 19 Jun 2015 23:16:24 +0200 Subject: [PATCH 14/27] Hopefully fixed --- .../com/jme3/renderer/opengl/GLRenderer.java | 89 ++++++++----------- 1 file changed, 38 insertions(+), 51 deletions(-) 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 23d3eea17..bb145edbe 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 @@ -101,9 +101,9 @@ public class GLRenderer implements Renderer { public GLRenderer(GL gl, GLExt glext, GLFbo glfbo) { this.gl = gl; - this.gl2 = gl instanceof GL2 ? (GL2) gl : null; - this.gl3 = gl instanceof GL3 ? (GL3) gl : null; - this.gl4 = gl instanceof GL4 ? (GL4) gl : null; + this.gl2 = gl instanceof GL2 ? (GL2)gl : null; + this.gl3 = gl instanceof GL3 ? (GL3)gl : null; + this.gl4 = gl instanceof GL4 ? (GL4)gl : null; this.glfbo = glfbo; this.glext = glext; this.texUtil = new TextureUtil(gl, gl2, glext, context); @@ -425,8 +425,8 @@ public class GLRenderer implements Renderer { } // Supports sRGB pipeline. - if ((hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) - || caps.contains(Caps.OpenGL30)) { + if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) + || caps.contains(Caps.OpenGL30) ) { caps.add(Caps.Srgb); } @@ -465,7 +465,8 @@ public class GLRenderer implements Renderer { if (logger.isLoggable(Level.FINE)) { StringBuilder sb = new StringBuilder(); sb.append("Supported capabilities: \n"); - for (Caps cap : caps) { + for (Caps cap : caps) + { sb.append("\t").append(cap.toString()).append("\n"); } logger.log(Level.FINE, sb.toString()); @@ -491,7 +492,7 @@ public class GLRenderer implements Renderer { private boolean getBoolean(int en) { gl.glGetBoolean(en, nameBuf); - return nameBuf.get(0) != (byte) 0; + return nameBuf.get(0) != (byte)0; } @SuppressWarnings("fallthrough") @@ -538,11 +539,9 @@ public class GLRenderer implements Renderer { invalidateState(); } - /** - * ******************************************************************\ - * |* Render State *| - * \******************************************************************** - */ + /*********************************************************************\ + |* Render State *| + \*********************************************************************/ public void setDepthRange(float start, float end) { gl.glDepthRange(start, end); } @@ -819,11 +818,9 @@ public class GLRenderer implements Renderer { } } - /** - * ******************************************************************\ - * |* Camera and World transforms *| - * \******************************************************************** - */ + /*********************************************************************\ + |* Camera and World transforms *| + \*********************************************************************/ public void setViewPort(int x, int y, int w, int h) { if (x != vpX || vpY != y || vpW != w || vpH != h) { gl.glViewport(x, y, w, h); @@ -865,11 +862,9 @@ public class GLRenderer implements Renderer { gl.resetStats(); } - /** - * ******************************************************************\ - * |* Shaders *| - * \******************************************************************** - */ + /*********************************************************************\ + |* Shaders *| + \*********************************************************************/ protected void updateUniformLocation(Shader shader, Uniform uniform) { int loc = gl.glGetUniformLocation(shader.getId(), uniform.getName()); if (loc < 0) { @@ -1091,7 +1086,7 @@ public class GLRenderer implements Renderer { intBuf1.clear(); intBuf1.put(0, stringBuf.length()); - gl.glShaderSource(id, new String[]{stringBuf.toString()}, intBuf1); + gl.glShaderSource(id, new String[]{ stringBuf.toString() }, intBuf1); gl.glCompileShader(id); gl.glGetShader(id, GL.GL_COMPILE_STATUS, intBuf1); @@ -1254,11 +1249,9 @@ public class GLRenderer implements Renderer { shader.resetObject(); } - /** - * ******************************************************************\ - * |* Framebuffers *| - * \******************************************************************** - */ + /*********************************************************************\ + |* Framebuffers *| + \*********************************************************************/ public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { copyFrameBuffer(src, dst, true); } @@ -1706,11 +1699,9 @@ public class GLRenderer implements Renderer { } } - /** - * ******************************************************************\ - * |* Textures *| - * \******************************************************************** - */ + /*********************************************************************\ + |* 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" + @@ -1765,7 +1756,7 @@ public class GLRenderer implements Renderer { } private int convertMinFilter(Texture.MinFilter filter, boolean haveMips) { - if (haveMips) { + if (haveMips){ switch (filter) { case Trilinear: return GL.GL_LINEAR_MIPMAP_LINEAR; @@ -1880,7 +1871,7 @@ public class GLRenderer implements Renderer { throw new UnsupportedOperationException("Unknown texture type: " + tex.getType()); } - if (tex.isNeedCompareModeUpdate() && gl2 != null) { + if(tex.isNeedCompareModeUpdate() && gl2 != null){ // R to Texture compare mode if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off) { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL2.GL_COMPARE_R_TO_TEXTURE); @@ -1890,7 +1881,7 @@ public class GLRenderer implements Renderer { } else { gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_LEQUAL); } - } else { + }else{ //restoring default value gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); } @@ -1901,7 +1892,7 @@ public class GLRenderer implements Renderer { /** * Validates if a potentially NPOT texture is supported by the hardware. *

- * Textures with power-of-2 dimensions are supported on all hardware, however + * Textures with power-of-2 dimensions are supported on all hardware, however * non-power-of-2 textures may or may not be supported depending on which * texturing features are used. * @@ -1956,11 +1947,11 @@ public class GLRenderer implements Renderer { /** * 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 + * @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 * @param scaleToPot If true, the image will be scaled to power-of-2 dimensions - * before being uploaded. + * before being uploaded. */ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean scaleToPot) { int texId = img.getId(); @@ -2159,11 +2150,9 @@ public class GLRenderer implements Renderer { } } - /** - * ******************************************************************\ - * |* Vertex Buffers and Attributes *| - * \******************************************************************** - */ + /*********************************************************************\ + |* Vertex Buffers and Attributes *| + \*********************************************************************/ private int convertUsage(Usage usage) { switch (usage) { case Static: @@ -2501,11 +2490,9 @@ public class GLRenderer implements Renderer { } } - /** - * ******************************************************************\ - * |* Render Calls *| - * \******************************************************************** - */ + /*********************************************************************\ + |* Render Calls *| + \*********************************************************************/ public int convertElementMode(Mesh.Mode mode) { switch (mode) { case Points: From 86900c9d0965f749266efff20e103245ab89c0a3 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 20 Jun 2015 14:28:41 -0400 Subject: [PATCH 15/27] Travis-CI: Try to fix notifications --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8a29bd1f8..f7b3add47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,10 @@ branches: notifications: slack: - secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s=" on_success: change on_failure: always + rooms: + secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s=" before_install: # required libs for android build tools From 5a1faac6294e076157bcd210dca17c5a122219ab Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 20 Jun 2015 14:37:01 -0400 Subject: [PATCH 16/27] Travis-CI: create zip dist as part of build --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f7b3add47..2b324fdbb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,12 @@ notifications: rooms: secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s=" -before_install: +install: + - ./gradlew assemble +script: + - ./gradlew check + - ./gradlew createZipDistribution +# before_install: # required libs for android build tools # sudo apt-get update # sudo apt-get install -qq p7zip-full From c39abf48de49bd661b1f5b5fc2d7c1e3dc069373 Mon Sep 17 00:00:00 2001 From: Kirill Vainer Date: Sat, 20 Jun 2015 15:59:45 -0400 Subject: [PATCH 17/27] Travis-CI: enable releases --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2b324fdbb..71c3b576f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,9 +21,20 @@ notifications: install: - ./gradlew assemble + script: - ./gradlew check - ./gradlew createZipDistribution + +deploy: + provider: releases + api_key: + secure: "KbFiMt0a8FxUKvCJUYwikLYaqqGMn1p6k4OsXnGqwptQZEUIayabNLHeaD2kTNT3e6AY1ETwQLff/lB2LttmIo4g5NWW63g1K3A/HwgnhJwETengiProZ/Udl+ugPeDL/+ar43HUhFq4knBnzFKnEcHAThTPVqH/RMDvZf1UUYI=" + file: build/distributions/jME3.1.0_snapshot-github_2015-06-20.zip + skip_cleanup: true + on: + tags: true + # before_install: # required libs for android build tools # sudo apt-get update From 97a2f58be7b0d8e411bdc02c4c97e83ea004bfae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=A4rtner?= Date: Mon, 22 Jun 2015 13:59:11 +0200 Subject: [PATCH 18/27] [Nifty-GUI] Using java logger, instead of stdout Replaced call to System.out.println() with proper logging call. --- .../src/main/java/com/jme3/cinematic/events/GuiEvent.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jme3-niftygui/src/main/java/com/jme3/cinematic/events/GuiEvent.java b/jme3-niftygui/src/main/java/com/jme3/cinematic/events/GuiEvent.java index 2f5d788b4..f832b4266 100644 --- a/jme3-niftygui/src/main/java/com/jme3/cinematic/events/GuiEvent.java +++ b/jme3-niftygui/src/main/java/com/jme3/cinematic/events/GuiEvent.java @@ -38,6 +38,8 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import de.lessvoid.nifty.Nifty; import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; /** * @@ -45,6 +47,8 @@ import java.io.IOException; */ public class GuiEvent extends AbstractCinematicEvent { + static final Logger log = Logger.getLogger(GuiEvent.class.getName()); + protected String screen; protected Nifty nifty; @@ -76,7 +80,7 @@ public class GuiEvent extends AbstractCinematicEvent { @Override public void onPlay() { - System.out.println("screen should be " + screen); + log.log(Level.FINEST, "screen should be {0}", screen); nifty.gotoScreen(screen); } From 1eedfa5a5f3f53399f0dc78a35af92b187e418f6 Mon Sep 17 00:00:00 2001 From: Alrik Date: Mon, 22 Jun 2015 17:04:50 +0200 Subject: [PATCH 19/27] - fix GZIP and ZIP serializer copying the whole temporary buffer instead of only the part where the data was written. --- .../jme3/network/serializing/serializers/GZIPSerializer.java | 3 ++- .../jme3/network/serializing/serializers/ZIPSerializer.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java index 01dbd1d41..287d81cd0 100644 --- a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java +++ b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java @@ -87,7 +87,8 @@ public class GZIPSerializer extends Serializer { ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream(); GZIPOutputStream gzipOutput = new GZIPOutputStream(byteArrayOutput); - gzipOutput.write(tempBuffer.array()); + tempBuffer.flip(); + gzipOutput.write(tempBuffer.array(), 0, tempBuffer.limit()); gzipOutput.flush(); gzipOutput.finish(); gzipOutput.close(); diff --git a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/ZIPSerializer.java b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/ZIPSerializer.java index 1241c1341..ad7d7162d 100644 --- a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/ZIPSerializer.java +++ b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/ZIPSerializer.java @@ -98,7 +98,8 @@ public class ZIPSerializer extends Serializer { ZipEntry zipEntry = new ZipEntry("zip"); zipOutput.putNextEntry(zipEntry); - zipOutput.write(tempBuffer.array()); + tempBuffer.flip(); + zipOutput.write(tempBuffer.array(), 0, tempBuffer.limit()); zipOutput.flush(); zipOutput.closeEntry(); zipOutput.close(); From 2cf7d9eb5af40254b89320962c7a302b7744060b Mon Sep 17 00:00:00 2001 From: AlrikG Date: Mon, 22 Jun 2015 17:11:50 +0200 Subject: [PATCH 20/27] Update GZIPSerializer.java --- .../jme3/network/serializing/serializers/GZIPSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java index 287d81cd0..a4dd10098 100644 --- a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java +++ b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java @@ -88,7 +88,7 @@ public class GZIPSerializer extends Serializer { GZIPOutputStream gzipOutput = new GZIPOutputStream(byteArrayOutput); tempBuffer.flip(); - gzipOutput.write(tempBuffer.array(), 0, tempBuffer.limit()); + gzipOutput.write(tempBuffer.array(), 0, tempBuffer.limit()); gzipOutput.flush(); gzipOutput.finish(); gzipOutput.close(); From 7b6a742f0f2bea30bb44085af7edd150d2b387ab Mon Sep 17 00:00:00 2001 From: AlrikG Date: Mon, 22 Jun 2015 17:12:12 +0200 Subject: [PATCH 21/27] Update GZIPSerializer.java --- .../jme3/network/serializing/serializers/GZIPSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java index a4dd10098..7579e84c5 100644 --- a/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java +++ b/jme3-networking/src/main/java/com/jme3/network/serializing/serializers/GZIPSerializer.java @@ -88,7 +88,7 @@ public class GZIPSerializer extends Serializer { GZIPOutputStream gzipOutput = new GZIPOutputStream(byteArrayOutput); tempBuffer.flip(); - gzipOutput.write(tempBuffer.array(), 0, tempBuffer.limit()); + gzipOutput.write(tempBuffer.array(), 0, tempBuffer.limit()); gzipOutput.flush(); gzipOutput.finish(); gzipOutput.close(); From 4cec908a50fecd7afcb27db76c34cd4ee8f80d0e Mon Sep 17 00:00:00 2001 From: kaelthas Date: Mon, 22 Jun 2015 18:41:53 +0200 Subject: [PATCH 22/27] Inverse Kinematics: several minor memory and CPU optimisations. --- .../definitions/ConstraintDefinitionIK.java | 111 ++++++++++-------- .../scene/plugins/blender/math/Matrix.java | 2 +- 2 files changed, 61 insertions(+), 52 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java index 820a283b3..4fb9ecd74 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java @@ -1,9 +1,9 @@ package com.jme3.scene.plugins.blender.constraints.definitions; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; -import java.util.Set; import org.ejml.simple.SimpleMatrix; @@ -19,6 +19,11 @@ import com.jme3.scene.plugins.blender.math.DTransform; import com.jme3.scene.plugins.blender.math.Matrix; import com.jme3.scene.plugins.blender.math.Vector3d; +/** + * A definiotion of a Inverse Kinematics constraint. This implementation uses Jacobian pseudoinverse algorithm. + * + * @author Marcin Roguski (Kaelthas) + */ public class ConstraintDefinitionIK extends ConstraintDefinition { private static final float MIN_DISTANCE = 0.001f; private static final int FLAG_USE_TAIL = 0x01; @@ -31,6 +36,8 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { private boolean useTail; /** The amount of iterations of the algorithm. */ private int iterations; + /** The count of bones' chain. */ + private int bonesCount = -1; public ConstraintDefinitionIK(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); @@ -47,47 +54,64 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { } } - @Override - public Set getAlteredOmas() { - return bones.alteredOmas; - } + /** + * Below are the variables that only need to be allocated once for IK constraint instance. + */ + /** Temporal quaternion. */ + private DQuaternion tempDQuaternion = new DQuaternion(); + /** Temporal matrix column. */ + private Vector3d col = new Vector3d(); + /** Effector's position change. */ + private Matrix deltaP = new Matrix(3, 1); + /** The current target position. */ + private Vector3d target = new Vector3d(); + /** Rotation vectors for each joint (allocated when we know the size of a bones' chain. */ + private Vector3d[] rotationVectors; + /** The Jacobian matrix. Allocated when the bones' chain size is known. */ + private Matrix J; @Override public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { - if (influence == 0 || !trackToBeChanged || targetTransform == null) { + if (influence == 0 || !trackToBeChanged || targetTransform == null || bonesCount == 0) { return;// no need to do anything } - DQuaternion q = new DQuaternion(); - Vector3d t = new Vector3d(targetTransform.getTranslation()); - bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, blenderContext); + if (bones == null) { + bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, alteredOmas, blenderContext); + } if (bones.size() == 0) { + bonesCount = 0; return;// no need to do anything } double distanceFromTarget = Double.MAX_VALUE; + target.set(targetTransform.getTranslation().x, targetTransform.getTranslation().y, targetTransform.getTranslation().z); + + if (bonesCount < 0) { + bonesCount = bones.size(); + rotationVectors = new Vector3d[bonesCount]; + for (int i = 0; i < bonesCount; ++i) { + rotationVectors[i] = new Vector3d(); + } + J = new Matrix(3, bonesCount); + } - Vector3d target = new Vector3d(targetTransform.getTranslation()); - Vector3d[] rotationVectors = new Vector3d[bones.size()]; BoneContext topBone = bones.get(0); - for (int i = 1; i <= iterations; ++i) { + for (int i = 0; i < iterations; ++i) { DTransform topBoneTransform = bones.getWorldTransform(topBone); Vector3d e = topBoneTransform.getTranslation().add(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector - distanceFromTarget = e.distance(t); + distanceFromTarget = e.distance(target); if (distanceFromTarget <= MIN_DISTANCE) { break; } - Matrix deltaP = new Matrix(3, 1); - deltaP.setColumn(target.subtract(e), 0); - - Matrix J = new Matrix(3, bones.size()); + deltaP.setColumn(0, 0, target.x - e.x, target.y - e.y, target.z - e.z); int column = 0; for (BoneContext boneContext : bones) { DTransform boneWorldTransform = bones.getWorldTransform(boneContext); Vector3d j = boneWorldTransform.getTranslation(); // current join position Vector3d vectorFromJointToEffector = e.subtract(j); - rotationVectors[column] = vectorFromJointToEffector.cross(target.subtract(j)).normalize(); - Vector3d col = rotationVectors[column].cross(vectorFromJointToEffector); + vectorFromJointToEffector.cross(target.subtract(j), rotationVectors[column]).normalizeLocal(); + rotationVectors[column].cross(vectorFromJointToEffector, col); J.setColumn(col, column++); } Matrix J_1 = J.pseudoinverse(); @@ -98,34 +122,34 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { double angle = deltaThetas.get(j, 0); Vector3d rotationVector = rotationVectors[j]; - q.fromAngleAxis(angle, rotationVector); + tempDQuaternion.fromAngleAxis(angle, rotationVector); BoneContext boneContext = bones.get(j); Bone bone = boneContext.getBone(); if (bone.equals(this.getOwner())) { if (boneContext.isLockX()) { - q.set(0, q.getY(), q.getZ(), q.getW()); + tempDQuaternion.set(0, tempDQuaternion.getY(), tempDQuaternion.getZ(), tempDQuaternion.getW()); } if (boneContext.isLockY()) { - q.set(q.getX(), 0, q.getZ(), q.getW()); + tempDQuaternion.set(tempDQuaternion.getX(), 0, tempDQuaternion.getZ(), tempDQuaternion.getW()); } if (boneContext.isLockZ()) { - q.set(q.getX(), q.getY(), 0, q.getW()); + tempDQuaternion.set(tempDQuaternion.getX(), tempDQuaternion.getY(), 0, tempDQuaternion.getW()); } } DTransform boneTransform = bones.getWorldTransform(boneContext); - boneTransform.getRotation().set(q.mult(boneTransform.getRotation())); + boneTransform.getRotation().set(tempDQuaternion.mult(boneTransform.getRotation())); bones.setWorldTransform(boneContext, boneTransform); } } // applying the results - for (int i = bones.size() - 1; i >= 0; --i) { + for (int i = bonesCount - 1; i >= 0; --i) { BoneContext boneContext = bones.get(i); DTransform transform = bones.getWorldTransform(boneContext); constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, transform.toTransform()); } - bones.reset(); + bones = null;// need to reload them again } @Override @@ -133,30 +157,23 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { return "Inverse kinematics"; } - @Override - public boolean isTrackToBeChanged() { - if (trackToBeChanged) { - // need to check the bone structure too (when constructor was called not all of the bones might have been loaded yet) - // that is why it is also checked here - bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, blenderContext); - trackToBeChanged = bones.size() > 0; - } - return trackToBeChanged; - } - @Override public boolean isTargetRequired() { return true; } + /** + * Loaded bones' chain. This class allows to operate on transform matrices that use double precision in computations. + * Only the final result is being transformed to single precision numbers. + * + * @author Marcin Roguski (Kaelthas) + */ private static class BonesChain extends ArrayList { - private static final long serialVersionUID = -1850524345643600718L; + private static final long serialVersionUID = -1850524345643600718L; - private Set alteredOmas = new HashSet(); - private List originalBonesMatrices = new ArrayList(); - private List bonesMatrices = new ArrayList(); + private List bonesMatrices = new ArrayList(); - public BonesChain(Bone bone, boolean useTail, int bonesAffected, BlenderContext blenderContext) { + public BonesChain(Bone bone, boolean useTail, int bonesAffected, Collection alteredOmas, BlenderContext blenderContext) { if (bone != null) { ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class); if (!useTail) { @@ -169,11 +186,10 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { Space space = this.size() < bonesAffected ? Space.CONSTRAINT_SPACE_LOCAL : Space.CONSTRAINT_SPACE_WORLD; Transform transform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), space); - originalBonesMatrices.add(new DTransform(transform).toMatrix()); + bonesMatrices.add(new DTransform(transform).toMatrix()); bone = bone.getParent(); } - this.reset(); } } @@ -204,12 +220,5 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { result = result.mult(bonesMatrices.get(index)); return new Matrix(result); } - - public void reset() { - bonesMatrices.clear(); - for (Matrix m : originalBonesMatrices) { - bonesMatrices.add(new Matrix(m)); - } - } } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java index 5ea580b84..29550f23b 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java @@ -51,7 +51,7 @@ public class Matrix extends SimpleMatrix { int N = Math.min(this.numRows(),this.numCols()); double maxSingular = 0; - for( int i = 0; i < N; i++ ) { + for( int i = 0; i < N; ++i ) { if( S.get(i, i) > maxSingular ) { maxSingular = S.get(i, i); } From 483156f2bad72c3199350cd5d05ddd78172531e4 Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Sun, 28 Jun 2015 15:11:04 +0200 Subject: [PATCH 23/27] Improvement: Inverse Kinematics now breaks the iteration if the computed angle change drops below some minimal level. --- .../definitions/ConstraintDefinitionIK.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java index 4fb9ecd74..af6f17669 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java @@ -25,19 +25,20 @@ import com.jme3.scene.plugins.blender.math.Vector3d; * @author Marcin Roguski (Kaelthas) */ public class ConstraintDefinitionIK extends ConstraintDefinition { - private static final float MIN_DISTANCE = 0.001f; - private static final int FLAG_USE_TAIL = 0x01; - private static final int FLAG_POSITION = 0x20; + private static final float MIN_DISTANCE = 0.001f; + private static final float MIN_ANGLE_CHANGE = 0.001f; + private static final int FLAG_USE_TAIL = 0x01; + private static final int FLAG_POSITION = 0x20; - private BonesChain bones; + private BonesChain bones; /** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */ - private int bonesAffected; + private int bonesAffected; /** Indicates if the tail of the bone should be used or not. */ - private boolean useTail; + private boolean useTail; /** The amount of iterations of the algorithm. */ - private int iterations; + private int iterations; /** The count of bones' chain. */ - private int bonesCount = -1; + private int bonesCount = -1; public ConstraintDefinitionIK(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { super(constraintData, ownerOMA, blenderContext); @@ -117,7 +118,9 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { Matrix J_1 = J.pseudoinverse(); SimpleMatrix deltaThetas = J_1.mult(deltaP); - + if (deltaThetas.elementMaxAbs() < MIN_ANGLE_CHANGE) { + break; + } for (int j = 0; j < deltaThetas.numRows(); ++j) { double angle = deltaThetas.get(j, 0); Vector3d rotationVector = rotationVectors[j]; @@ -171,7 +174,7 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { private static class BonesChain extends ArrayList { private static final long serialVersionUID = -1850524345643600718L; - private List bonesMatrices = new ArrayList(); + private List bonesMatrices = new ArrayList(); public BonesChain(Bone bone, boolean useTail, int bonesAffected, Collection alteredOmas, BlenderContext blenderContext) { if (bone != null) { From 2d9a1b8737cfc0c4e4b346ebf3f2b55b32848a60 Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Sun, 28 Jun 2015 15:48:11 +0200 Subject: [PATCH 24/27] Bugfix: include all bones in the chain of the IK constraint if the specified chain length is zero. --- .../blender/constraints/definitions/ConstraintDefinitionIK.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java index af6f17669..69e087a28 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java @@ -182,7 +182,7 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { if (!useTail) { bone = bone.getParent(); } - while (bone != null && this.size() < bonesAffected) { + while (bone != null && (bonesAffected <= 0 || this.size() < bonesAffected)) { BoneContext boneContext = blenderContext.getBoneContext(bone); this.add(boneContext); alteredOmas.add(boneContext.getBoneOma()); From b0e751c81acfeea1de98da636a260d387a8bb42a Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Sun, 28 Jun 2015 15:48:49 +0200 Subject: [PATCH 25/27] Bugfix: avoiding infinite loops while applying constraints. --- .../blender/constraints/SimulationNode.java | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java index 031676b94..711e0a338 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.Stack; import java.util.logging.Logger; import com.jme3.animation.AnimChannel; @@ -38,9 +39,9 @@ import com.jme3.util.TempVars; * @author Marcin Roguski (Kaelthas) */ public class SimulationNode { - private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName()); + private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName()); - private Long featureOMA; + private Long featureOMA; /** The blender context. */ private BlenderContext blenderContext; /** The name of the node (for debugging purposes). */ @@ -51,11 +52,11 @@ public class SimulationNode { private List animations; /** The nodes spatial (if null then the boneContext should be set). */ - private Spatial spatial; + private Spatial spatial; /** The skeleton of the bone (not null if the node simulated the bone). */ - private Skeleton skeleton; + private Skeleton skeleton; /** Animation controller for the node's feature. */ - private AnimControl animControl; + private AnimControl animControl; /** * The star transform of a spatial. Needed to properly reset the spatial to @@ -64,7 +65,7 @@ public class SimulationNode { private Transform spatialStartTransform; /** Star transformations for bones. Needed to properly reset the bones. */ private Map boneStartTransforms; - + /** * Builds the nodes tree for the given feature. The feature (bone or * spatial) is found by its OMA. The feature must be a root bone or a root @@ -208,8 +209,7 @@ public class SimulationNode { if (animations != null) { TempVars vars = TempVars.get(); AnimChannel animChannel = animControl.createChannel(); - - // List bonesWithConstraints = this.collectBonesWithConstraints(skeleton); + for (Animation animation : animations) { float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation); int maxFrame = (int) animationTimeBoundaries[0]; @@ -233,7 +233,7 @@ public class SimulationNode { for (Bone rootBone : skeleton.getRoots()) { // ignore the 0-indexed bone if (skeleton.getBoneIndex(rootBone) > 0) { - this.applyConstraints(rootBone, alteredOmas, applied, frame); + this.applyConstraints(rootBone, alteredOmas, applied, frame, new Stack()); } } @@ -294,34 +294,39 @@ public class SimulationNode { * the set of OMAS of the altered bones (is populated if necessary) * @param frame * the current frame of the animation + * @param bonesStack + * the stack of bones used to avoid infinite loops while applying constraints */ - private void applyConstraints(Bone bone, Set alteredOmas, Set applied, int frame) { - BoneContext boneContext = blenderContext.getBoneContext(bone); - if(!applied.contains(boneContext.getBoneOma())) { - List constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); - if (constraints != null && constraints.size() > 0) { - // TODO: BEWARE OF INFINITE LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!! - for (Constraint constraint : constraints) { - if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) { - // first apply constraints of the target bone - BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA()); - this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame); - } - constraint.apply(frame); - if (constraint.getAlteredOmas() != null) { - alteredOmas.addAll(constraint.getAlteredOmas()); + private void applyConstraints(Bone bone, Set alteredOmas, Set applied, int frame, Stack bonesStack) { + if (!bonesStack.contains(bone)) { + bonesStack.push(bone); + BoneContext boneContext = blenderContext.getBoneContext(bone); + if (!applied.contains(boneContext.getBoneOma())) { + List constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); + if (constraints != null && constraints.size() > 0) { + for (Constraint constraint : constraints) { + if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) { + // first apply constraints of the target bone + BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA()); + this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame, bonesStack); + } + constraint.apply(frame); + if (constraint.getAlteredOmas() != null) { + alteredOmas.addAll(constraint.getAlteredOmas()); + } + alteredOmas.add(boneContext.getBoneOma()); } - alteredOmas.add(boneContext.getBoneOma()); } + applied.add(boneContext.getBoneOma()); } - applied.add(boneContext.getBoneOma()); - } - - List children = bone.getChildren(); - if (children != null && children.size() > 0) { - for (Bone child : bone.getChildren()) { - this.applyConstraints(child, alteredOmas, applied, frame); + + List children = bone.getChildren(); + if (children != null && children.size() > 0) { + for (Bone child : bone.getChildren()) { + this.applyConstraints(child, alteredOmas, applied, frame, bonesStack); + } } + bonesStack.pop(); } } From 485af7cf2aaf929d15bd39655fe86a0df6fbbb4f Mon Sep 17 00:00:00 2001 From: Nehon Date: Fri, 3 Jul 2015 22:58:42 +0200 Subject: [PATCH 26/27] TextureFetch shader node now works with glgl1.5 --- .../Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn | 1 + .../resources/Common/MatDefs/ShaderNodes/Basic/texture15.frag | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/texture15.frag diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn index b4ccd3640..69fdec638 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn @@ -2,6 +2,7 @@ ShaderNodeDefinitions{ ShaderNodeDefinition TextureFetch { Type: Fragment Shader GLSL100: Common/MatDefs/ShaderNodes/Basic/texture.frag + Shader GLSL150: Common/MatDefs/ShaderNodes/Basic/texture15.frag Documentation{ Fetches a color value in the given texture acording to given texture coordinates @input texture the texture to read diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/texture15.frag b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/texture15.frag new file mode 100644 index 000000000..b716c3e89 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/texture15.frag @@ -0,0 +1,3 @@ +void main(){ + outColor = texture(texture,texCoord); +} \ No newline at end of file From 6d3377a2a88afa30e54fcc8666a10420e38931ca Mon Sep 17 00:00:00 2001 From: Nehon Date: Fri, 3 Jul 2015 23:33:19 +0200 Subject: [PATCH 27/27] Fixed Parallax without normal map in lighting.j3md --- .../Common/MatDefs/Light/Lighting.frag | 9 ++++--- .../Common/MatDefs/Light/Lighting.vert | 16 +++++++++-- .../java/jme3test/material/TestParallax.java | 27 +++++++------------ .../Textures/Terrain/BrickWall/BrickWall.j3m | 5 ++-- .../Textures/Terrain/BrickWall/BrickWall2.j3m | 4 +-- 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag index 107597047..d2ade5199 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag @@ -37,6 +37,7 @@ varying vec3 SpecularSum; #endif #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING) uniform float m_ParallaxHeight; + varying vec3 vViewDirPrlx; #endif #ifdef LIGHTMAP @@ -78,18 +79,18 @@ void main(){ #ifdef STEEP_PARALLAX #ifdef NORMALMAP_PARALLAX //parallax map is stored in the alpha channel of the normal map - newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + newTexCoord = steepParallaxOffset(m_NormalMap, vViewDirPrlx, texCoord, m_ParallaxHeight); #else //parallax map is a texture - newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight); #endif #else #ifdef NORMALMAP_PARALLAX //parallax map is stored in the alpha channel of the normal map - newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + newTexCoord = classicParallaxOffset(m_NormalMap, vViewDirPrlx, texCoord, m_ParallaxHeight); #else //parallax map is a texture - newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight); #endif #endif #else diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert index f92b91fff..df441ed59 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert @@ -48,6 +48,10 @@ varying vec3 lightVec; uniform vec4 g_LightDirection; #endif +#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING) + varying vec3 vViewDirPrlx; +#endif + #ifdef USE_REFLECTION uniform vec3 g_CameraPosition; @@ -107,17 +111,25 @@ void main(){ wvLightPos.w = g_LightPosition.w; vec4 lightColor = g_LightColor; - #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + #if (defined(NORMALMAP) || defined(PARALLAXMAP)) && !defined(VERTEX_LIGHTING) vec3 wvTangent = normalize(TransformNormal(modelSpaceTan)); vec3 wvBinormal = cross(wvNormal, wvTangent); mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal); + #endif - vViewDir = -wvPosition * tbnMat; + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vViewDir = -wvPosition * tbnMat; + #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) + vViewDirPrlx = vViewDir; + #endif lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; #elif !defined(VERTEX_LIGHTING) vNormal = wvNormal; vViewDir = viewDir; + #if defined(PARALLAXMAP) + vViewDirPrlx = -wvPosition * tbnMat; + #endif lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); #endif diff --git a/jme3-examples/src/main/java/jme3test/material/TestParallax.java b/jme3-examples/src/main/java/jme3test/material/TestParallax.java index 37b5e09b0..f5af57f1f 100644 --- a/jme3-examples/src/main/java/jme3test/material/TestParallax.java +++ b/jme3-examples/src/main/java/jme3test/material/TestParallax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 jMonkeyEngine + * Copyright (c) 2009-2015 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,20 +39,17 @@ import com.jme3.input.controls.KeyTrigger; import com.jme3.light.DirectionalLight; import com.jme3.material.Material; import com.jme3.math.*; -import com.jme3.post.FilterPostProcessor; -import com.jme3.post.filters.FXAAFilter; import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Quad; -import com.jme3.texture.Texture.WrapMode; import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; public class TestParallax extends SimpleApplication { - private Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal(); + private final Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal(); public static void main(String[] args) { TestParallax app = new TestParallax(); @@ -60,7 +57,7 @@ public class TestParallax extends SimpleApplication { } public void setupSkyBox() { - rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false)); + rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap)); } DirectionalLight dl; @@ -75,12 +72,7 @@ public class TestParallax extends SimpleApplication { public void setupFloor() { mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall2.j3m"); - mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat); - mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat); - - // Node floorGeom = (Node) assetManager.loadAsset("Models/WaterTest/WaterTest.mesh.xml"); - //Geometry g = ((Geometry) floorGeom.getChild(0)); - //g.getMesh().scaleTextureCoordinates(new Vector2f(10, 10)); + //mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m"); Node floorGeom = new Node("floorGeom"); Quad q = new Quad(100, 100); @@ -100,9 +92,9 @@ public class TestParallax extends SimpleApplication { public void setupSignpost() { Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); - Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); + Material matSp = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); TangentBinormalGenerator.generate(signpost); - signpost.setMaterial(mat); + signpost.setMaterial(matSp); signpost.rotate(0, FastMath.HALF_PI, 0); signpost.setLocalTranslation(12, 23.5f, 30); signpost.setLocalScale(4); @@ -116,7 +108,6 @@ public class TestParallax extends SimpleApplication { cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f)); flyCam.setMoveSpeed(30); - setupLighting(); setupSkyBox(); setupFloor(); @@ -124,13 +115,14 @@ public class TestParallax extends SimpleApplication { inputManager.addListener(new AnalogListener() { + @Override public void onAnalog(String name, float value, float tpf) { if ("heightUP".equals(name)) { - parallaxHeigh += 0.0001; + parallaxHeigh += 0.01; mat.setFloat("ParallaxHeight", parallaxHeigh); } if ("heightDown".equals(name)) { - parallaxHeigh -= 0.0001; + parallaxHeigh -= 0.01; parallaxHeigh = Math.max(parallaxHeigh, 0); mat.setFloat("ParallaxHeight", parallaxHeigh); } @@ -142,6 +134,7 @@ public class TestParallax extends SimpleApplication { inputManager.addListener(new ActionListener() { + @Override public void onAction(String name, boolean isPressed, float tpf) { if (isPressed && "toggleSteep".equals(name)) { steep = !steep; diff --git a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m index 8b54f9e39..41af10431 100644 --- a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m +++ b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall.j3m @@ -1,8 +1,7 @@ Material Pong Rock : Common/MatDefs/Light/Lighting.j3md { MaterialParameters { Shininess: 2.0 - DiffuseMap : Textures/Terrain/BrickWall/BrickWall.jpg - NormalMap : Textures/Terrain/BrickWall/BrickWall_normal.jpg - ParallaxMap : Textures/Terrain/BrickWall/BrickWall_height.jpg + DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg + ParallaxMap : Repeat Textures/Terrain/BrickWall/BrickWall_height.jpg } } \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m index 7db3ab893..8f90a9454 100644 --- a/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m +++ b/jme3-testdata/src/main/resources/Textures/Terrain/BrickWall/BrickWall2.j3m @@ -1,8 +1,8 @@ Material Pong Rock : Common/MatDefs/Light/Lighting.j3md { MaterialParameters { Shininess: 2.0 - DiffuseMap : Textures/Terrain/BrickWall/BrickWall.jpg - NormalMap : Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds + DiffuseMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg + NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal_parallax.dds PackedNormalParallax: true } } \ No newline at end of file