diff --git a/engine/src/core/com/jme3/texture/TextureArray.java b/engine/src/core/com/jme3/texture/TextureArray.java new file mode 100644 index 000000000..e39d95fa8 --- /dev/null +++ b/engine/src/core/com/jme3/texture/TextureArray.java @@ -0,0 +1,113 @@ +package com.jme3.texture; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements a Texture array + * warning, this feature is only supported on opengl 3.0 version. + * To check if a hardware supports TextureArray check : + * renderManager.getRenderer().getCaps().contains(Caps.TextureArray) + * @author phate666 + */ +public class TextureArray extends Texture { + + private WrapMode wrapS = WrapMode.EdgeClamp; + private WrapMode wrapT = WrapMode.EdgeClamp; + + /** + * Construct a TextureArray + * warning, this feature is only supported on opengl 3.0 version. + * To check if a hardware supports TextureArray check : + * renderManager.getRenderer().getCaps().contains(Caps.TextureArray) + */ + public TextureArray() { + super(); + } + + /** + * Construct a TextureArray from the given list of images + * warning, this feature is only supported on opengl 3.0 version. + * To check if a hardware supports TextureArray check : + * renderManager.getRenderer().getCaps().contains(Caps.TextureArray) + * @param images + */ + public TextureArray(List images) { + super(); + int width = images.get(0).getWidth(); + int height = images.get(0).getHeight(); + Image arrayImage = new Image(images.get(0).getFormat(), width, height, + null); + + for (Image img : images) { + if (img.getHeight() != height || img.getWidth() != width) { + Logger.getLogger(TextureArray.class.getName()).log( + Level.WARNING, + "all images must have the same width/height"); + continue; + } + arrayImage.addData(img.getData(0)); + } + setImage(arrayImage); + } + + @Override + public Texture createSimpleClone() { + TextureArray clone = new TextureArray(); + createSimpleClone(clone); + return clone; + } + + @Override + public Texture createSimpleClone(Texture rVal) { + rVal.setWrap(WrapAxis.S, wrapS); + rVal.setWrap(WrapAxis.T, wrapT); + return super.createSimpleClone(rVal); + } + + @Override + public Type getType() { + return Type.TwoDimensionalArray; + } + + @Override + public WrapMode getWrap(WrapAxis axis) { + switch (axis) { + case S: + return wrapS; + case T: + return wrapT; + default: + throw new IllegalArgumentException("invalid WrapAxis: " + axis); + } + } + + @Override + public void setWrap(WrapAxis axis, WrapMode mode) { + if (mode == null) { + throw new IllegalArgumentException("mode can not be null."); + } else if (axis == null) { + throw new IllegalArgumentException("axis can not be null."); + } + switch (axis) { + case S: + this.wrapS = mode; + break; + case T: + this.wrapT = mode; + break; + default: + throw new IllegalArgumentException("Not applicable for 2D textures"); + } + } + + @Override + public void setWrap(WrapMode mode) { + if (mode == null) { + throw new IllegalArgumentException("mode can not be null."); + } + this.wrapS = mode; + this.wrapT = mode; + } +} \ No newline at end of file diff --git a/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/TextureUtil.java b/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/TextureUtil.java index 10c6c604d..dc5dbae38 100644 --- a/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/TextureUtil.java +++ b/engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/TextureUtil.java @@ -474,7 +474,7 @@ public class TextureUtil { border, format, dataType, - 0); + data); }else{ glTexSubImage3D(target, i, // level diff --git a/engine/src/test/jme3test/texture/TestTextureArray.java b/engine/src/test/jme3test/texture/TestTextureArray.java new file mode 100644 index 000000000..84a726026 --- /dev/null +++ b/engine/src/test/jme3test/texture/TestTextureArray.java @@ -0,0 +1,87 @@ +package jme3test.texture; + + +import java.util.ArrayList; +import java.util.List; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Caps; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.texture.TextureArray; +import com.jme3.util.BufferUtils; + +public class TestTextureArray extends SimpleApplication +{ + + @Override + public void simpleInitApp() + { + Material mat = new Material(assetManager, "jme3test/texture/UnshadedArray.j3md"); + + for (Caps caps : renderManager.getRenderer().getCaps()) { + System.out.println(caps.name()); + } + if(!renderManager.getRenderer().getCaps().contains(Caps.TextureArray)){ + throw new UnsupportedOperationException("Your hardware does not support TextureArray"); + } + + + Texture tex1 = assetManager.loadTexture( "Textures/Terrain/Pond/Pond.jpg"); + Texture tex2 = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + List images = new ArrayList(); + images.add(tex1.getImage()); + images.add(tex2.getImage()); + TextureArray tex3 = new TextureArray(images); + mat.setTexture("ColorMap", tex3); + + Mesh m = new Mesh(); + Vector3f[] vertices = new Vector3f[8]; + vertices[0] = new Vector3f(0, 0, 0); + vertices[1] = new Vector3f(3, 0, 0); + vertices[2] = new Vector3f(0, 3, 0); + vertices[3] = new Vector3f(3, 3, 0); + + vertices[4] = new Vector3f(3, 0, 0); + vertices[5] = new Vector3f(6, 0, 0); + vertices[6] = new Vector3f(3, 3, 0); + vertices[7] = new Vector3f(6, 3, 0); + + Vector3f[] texCoord = new Vector3f[8]; + texCoord[0] = new Vector3f(0, 0, 0); + texCoord[1] = new Vector3f(1, 0, 0); + texCoord[2] = new Vector3f(0, 1, 0); + texCoord[3] = new Vector3f(1, 1, 0); + + texCoord[4] = new Vector3f(0, 0, 1); + texCoord[5] = new Vector3f(1, 0, 1); + texCoord[6] = new Vector3f(0, 1, 1); + texCoord[7] = new Vector3f(1, 1, 1); + + int[] indexes = { 2, 0, 1, 1, 3, 2 , 6, 4, 5, 5, 7, 6}; + + m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices)); + m.setBuffer(Type.TexCoord, 3, BufferUtils.createFloatBuffer(texCoord)); + m.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indexes)); + m.updateBound(); + + Geometry geom = new Geometry("Mesh", m); + geom.setMaterial(mat); + rootNode.attachChild(geom); + } + + /** + * @param args + */ + public static void main(String[] args) + { + TestTextureArray app = new TestTextureArray(); + app.start(); + } + +} \ No newline at end of file diff --git a/engine/src/test/jme3test/texture/UnshadedArray.frag b/engine/src/test/jme3test/texture/UnshadedArray.frag new file mode 100644 index 000000000..655ff9b5e --- /dev/null +++ b/engine/src/test/jme3test/texture/UnshadedArray.frag @@ -0,0 +1,50 @@ +uniform vec4 m_Color; + +#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) + #define NEED_TEXCOORD1 +#endif + +#ifdef HAS_COLORMAP + uniform sampler2DArray m_ColorMap; +#endif + +#ifdef NEED_TEXCOORD1 + varying vec3 texCoord1; +#endif + +#ifdef HAS_LIGHTMAP + uniform sampler2D m_LightMap; + #ifdef SEPERATE_TEXCOORD + varying vec3 texCoord2; + #endif +#endif + +#ifdef HAS_VERTEXCOLOR + varying vec4 vertColor; +#endif + +void main(){ + vec4 color = vec4(1.0); + + #ifdef HAS_COLORMAP + color *= texture2DArray(m_ColorMap, texCoord1); + #endif + + #ifdef HAS_VERTEXCOLOR + color *= vertColor; + #endif + + #ifdef HAS_COLOR + color *= m_Color; + #endif + + #ifdef HAS_LIGHTMAP + #ifdef SEPARATE_TEXCOORD + color.rgb *= texture2D(m_LightMap, texCoord2).rgb; + #else + color.rgb *= texture2D(m_LightMap, texCoord1).rgb; + #endif + #endif + + gl_FragColor = color; +} \ No newline at end of file diff --git a/engine/src/test/jme3test/texture/UnshadedArray.j3md b/engine/src/test/jme3test/texture/UnshadedArray.j3md new file mode 100644 index 000000000..19af9bf72 --- /dev/null +++ b/engine/src/test/jme3test/texture/UnshadedArray.j3md @@ -0,0 +1,70 @@ +MaterialDef Unshaded { + + MaterialParameters { + TextureArray ColorMap + Texture2D LightMap + Color Color (Color) + Boolean VertexColor + Boolean SeparateTexCoord + + // Texture of the glowing parts of the material + Texture2D GlowMap + // The glow color of the object + Color GlowColor + } + + Technique { + VertexShader GLSL100: jme3test/texture/UnshadedArray.vert + FragmentShader GLSL100: jme3test/texture/UnshadedArray.frag + + WorldParameters { + WorldViewProjectionMatrix + } + + Defines { + SEPARATE_TEXCOORD : SeparateTexCoord + HAS_COLORMAP : ColorMap + HAS_LIGHTMAP : LightMap + HAS_VERTEXCOLOR : VertexColor + HAS_COLOR : Color + } + } + + Technique PreNormalPass { + + VertexShader GLSL100 : Common/MatDefs/SSAO/normal.vert + FragmentShader GLSL100 : Common/MatDefs/SSAO/normal.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + NormalMatrix + } + + RenderState { + + } + + } + + + Technique Glow { + + VertexShader GLSL100: Cjme3test/texture/UnshadedArray.vert + FragmentShader GLSL100: Common/MatDefs/Light/Glow.frag + + WorldParameters { + WorldViewProjectionMatrix + } + + Defines { + HAS_GLOWMAP : GlowMap + HAS_GLOWCOLOR : GlowColor + HAS_COLORMAP // Must be passed so that Unshaded.vert exports texCoord. + } + } + + Technique FixedFunc { + } + +} \ No newline at end of file diff --git a/engine/src/test/jme3test/texture/UnshadedArray.vert b/engine/src/test/jme3test/texture/UnshadedArray.vert new file mode 100644 index 000000000..9d1153c3d --- /dev/null +++ b/engine/src/test/jme3test/texture/UnshadedArray.vert @@ -0,0 +1,38 @@ +uniform mat4 g_WorldViewProjectionMatrix; +attribute vec3 inPosition; + +#if defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) + #define NEED_TEXCOORD1 +#endif + +#ifdef NEED_TEXCOORD1 + attribute vec3 inTexCoord; + varying vec3 texCoord1; +#endif + +#ifdef SEPARATE_TEXCOORD + attribute vec3 inTexCoord2; + varying vec3 texCoord2; +#endif + +#ifdef HAS_VERTEXCOLOR + attribute vec4 inColor; + varying vec4 vertColor; +#endif + +void main(){ + #ifdef NEED_TEXCOORD1 + texCoord1 = inTexCoord; + #endif + + #ifdef SEPARATE_TEXCOORD + texCoord2 = inTexCoord2; + #endif + + #ifdef HAS_VERTEXCOLOR + vertColor = inColor; + #endif + + gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0); +} +