diff --git a/VulkanDesign.txt b/VulkanDesign.txt new file mode 100644 index 0000000000..b42da4d728 --- /dev/null +++ b/VulkanDesign.txt @@ -0,0 +1,7 @@ +Spatial: Current problems: + + * The transform refresh only works when transform setter methods are used. I propose that the world transform should be recalculated on every frame. It will make the system a lot simpler, I think. + * An explicit world light list is unnecessary. All that needs to be done to capture all lights affecting a spatial is to iterate up the hierarchy and collect lights from the local light lists. Iterating up the hierarchy is extremely cheap and I want to take more advantage of it. + * There should be at most one method in Spatial for iterating over an entire tree. It should use depth-first traversal. Breadth-first traversal isn't used within the engine and is obviously more expensive. collideWith() is also counted as a traversal method. If possible, I'd like to take more advantage of SceneGraphIterator, since I think it is the most powerful traversal available. + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b56daa8a7..b08ae5bd7f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,6 +34,8 @@ lwjgl3-opencl = { module = "org.lwjgl:lwjgl-opencl", version.ref = "lwjgl3" lwjgl3-opengl = { module = "org.lwjgl:lwjgl-opengl", version.ref = "lwjgl3" } lwjgl3-openvr = { module = "org.lwjgl:lwjgl-openvr", version.ref = "lwjgl3" } lwjgl3-ovr = { module = "org.lwjgl:lwjgl-ovr", version.ref = "lwjgl3" } +lwjgl3-vulkan = { module = "org.lwjgl:lwjgl-vulkan", version.ref = "lwjgl3" } +lwjgl3-shaderc = { module = "org.lwjgl:lwjgl-shaderc", version.ref = "lwjgl3" } mokito-core = "org.mockito:mockito-core:3.12.4" diff --git a/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java b/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java index cc25a40d55..15f7ac6816 100644 --- a/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java +++ b/jme3-android/src/main/java/com/jme3/app/state/VideoRecorderAppState.java @@ -43,7 +43,7 @@ import com.jme3.system.JmeSystem; import com.jme3.system.Timer; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.util.AndroidScreenshots; import com.jme3.util.BufferUtils; import java.io.File; @@ -241,7 +241,7 @@ public void addImage(Renderer renderer, FrameBuffer out) { final WorkItem item = freeItems.take(); usedItems.add(item); item.buffer.clear(); - renderer.readFrameBufferWithFormat(out, item.buffer, Image.Format.BGRA8); + renderer.readFrameBufferWithFormat(out, item.buffer, GlImage.Format.BGRA8); executor.submit(new Callable() { @Override diff --git a/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java b/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java index 4dc13519da..f723d6ce76 100644 --- a/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java +++ b/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java @@ -37,7 +37,7 @@ import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import java.io.IOException; @@ -72,7 +72,7 @@ private static void convertARGBtoABGR(int[] src, int srcOff, int[] dst, int dstO @Override public Object load(AssetInfo assetInfo) throws IOException { Bitmap bitmap; - Image.Format format; + GlImage.Format format; int bpp; BitmapFactory.Options options = new BitmapFactory.Options(); @@ -102,15 +102,15 @@ public Object load(AssetInfo assetInfo) throws IOException { switch (bitmap.getConfig()) { case ALPHA_8: - format = Image.Format.Alpha8; + format = GlImage.Format.Alpha8; bpp = 1; break; case ARGB_8888: - format = Image.Format.RGBA8; + format = GlImage.Format.RGBA8; bpp = 4; break; case RGB_565: - format = Image.Format.RGB565; + format = GlImage.Format.RGB565; bpp = 2; break; default: @@ -124,7 +124,7 @@ public Object load(AssetInfo assetInfo) throws IOException { ByteBuffer data = BufferUtils.createByteBuffer(bitmap.getWidth() * bitmap.getHeight() * bpp); - if (format == Image.Format.RGBA8) { + if (format == GlImage.Format.RGBA8) { int[] pixelData = new int[width * height]; bitmap.getPixels(pixelData, 0, width, 0, 0, width, height); @@ -163,7 +163,7 @@ public Object load(AssetInfo assetInfo) throws IOException { bitmap.recycle(); - Image image = new Image(format, width, height, data, ColorSpace.sRGB); + GlImage image = new GlImage(format, width, height, data, ColorSpace.sRGB); return image; } diff --git a/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidNativeImageLoader.java b/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidNativeImageLoader.java index c56e51d0f0..754cdf4f34 100644 --- a/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidNativeImageLoader.java +++ b/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidNativeImageLoader.java @@ -34,7 +34,7 @@ import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import java.io.IOException; import java.io.InputStream; @@ -52,10 +52,10 @@ public class AndroidNativeImageLoader implements AssetLoader { System.loadLibrary("decodejme"); } - private static native Image load(InputStream in, boolean flipY, byte[] tmpArray) throws IOException; + private static native GlImage load(InputStream in, boolean flipY, byte[] tmpArray) throws IOException; @Override - public Image load(AssetInfo info) throws IOException { + public GlImage load(AssetInfo info) throws IOException { boolean flip = ((TextureKey) info.getKey()).isFlipY(); try (final InputStream in = info.openStream()) { return load(in, flip, tmpArray); diff --git a/jme3-core/build.gradle b/jme3-core/build.gradle index 58ac362921..b3a96bdab7 100644 --- a/jme3-core/build.gradle +++ b/jme3-core/build.gradle @@ -19,6 +19,56 @@ dependencies { testRuntimeOnly project(':jme3-testdata') testImplementation project(':jme3-desktop') testRuntimeOnly project(':jme3-plugins') + + // Use LWJGL3 directly in core. This destroys LWJGL2 and JOGL compatibility. + api (libs.lwjgl3.awt) { + exclude group: 'org.lwjgl', module: 'lwjgl' + } + api libs.lwjgl3.base + api libs.lwjgl3.glfw + api libs.lwjgl3.jawt + api libs.lwjgl3.jemalloc + api libs.lwjgl3.openal + api libs.lwjgl3.opencl + api libs.lwjgl3.opengl + api libs.lwjgl3.vulkan + runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-windows') }) + runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-windows-x86') }) + runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-linux') }) + runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-linux-arm32') }) + runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-linux-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-macos') }) + runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-macos-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.glfw){ classifier('natives-windows') }) + runtimeOnly(variantOf(libs.lwjgl3.glfw){ classifier('natives-windows-x86') }) + runtimeOnly(variantOf(libs.lwjgl3.glfw){ classifier('natives-linux') }) + runtimeOnly(variantOf(libs.lwjgl3.glfw){ classifier('natives-linux-arm32') }) + runtimeOnly(variantOf(libs.lwjgl3.glfw){ classifier('natives-linux-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.glfw){ classifier('natives-macos') }) + runtimeOnly(variantOf(libs.lwjgl3.glfw){ classifier('natives-macos-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.jemalloc){ classifier('natives-windows') }) + runtimeOnly(variantOf(libs.lwjgl3.jemalloc){ classifier('natives-windows-x86') }) + runtimeOnly(variantOf(libs.lwjgl3.jemalloc){ classifier('natives-linux') }) + runtimeOnly(variantOf(libs.lwjgl3.jemalloc){ classifier('natives-linux-arm32') }) + runtimeOnly(variantOf(libs.lwjgl3.jemalloc){ classifier('natives-linux-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.jemalloc){ classifier('natives-macos') }) + runtimeOnly(variantOf(libs.lwjgl3.jemalloc){ classifier('natives-macos-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.opengl){ classifier('natives-windows') }) + runtimeOnly(variantOf(libs.lwjgl3.opengl){ classifier('natives-windows-x86') }) + runtimeOnly(variantOf(libs.lwjgl3.opengl){ classifier('natives-linux') }) + runtimeOnly(variantOf(libs.lwjgl3.opengl){ classifier('natives-linux-arm32') }) + runtimeOnly(variantOf(libs.lwjgl3.opengl){ classifier('natives-linux-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.opengl){ classifier('natives-macos') }) + runtimeOnly(variantOf(libs.lwjgl3.opengl){ classifier('natives-macos-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.openal){ classifier('natives-windows') }) + runtimeOnly(variantOf(libs.lwjgl3.openal){ classifier('natives-windows-x86') }) + runtimeOnly(variantOf(libs.lwjgl3.openal){ classifier('natives-linux') }) + runtimeOnly(variantOf(libs.lwjgl3.openal){ classifier('natives-linux-arm32') }) + runtimeOnly(variantOf(libs.lwjgl3.openal){ classifier('natives-linux-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.openal){ classifier('natives-macos') }) + runtimeOnly(variantOf(libs.lwjgl3.openal){ classifier('natives-macos-arm64') }) + runtimeOnly(variantOf(libs.lwjgl3.shaderc) { classifier('natives-linux') }) + } task updateVersionPropertiesFile { diff --git a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java index 73762a1234..dafc454c13 100644 --- a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java @@ -42,7 +42,7 @@ import com.jme3.scene.Spatial; import com.jme3.scene.plugins.OBJLoader; import com.jme3.shader.ShaderGenerator; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.plugins.TGALoader; import java.io.IOException; import java.io.InputStream; @@ -270,7 +270,7 @@ public default List getClassLoaders() { * * @see AssetManager#loadAsset(com.jme3.asset.AssetKey) */ - public Texture loadTexture(TextureKey key); + public GlTexture loadTexture(TextureKey key); /** * Loads texture file, supported types are BMP, JPG, PNG, GIF, @@ -283,7 +283,7 @@ public default List getClassLoaders() { * * @see AssetManager#loadAsset(com.jme3.asset.AssetKey) */ - public Texture loadTexture(String name); + public GlTexture loadTexture(String name); /** * Load audio file, supported types are WAV or OGG. diff --git a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java index a8ff73f2c4..9edaa4a5d7 100644 --- a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java @@ -44,7 +44,7 @@ import com.jme3.shader.Glsl300ShaderGenerator; import com.jme3.shader.ShaderGenerator; import com.jme3.system.JmeSystem; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -405,7 +405,7 @@ public Object loadAsset(String name) { } @Override - public Texture loadTexture(TextureKey key) { + public GlTexture loadTexture(TextureKey key) { return loadAsset(key); } @@ -415,7 +415,7 @@ public Material loadMaterial(String name) { } @Override - public Texture loadTexture(String name) { + public GlTexture loadTexture(String name) { TextureKey key = new TextureKey(name, true); key.setGenerateMips(true); return loadTexture(key); diff --git a/jme3-core/src/main/java/com/jme3/asset/TextureKey.java b/jme3-core/src/main/java/com/jme3/asset/TextureKey.java index be096de5da..8b9d24a2ca 100644 --- a/jme3-core/src/main/java/com/jme3/asset/TextureKey.java +++ b/jme3-core/src/main/java/com/jme3/asset/TextureKey.java @@ -31,22 +31,22 @@ */ package com.jme3.asset; -import com.jme3.texture.Texture.Type; +import com.jme3.texture.GlTexture.Type; import com.jme3.asset.cache.AssetCache; import com.jme3.asset.cache.WeakRefCloneAssetCache; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.TextureProcessor; import java.io.IOException; /** * Used to load textures from image files such as JPG or PNG. - * Note that texture loaders actually load the asset as an {@link Image} - * object, which is then converted to a {@link Texture} in the + * Note that texture loaders actually load the asset as an {@link GlImage} + * object, which is then converted to a {@link GlTexture} in the * {@link TextureProcessor#postProcess(com.jme3.asset.AssetKey, java.lang.Object)} * method. Since textures are cloneable smart assets, the texture stored * in the cache will be collected when all clones of the texture become @@ -54,12 +54,12 @@ * * @author Kirill Vainer */ -public class TextureKey extends AssetKey { +public class TextureKey extends AssetKey { private boolean generateMips; private boolean flipY; private int anisotropy; - private Texture.Type textureTypeHint = Texture.Type.TwoDimensional; + private GlTexture.Type textureTypeHint = GlTexture.Type.TwoDimensional; public TextureKey(String name, boolean flipY) { super(name); @@ -213,7 +213,7 @@ public void read(JmeImporter im) throws IOException { // Backwards compat textureTypeHint = Type.CubeMap; } else { - textureTypeHint = ic.readEnum("tex_type", Texture.Type.class, Type.TwoDimensional); + textureTypeHint = ic.readEnum("tex_type", GlTexture.Type.class, Type.TwoDimensional); } } } diff --git a/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java b/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java index 6b0e023b34..dd879739a6 100644 --- a/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java +++ b/jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java @@ -43,6 +43,9 @@ import com.jme3.scene.Mesh; import com.jme3.scene.Spatial; import com.jme3.util.TempVars; +import com.jme3.vulkan.mesh.VertexReader; +import com.jme3.vulkan.util.FloatBufferModifier; + import java.io.IOException; import java.nio.FloatBuffer; //import com.jme.scene.TriMesh; @@ -129,6 +132,11 @@ public Type getType() { */ @Override public void computeFromPoints(FloatBuffer points) { + containAABB(new FloatBufferModifier(points, 3)); + } + + @Override + public void computeFromPoints(VertexReader points) { containAABB(points); } @@ -236,21 +244,19 @@ public static void checkMinMax(Vector3f min, Vector3f max, Vector3f point) { * @param points * the list of points. */ - public void containAABB(FloatBuffer points) { + public void containAABB(VertexReader points) { if (points == null) { return; } - points.rewind(); - if (points.remaining() <= 2) // we need at least a 3 float vector + //points.rewind(); + if (points.limit() == 0) // we need at least a 3 float vector { return; } TempVars vars = TempVars.get(); - float[] tmpArray = vars.skinPositions; - float minX = Float.POSITIVE_INFINITY, minY = Float.POSITIVE_INFINITY, minZ = Float.POSITIVE_INFINITY; @@ -258,37 +264,17 @@ public void containAABB(FloatBuffer points) { maxY = Float.NEGATIVE_INFINITY, maxZ = Float.NEGATIVE_INFINITY; - int iterations = (int) FastMath.ceil(points.limit() / ((float) tmpArray.length)); - for (int i = iterations - 1; i >= 0; i--) { - int bufLength = Math.min(tmpArray.length, points.remaining()); - points.get(tmpArray, 0, bufLength); - - for (int j = 0; j < bufLength; j += 3) { - vars.vect1.x = tmpArray[j]; - vars.vect1.y = tmpArray[j + 1]; - vars.vect1.z = tmpArray[j + 2]; - - if (vars.vect1.x < minX) { - minX = vars.vect1.x; - } - if (vars.vect1.x > maxX) { - maxX = vars.vect1.x; - } - - if (vars.vect1.y < minY) { - minY = vars.vect1.y; - } - if (vars.vect1.y > maxY) { - maxY = vars.vect1.y; - } - - if (vars.vect1.z < minZ) { - minZ = vars.vect1.z; - } - if (vars.vect1.z > maxZ) { - maxZ = vars.vect1.z; - } - } + for (int i = 0, l = points.limit(); i < l; i++) { +// vars.vect1.x = tmpArray[j]; +// vars.vect1.y = tmpArray[j + 1]; +// vars.vect1.z = tmpArray[j + 2]; + points.getVector3(i, 0, vars.vect1); + minX = Math.min(minX, vars.vect1.x); + minY = Math.min(minY, vars.vect1.y); + minZ = Math.min(minZ, vars.vect1.z); + maxX = Math.max(maxX, vars.vect1.x); + maxY = Math.max(maxY, vars.vect1.y); + maxZ = Math.max(maxZ, vars.vect1.z); } vars.release(); diff --git a/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java b/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java index 67cf7263f8..a0687efae9 100644 --- a/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java +++ b/jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java @@ -39,8 +39,12 @@ import com.jme3.export.JmeImporter; import com.jme3.math.*; import com.jme3.scene.Spatial; -import com.jme3.util.BufferUtils; import com.jme3.util.TempVars; +import com.jme3.vulkan.mesh.VertexReader; +import com.jme3.vulkan.mesh.VertexWriter; +import com.jme3.vulkan.util.FloatBufferModifier; +import org.lwjgl.system.MemoryStack; + import java.io.IOException; import java.nio.FloatBuffer; import java.util.Objects; @@ -120,6 +124,11 @@ public void setRadius(float radius) { */ @Override public void computeFromPoints(FloatBuffer points) { + calcWelzl(new FloatBufferModifier(points, 3)); + } + + @Override + public void computeFromPoints(VertexReader points) { calcWelzl(points); } @@ -184,15 +193,17 @@ public void computeFromTris(Triangle[] tris, int start, int end) { * @param points * The points to calculate the minimum bounds from. */ - public void calcWelzl(FloatBuffer points) { + public void calcWelzl(VertexReader points) { if (center == null) { center = new Vector3f(); } - FloatBuffer buf = BufferUtils.createFloatBuffer(points.limit()); - points.rewind(); - buf.put(points); - buf.flip(); - recurseMini(buf, buf.limit() / 3, 0, 0); + assert points.components() == 3; + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer buf = stack.mallocFloat(points.limit() * 3); + points.getFloats(0, 0, buf); + FloatBufferModifier bufMod = new FloatBufferModifier(buf, 3); + recurseMini(bufMod, bufMod.limit(), 0, 0); + } } /** @@ -210,7 +221,7 @@ public void calcWelzl(FloatBuffer points) { * A variable simulating pointer arithmetic from C++, and offset * in points. */ - private void recurseMini(FloatBuffer points, int p, int b, int ap) { + private void recurseMini(VertexWriter points, int p, int b, int ap) { //TempVars vars = TempVars.get(); Vector3f tempA = new Vector3f(); //vars.vect1; @@ -225,36 +236,51 @@ private void recurseMini(FloatBuffer points, int p, int b, int ap) { break; case 1: this.radius = 1f - RADIUS_EPSILON; - BufferUtils.populateFromBuffer(center, points, ap - 1); + //BufferUtils.populateFromBuffer(center, points, ap - 1); + points.getVector3(ap - 1, 0, center); break; case 2: - BufferUtils.populateFromBuffer(tempA, points, ap - 1); - BufferUtils.populateFromBuffer(tempB, points, ap - 2); + //BufferUtils.populateFromBuffer(tempA, points, ap - 1); + //BufferUtils.populateFromBuffer(tempB, points, ap - 2); + points.getVector3(ap - 1, 0, tempA); + points.getVector3(ap - 2, 0, tempB); setSphere(tempA, tempB); break; case 3: - BufferUtils.populateFromBuffer(tempA, points, ap - 1); - BufferUtils.populateFromBuffer(tempB, points, ap - 2); - BufferUtils.populateFromBuffer(tempC, points, ap - 3); +// BufferUtils.populateFromBuffer(tempA, points, ap - 1); +// BufferUtils.populateFromBuffer(tempB, points, ap - 2); +// BufferUtils.populateFromBuffer(tempC, points, ap - 3); + points.getVector3(ap - 1, 0, tempA); + points.getVector3(ap - 2, 0, tempB); + points.getVector3(ap - 3, 0, tempC); setSphere(tempA, tempB, tempC); break; case 4: - BufferUtils.populateFromBuffer(tempA, points, ap - 1); - BufferUtils.populateFromBuffer(tempB, points, ap - 2); - BufferUtils.populateFromBuffer(tempC, points, ap - 3); - BufferUtils.populateFromBuffer(tempD, points, ap - 4); +// BufferUtils.populateFromBuffer(tempA, points, ap - 1); +// BufferUtils.populateFromBuffer(tempB, points, ap - 2); +// BufferUtils.populateFromBuffer(tempC, points, ap - 3); +// BufferUtils.populateFromBuffer(tempD, points, ap - 4); + points.getVector3(ap - 1, 0, tempA); + points.getVector3(ap - 2, 0, tempB); + points.getVector3(ap - 3, 0, tempC); + points.getVector3(ap - 4, 0, tempD); setSphere(tempA, tempB, tempC, tempD); //vars.release(); return; } for (int i = 0; i < p; i++) { - BufferUtils.populateFromBuffer(tempA, points, i + ap); + //BufferUtils.populateFromBuffer(tempA, points, i + ap); + points.getVector3(i + ap, 0, tempA); if (tempA.distanceSquared(center) - (radius * radius) > RADIUS_EPSILON - 1f) { for (int j = i; j > 0; j--) { - BufferUtils.populateFromBuffer(tempB, points, j + ap); - BufferUtils.populateFromBuffer(tempC, points, j - 1 + ap); - BufferUtils.setInBuffer(tempC, points, j + ap); - BufferUtils.setInBuffer(tempB, points, j - 1 + ap); +// BufferUtils.populateFromBuffer(tempB, points, j + ap); +// BufferUtils.populateFromBuffer(tempC, points, j - 1 + ap); + points.getVector3(j + ap, 0, tempB); + points.getVector3(j - 1 + ap, 0, tempC); +// BufferUtils.setInBuffer(tempC, points, j + ap); +// BufferUtils.setInBuffer(tempB, points, j - 1 + ap); + points.putVector3(j + ap, 0, tempC); + points.putVector3(j - 1 + ap, 0, tempB); } recurseMini(points, i, b + 1, ap + 1); } @@ -274,7 +300,7 @@ private void recurseMini(FloatBuffer points, int p, int b, int ap) { * The 3rd point inside the sphere. * @param C * The 4th point inside the sphere. - * @see #calcWelzl(java.nio.FloatBuffer) + * @see #calcWelzl(VertexReader) */ private void setSphere(Vector3f O, Vector3f A, Vector3f B, Vector3f C) { Vector3f a = A.subtract(O); @@ -307,7 +333,7 @@ private void setSphere(Vector3f O, Vector3f A, Vector3f B, Vector3f C) { * The 2nd point inside the sphere. * @param B * The 3rd point inside the sphere. - * @see #calcWelzl(java.nio.FloatBuffer) + * @see #calcWelzl(VertexReader) */ private void setSphere(Vector3f O, Vector3f A, Vector3f B) { Vector3f a = A.subtract(O); @@ -335,7 +361,7 @@ private void setSphere(Vector3f O, Vector3f A, Vector3f B) { * The 1st point inside the sphere. * @param A * The 2nd point inside the sphere. - * @see #calcWelzl(java.nio.FloatBuffer) + * @see #calcWelzl(VertexReader) */ private void setSphere(Vector3f O, Vector3f A) { radius = FastMath.sqrt(((A.x - O.x) * (A.x - O.x) + (A.y - O.y) diff --git a/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java b/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java index 3a80764910..7992866a8c 100644 --- a/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java +++ b/jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java @@ -38,6 +38,8 @@ import com.jme3.export.Savable; import com.jme3.math.*; import com.jme3.util.TempVars; +import com.jme3.vulkan.mesh.VertexReader; + import java.io.IOException; import java.nio.FloatBuffer; import java.util.Objects; @@ -149,6 +151,8 @@ public final BoundingVolume transform(Transform trans) { */ public abstract void computeFromPoints(FloatBuffer points); + public abstract void computeFromPoints(VertexReader points); + /** * merge combines two bounding volumes into a single bounding * volume that contains both this bounding volume and the parameter volume. diff --git a/jme3-core/src/main/java/com/jme3/collision/bih/BIHTree.java b/jme3-core/src/main/java/com/jme3/collision/bih/BIHTree.java index fca434f750..62747b44ae 100644 --- a/jme3-core/src/main/java/com/jme3/collision/bih/BIHTree.java +++ b/jme3-core/src/main/java/com/jme3/collision/bih/BIHTree.java @@ -47,16 +47,12 @@ import com.jme3.math.Vector3f; import com.jme3.scene.CollisionData; import com.jme3.scene.Mesh; -import com.jme3.scene.Mesh.Mode; -import com.jme3.scene.VertexBuffer; -import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.mesh.IndexBuffer; -import com.jme3.scene.mesh.VirtualIndexBuffer; -import com.jme3.scene.mesh.WrappedIndexBuffer; import com.jme3.util.TempVars; +import com.jme3.vulkan.mesh.VertexReader; + import java.io.IOException; import static java.lang.Math.max; -import java.nio.FloatBuffer; public class BIHTree implements CollisionData { @@ -72,24 +68,25 @@ public class BIHTree implements CollisionData { // private transient CollisionResults boundResults = new CollisionResults(); private transient float[] bihSwapTmp; - private void initTriList(FloatBuffer vb, IndexBuffer ib) { + private void initTriList(VertexReader vb, IndexBuffer ib) { pointData = new float[numTris * 3 * 3]; int p = 0; + for (int i = 0; i < numTris * 3; i += 3) { int vert = ib.get(i) * 3; - pointData[p++] = vb.get(vert++); - pointData[p++] = vb.get(vert++); - pointData[p++] = vb.get(vert); + pointData[p++] = vb.getFloat(vert, 0); + pointData[p++] = vb.getFloat(vert, 1); + pointData[p++] = vb.getFloat(vert, 2); vert = ib.get(i + 1) * 3; - pointData[p++] = vb.get(vert++); - pointData[p++] = vb.get(vert++); - pointData[p++] = vb.get(vert); + pointData[p++] = vb.getFloat(vert, 0); + pointData[p++] = vb.getFloat(vert, 1); + pointData[p++] = vb.getFloat(vert, 2); vert = ib.get(i + 2) * 3; - pointData[p++] = vb.get(vert++); - pointData[p++] = vb.get(vert++); - pointData[p++] = vb.get(vert); + pointData[p++] = vb.getFloat(vert, 0); + pointData[p++] = vb.getFloat(vert, 1); + pointData[p++] = vb.getFloat(vert, 2); } triIndices = new int[numTris]; @@ -98,6 +95,14 @@ private void initTriList(FloatBuffer vb, IndexBuffer ib) { } } + public BIHTree(VertexReader positions, IndexBuffer indices) { + maxTrisPerNode = MAX_TRIS_PER_NODE; + bihSwapTmp = new float[9]; + numTris = indices.size() / 3; + initTriList(positions, indices); + } + + @Deprecated public BIHTree(Mesh mesh, int maxTrisPerNode) { this.mesh = mesh; this.maxTrisPerNode = maxTrisPerNode; @@ -111,21 +116,23 @@ public BIHTree(Mesh mesh, int maxTrisPerNode) { bihSwapTmp = new float[9]; - VertexBuffer vBuffer = mesh.getBuffer(Type.Position); - if (vBuffer == null) { - throw new IllegalArgumentException("A mesh should at least contain a Position buffer"); - } - IndexBuffer ib = mesh.getIndexBuffer(); - FloatBuffer vb = (FloatBuffer) vBuffer.getData(); + // Code incompatible with new Mesh interface - if (ib == null) { - ib = new VirtualIndexBuffer(mesh.getVertexCount(), mesh.getMode()); - } else if (mesh.getMode() != Mode.Triangles) { - ib = new WrappedIndexBuffer(mesh); - } +// VertexBuffer vBuffer = mesh.getBuffer(Type.Position); +// if (vBuffer == null) { +// throw new IllegalArgumentException("A mesh should at least contain a Position buffer"); +// } +// IndexBuffer ib = mesh.getIndexBuffer(); +// FloatBuffer vb = (FloatBuffer) vBuffer.getData(); + +// if (ib == null) { +// ib = new VirtualIndexBuffer(mesh.getVertexCount(), mesh.getMode()); +// } else if (mesh.getMode() != Mode.Triangles) { +// ib = new WrappedIndexBuffer(mesh); +// } - numTris = ib.size() / 3; - initTriList(vb, ib); + //numTris = ib.size() / 3; + //initTriList(vb, ib); } public BIHTree(Mesh mesh) { diff --git a/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java b/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java index b4333ae9f8..f685fcfbb0 100644 --- a/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java +++ b/jme3-core/src/main/java/com/jme3/effect/ParticleMesh.java @@ -33,7 +33,7 @@ import com.jme3.math.Matrix3f; import com.jme3.renderer.Camera; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; /** * The ParticleMesh is the underlying visual implementation of a @@ -41,7 +41,7 @@ * * @author Kirill Vainer */ -public abstract class ParticleMesh extends Mesh { +public abstract class ParticleMesh extends GlMesh { /** * Type of particle mesh diff --git a/jme3-core/src/main/java/com/jme3/environment/EnvironmentCamera.java b/jme3-core/src/main/java/com/jme3/environment/EnvironmentCamera.java index 2f8ee78d9b..729018e20a 100644 --- a/jme3-core/src/main/java/com/jme3/environment/EnvironmentCamera.java +++ b/jme3-core/src/main/java/com/jme3/environment/EnvironmentCamera.java @@ -66,7 +66,7 @@ public class EnvironmentCamera extends BaseAppState { protected static Vector3f[] axisY = new Vector3f[6]; protected static Vector3f[] axisZ = new Vector3f[6]; - protected Image.Format imageFormat = Image.Format.RGB16F; + protected GlImage.Format imageFormat = GlImage.Format.RGB16F; public TextureCubeMap debugEnv; @@ -98,7 +98,7 @@ public class EnvironmentCamera extends BaseAppState { axisZ[5] = Vector3f.UNIT_Z.mult(-1f); } - protected Image images[]; + protected GlImage images[]; protected ViewPort[] viewports; protected FrameBuffer[] framebuffers; protected ByteBuffer[] buffers; @@ -146,7 +146,7 @@ public EnvironmentCamera(int size, Vector3f position) { * @param position the position of the camera. * @param imageFormat the ImageFormat to use for the resulting texture. */ - public EnvironmentCamera(int size, Vector3f position, Image.Format imageFormat) { + public EnvironmentCamera(int size, Vector3f position, GlImage.Format imageFormat) { this.size = size; this.position.set(position); this.imageFormat = imageFormat; @@ -183,7 +183,7 @@ public void render(final RenderManager renderManager) { size * size * imageFormat.getBitsPerPixel() / 8); renderManager.getRenderer().readFrameBufferWithFormat( framebuffers[i], buffers[i], imageFormat); - images[i] = new Image(imageFormat, size, size, buffers[i], + images[i] = new GlImage(imageFormat, size, size, buffers[i], ColorSpace.Linear); MipMapGenerator.generateMipMaps(images[i]); } @@ -299,7 +299,7 @@ protected void initialize(Application app) { viewports = new ViewPort[6]; framebuffers = new FrameBuffer[6]; buffers = new ByteBuffer[6]; - images = new Image[6]; + images = new GlImage[6]; for (int i = 0; i < 6; i++) { cameras[i] = createOffCamera(size, position, axisX[i], axisY[i], axisZ[i]); @@ -318,7 +318,7 @@ protected void cleanup(Application app) { frameBuffer.dispose(); } - for (final Image image : images) { + for (final GlImage image : images) { if (image != null) { image.dispose(); } @@ -330,7 +330,7 @@ protected void cleanup(Application app) { * * @return the enum value */ - public Image.Format getImageFormat() { + public GlImage.Format getImageFormat() { return imageFormat; } @@ -386,7 +386,7 @@ protected ViewPort createOffViewPort(final String name, final Camera offCamera) protected FrameBuffer createOffScreenFrameBuffer(int mapSize, ViewPort offView) { // create offscreen framebuffer final FrameBuffer offBuffer = new FrameBuffer(mapSize, mapSize, 1); - offBuffer.setDepthBuffer(Image.Format.Depth); + offBuffer.setDepthBuffer(GlImage.Format.Depth); offView.setOutputFrameBuffer(offBuffer); return offBuffer; } diff --git a/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java b/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java index 6f07fd1c1c..a6e83d96e0 100644 --- a/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java +++ b/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java @@ -49,7 +49,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; /** * A control that automatically handles environment bake and rebake including diff --git a/jme3-core/src/main/java/com/jme3/environment/FastLightProbeFactory.java b/jme3-core/src/main/java/com/jme3/environment/FastLightProbeFactory.java index 12ba5e99c1..0abe35f999 100644 --- a/jme3-core/src/main/java/com/jme3/environment/FastLightProbeFactory.java +++ b/jme3-core/src/main/java/com/jme3/environment/FastLightProbeFactory.java @@ -40,7 +40,7 @@ import com.jme3.renderer.RenderManager; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; /** * A faster LightProbeFactory that uses GPU accelerated algorithms. diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java b/jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java index 6831914945..2c2a071012 100644 --- a/jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java +++ b/jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java @@ -49,12 +49,12 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.FrameBuffer.FrameBufferTarget; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.TextureCubeMap; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; @@ -236,10 +236,10 @@ protected void startPulling() { * id of face if cubemap or 0 otherwise * @return the ByteBuffer containing the pulled data */ - protected ByteBuffer pull(FrameBuffer fb, Texture env, int faceId) { + protected ByteBuffer pull(FrameBuffer fb, GlTexture env, int faceId) { - if (fb.getColorTarget().getFormat() != env.getImage().getFormat()) - throw new IllegalArgumentException("Format mismatch: " + fb.getColorTarget().getFormat() + "!=" + env.getImage().getFormat()); + if (fb.getColorTarget().getFormat() != env.getImage().getGlFormat()) + throw new IllegalArgumentException("Format mismatch: " + fb.getColorTarget().getFormat() + "!=" + env.getImage().getGlFormat()); ByteBuffer face = BufferUtils.createByteBuffer(fb.getWidth() * fb.getHeight() * (fb.getColorTarget().getFormat().getBitsPerPixel() / 8)); renderManager.getRenderer().readFrameBufferWithFormat(fb, face, fb.getColorTarget().getFormat()); @@ -269,7 +269,7 @@ protected ByteBuffer pull(FrameBuffer fb, Texture env, int faceId) { * @param tx * the texture to pull into */ - protected void endPulling(Texture tx) { + protected void endPulling(GlTexture tx) { for (int i = 0; i < bos.size(); i++) { ByteArrayOutputStream bo = bos.get(i); if (bo != null) { diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java b/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java index 5b79a4922f..820d7ce4dd 100644 --- a/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java +++ b/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java @@ -44,10 +44,10 @@ import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.texture.TextureCubeMap; import com.jme3.texture.FrameBuffer.FrameBufferTarget; @@ -98,7 +98,7 @@ public IBLGLEnvBaker(RenderManager rm, AssetManager am, Format format, Format de int[] sizes = new int[nbMipMaps]; for (int i = 0; i < nbMipMaps; i++) { int size = (int) FastMath.pow(2, nbMipMaps - 1 - i); - sizes[i] = size * size * (specular.getImage().getFormat().getBitsPerPixel() / 8); + sizes[i] = size * size * (specular.getImage().getGlFormat().getBitsPerPixel() / 8); } specular.getImage().setMipMapSizes(sizes); diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBakerLight.java b/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBakerLight.java index f6284f14ea..c28c6b1266 100644 --- a/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBakerLight.java +++ b/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBakerLight.java @@ -45,10 +45,10 @@ import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.image.ColorSpace; import com.jme3.texture.image.ImageRaster; import com.jme3.util.BufferUtils; @@ -149,7 +149,7 @@ public void bakeSphericalHarmonicsCoefficients() { renderManager.getRenderer().readFrameBufferWithFormat(shbaker[renderOnT], shCoefRaw, shbaker[renderOnT].getColorTarget().getFormat()); shCoefRaw.rewind(); - Image img = new Image(format, NUM_SH_COEFFICIENT, 1, shCoefRaw, ColorSpace.Linear); + GlImage img = new GlImage(format, NUM_SH_COEFFICIENT, 1, shCoefRaw, ColorSpace.Linear); ImageRaster imgr = ImageRaster.create(img); shCoef = new Vector3f[NUM_SH_COEFFICIENT]; diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/IBLHybridEnvBakerLight.java b/jme3-core/src/main/java/com/jme3/environment/baker/IBLHybridEnvBakerLight.java index 26b3c1cd65..facf2c7f43 100644 --- a/jme3-core/src/main/java/com/jme3/environment/baker/IBLHybridEnvBakerLight.java +++ b/jme3-core/src/main/java/com/jme3/environment/baker/IBLHybridEnvBakerLight.java @@ -46,10 +46,10 @@ import com.jme3.texture.FrameBuffer; import com.jme3.texture.TextureCubeMap; import com.jme3.texture.FrameBuffer.FrameBufferTarget; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.image.ColorSpace; /** @@ -97,7 +97,7 @@ public IBLHybridEnvBakerLight(RenderManager rm, AssetManager am, Format format, int[] sizes = new int[nbMipMaps]; for (int i = 0; i < nbMipMaps; i++) { int size = (int) FastMath.pow(2, nbMipMaps - 1 - i); - sizes[i] = size * size * (specular.getImage().getFormat().getBitsPerPixel() / 8); + sizes[i] = size * size * (specular.getImage().getGlFormat().getBitsPerPixel() / 8); } specular.getImage().setMipMapSizes(sizes); specular.getImage().setMipmapsGenerated(true); diff --git a/jme3-core/src/main/java/com/jme3/environment/util/BoundingSphereDebug.java b/jme3-core/src/main/java/com/jme3/environment/util/BoundingSphereDebug.java index 622164e4a1..affcb101a1 100644 --- a/jme3-core/src/main/java/com/jme3/environment/util/BoundingSphereDebug.java +++ b/jme3-core/src/main/java/com/jme3/environment/util/BoundingSphereDebug.java @@ -36,7 +36,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import com.jme3.util.BufferUtils; import java.nio.FloatBuffer; @@ -49,7 +49,7 @@ * * @author nehon */ -public class BoundingSphereDebug extends Mesh { +public class BoundingSphereDebug extends GlMesh { protected int vertCount; protected int triCount; diff --git a/jme3-core/src/main/java/com/jme3/environment/util/CubeMapWrapper.java b/jme3-core/src/main/java/com/jme3/environment/util/CubeMapWrapper.java index 322caa92d1..046f02251f 100644 --- a/jme3-core/src/main/java/com/jme3/environment/util/CubeMapWrapper.java +++ b/jme3-core/src/main/java/com/jme3/environment/util/CubeMapWrapper.java @@ -32,7 +32,7 @@ package com.jme3.environment.util; import com.jme3.math.*; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.TextureCubeMap; import com.jme3.texture.image.DefaultImageRaster; import com.jme3.texture.image.MipMapImageRaster; @@ -53,7 +53,7 @@ public class CubeMapWrapper { private final DefaultImageRaster raster; private int[] sizes; private final Vector2f uvs = new Vector2f(); - private final Image image; + private final GlImage image; private final ColorRGBA tmpColor = new ColorRGBA(); @@ -245,7 +245,7 @@ public void initMipMaps(int nbMipMaps) { int totalSize = 0; for (int i = 0; i < nbMipMaps; i++) { int size = (int) pow(2, maxMipMap - 1 - i); - sizes[i] = size * size * image.getFormat().getBitsPerPixel() / 8; + sizes[i] = size * size * image.getGlFormat().getBitsPerPixel() / 8; totalSize += sizes[i]; } diff --git a/jme3-core/src/main/java/com/jme3/environment/util/EnvMapUtils.java b/jme3-core/src/main/java/com/jme3/environment/util/EnvMapUtils.java index 81c12e4a2c..2b62a080f1 100644 --- a/jme3-core/src/main/java/com/jme3/environment/util/EnvMapUtils.java +++ b/jme3-core/src/main/java/com/jme3/environment/util/EnvMapUtils.java @@ -113,8 +113,8 @@ private EnvMapUtils() { * @param format the format of the image * @return a cube map */ - public static TextureCubeMap makeCubeMap(Image rightImg, Image leftImg, Image upImg, Image downImg, Image backImg, Image frontImg, Image.Format format) { - Image cubeImage = new Image(format, leftImg.getWidth(), leftImg.getHeight(), null, ColorSpace.Linear); + public static TextureCubeMap makeCubeMap(GlImage rightImg, GlImage leftImg, GlImage upImg, GlImage downImg, GlImage backImg, GlImage frontImg, GlImage.Format format) { + GlImage cubeImage = new GlImage(format, leftImg.getWidth(), leftImg.getHeight(), null, ColorSpace.Linear); cubeImage.addData(rightImg.getData(0)); cubeImage.addData(leftImg.getData(0)); @@ -129,9 +129,9 @@ public static TextureCubeMap makeCubeMap(Image rightImg, Image leftImg, Image up TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); cubeMap.setAnisotropicFilter(0); - cubeMap.setMagFilter(Texture.MagFilter.Bilinear); - cubeMap.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - cubeMap.setWrap(Texture.WrapMode.EdgeClamp); + cubeMap.setMagFilter(GlTexture.MagFilter.Bilinear); + cubeMap.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); + cubeMap.setWrap(GlTexture.WrapMode.EdgeClamp); return cubeMap; } @@ -151,8 +151,8 @@ public static TextureCubeMap makeCubeMap(Image rightImg, Image leftImg, Image up * @return a new instance */ public static TextureCubeMap duplicateCubeMap(TextureCubeMap sourceMap) { - Image srcImg = sourceMap.getImage(); - Image cubeImage = new Image(srcImg.getFormat(), srcImg.getWidth(), srcImg.getHeight(), null, srcImg.getColorSpace()); + GlImage srcImg = sourceMap.getImage(); + GlImage cubeImage = new GlImage(srcImg.getGlFormat(), srcImg.getWidth(), srcImg.getHeight(), null, srcImg.getColorSpace()); for (ByteBuffer d : srcImg.getData()) { cubeImage.addData(d.duplicate()); @@ -164,7 +164,7 @@ public static TextureCubeMap duplicateCubeMap(TextureCubeMap sourceMap) { cubeMap.setAnisotropicFilter(sourceMap.getAnisotropicFilter()); cubeMap.setMagFilter(sourceMap.getMagFilter()); cubeMap.setMinFilter(sourceMap.getMinFilter()); - cubeMap.setWrap(sourceMap.getWrap(Texture.WrapAxis.S)); + cubeMap.setWrap(sourceMap.getWrap(GlTexture.WrapAxis.S)); return cubeMap; } @@ -621,7 +621,7 @@ public static Node getCubeMapCrossDebugView(TextureCubeMap cubeMap, AssetManager for (int i = 0; i < 6; i++) { pics[i] = new Picture("bla"); - Texture2D tex = new Texture2D(new Image(cubeMap.getImage().getFormat(), size, size, cubeMap.getImage().getData(i), cubeMap.getImage().getColorSpace())); + Texture2D tex = new Texture2D(new GlImage(cubeMap.getImage().getGlFormat(), size, size, cubeMap.getImage().getData(i), cubeMap.getImage().getColorSpace())); pics[i].setTexture(assetManager, tex, true); pics[i].setWidth(size); @@ -678,7 +678,7 @@ public static Node getCubeMapCrossDebugViewWithMipMaps(TextureCubeMap cubeMap, A ByteBuffer data = BufferUtils.createByteBuffer(dataArray); pics[i] = new Picture("bla"); - Texture2D tex = new Texture2D(new Image(cubeMap.getImage().getFormat(), size, size, data, cubeMap.getImage().getColorSpace())); + Texture2D tex = new Texture2D(new GlImage(cubeMap.getImage().getGlFormat(), size, size, data, cubeMap.getImage().getColorSpace())); pics[i].setTexture(assetManager, tex, true); pics[i].setWidth(size); @@ -721,11 +721,11 @@ public static Node getCubeMapCrossDebugViewWithMipMaps(TextureCubeMap cubeMap, A * @param imageFormat the format of the image * @return the initialized Irradiance map */ - public static TextureCubeMap createIrradianceMap(int size, Image.Format imageFormat) { + public static TextureCubeMap createIrradianceMap(int size, GlImage.Format imageFormat) { TextureCubeMap irrMap = new TextureCubeMap(size, size, imageFormat); - irrMap.setMagFilter(Texture.MagFilter.Bilinear); - irrMap.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + irrMap.setMagFilter(GlTexture.MagFilter.Bilinear); + irrMap.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); irrMap.getImage().setColorSpace(ColorSpace.Linear); return irrMap; } @@ -736,11 +736,11 @@ public static TextureCubeMap createIrradianceMap(int size, Image.Format imageFor * @param imageFormat the format of the image * @return the initialized prefiltered env map */ - public static TextureCubeMap createPrefilteredEnvMap(int size, Image.Format imageFormat) { + public static TextureCubeMap createPrefilteredEnvMap(int size, GlImage.Format imageFormat) { TextureCubeMap pem = new TextureCubeMap(size, size, imageFormat); - pem.setMagFilter(Texture.MagFilter.Bilinear); - pem.setMinFilter(Texture.MinFilter.Trilinear); + pem.setMagFilter(GlTexture.MagFilter.Bilinear); + pem.setMinFilter(GlTexture.MinFilter.Trilinear); pem.getImage().setColorSpace(ColorSpace.Linear); int nbMipMap = Math.min(6, (int) (Math.log(size) / Math.log(2))); CubeMapWrapper targetWrapper = new CubeMapWrapper(pem); diff --git a/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java b/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java index c4ac9b26f0..9a34f82b41 100644 --- a/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java +++ b/jme3-core/src/main/java/com/jme3/font/BitmapTextPage.java @@ -34,6 +34,7 @@ import com.jme3.material.Material; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; import com.jme3.texture.Texture2D; @@ -59,7 +60,7 @@ class BitmapTextPage extends Geometry { private final LinkedList pageQuads = new LinkedList<>(); BitmapTextPage(BitmapFont font, boolean arrayBased, int page) { - super("BitmapFont", new Mesh()); + super("BitmapFont", new GlMesh()); setRequiresUpdates(false); setBatchHint(BatchHint.Never); if (font == null) { diff --git a/jme3-core/src/main/java/com/jme3/material/GlMaterial.java b/jme3-core/src/main/java/com/jme3/material/GlMaterial.java new file mode 100644 index 0000000000..31992ac35f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/GlMaterial.java @@ -0,0 +1,1294 @@ +/* + * Copyright (c) 2009-2025 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.material; + +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetManager; +import com.jme3.asset.CloneableSmartAsset; +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.light.LightList; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.material.RenderState.FaceCullMode; +import com.jme3.material.TechniqueDef.LightMode; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Matrix4f; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.TextureUnitException; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.Geometry; +import com.jme3.shader.*; +import com.jme3.shader.bufferobject.BufferObject; +import com.jme3.texture.*; +import com.jme3.texture.image.ColorSpace; +import com.jme3.util.ListMap; +import com.jme3.util.SafeArrayList; +import com.jme3.vulkan.buffers.GpuBuffer; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.frames.VersionedResource; +import com.jme3.vulkan.pipelines.Pipeline; +import org.lwjgl.opengl.GL45; + +import java.io.IOException; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Material describes the rendering style for a given + * {@link Geometry}. + *

A material is essentially a list of {@link MatParam parameters}, + * those parameters map to uniforms which are defined in a shader. + * Setting the parameters can modify the behavior of a + * shader. + *

+ * + * @author Kirill Vainer + */ +public class GlMaterial implements Material, CloneableSmartAsset, Cloneable, Savable { + + // Version #2: Fixed issue with RenderState.apply*** flags not getting exported + public static final int SAVABLE_VERSION = 2; + private static final Logger logger = Logger.getLogger(GlMaterial.class.getName()); + + private AssetKey key; + private String name; + private MaterialDef def; + private ListMap paramValues = new ListMap<>(); + private Technique technique; + private HashMap techniques = new HashMap<>(); + private RenderState additionalState = null; + private final RenderState mergedRenderState = new RenderState(); + private boolean transparent = false; + private boolean receivesShadows = false; + private int sortingId = -1; + + @Override + public void setParam(String uniform, String param, Object value) { + setParam(param, value); + } + + /** + * Manages and tracks texture and buffer binding units for rendering. + * Used internally by the Material class. + */ + public static class BindUnits { + /** The current texture unit counter. */ + public int textureUnit = 0; + /** The current buffer unit counter. */ + public int bufferUnit = 0; + } + private BindUnits bindUnits = new BindUnits(); + + /** + * Constructs a new Material instance based on a provided MaterialDef. + * The material's parameters will be initialized with default values from the definition. + * + * @param def The material definition to use (cannot be null). + * @throws IllegalArgumentException if def is null. + */ + public GlMaterial(MaterialDef def) { + if (def == null) { + throw new IllegalArgumentException("Material definition cannot be null"); + } + this.def = def; + + // Load default values from definition (if any) + for (MatParam param : def.getMaterialParams()) { + if (param.getValue() != null) { + setParam(param.getName(), param.getVarType(), param.getValue()); + } + } + } + + /** + * Constructs a new Material by loading its MaterialDef from the asset manager. + * + * @param assetManager The asset manager to load the MaterialDef from. + * @param defName The asset path of the .j3md file. + */ + public GlMaterial(AssetManager assetManager, String defName) { + this(assetManager.loadAsset(new AssetKey(defName))); + } + + /** + * For serialization only. Do not use. + */ + public GlMaterial() { + } + + /** + * Returns the asset key name of the asset from which this material was loaded. + *

This value will be null unless this material was loaded from a .j3m file.

+ * + * @return Asset key name of the .j3m file, or null if not loaded from a file. + */ + public String getAssetName() { + return key != null ? key.getName() : null; + } + + /** + * Returns the user-defined name of the material. + * This name is distinct from the asset name and may be null or not unique. + * + * @return The name of the material, or null. + */ + public String getName() { + return name; + } + + /** + * Sets the user-defined name of the material. + * The name is not the same as the asset name. + * It can be null, and there is no guarantee of its uniqueness. + * + * @param name The name of the material. + */ + public void setName(String name) { + this.name = name; + } + + @Override + public void setKey(AssetKey key) { + this.key = key; + } + + @Override + public AssetKey getKey() { + return key; + } + + /** + * Returns the sorting ID or sorting index for this material. + * + *

The sorting ID is used internally by the system to sort rendering + * of geometries. It sorted to reduce shader switches, if the shaders + * are equal, then it is sorted by textures. + * + * @return The sorting ID used for sorting geometries for rendering. + */ + public int getSortId() { + if (sortingId == -1 && technique != null) { + sortingId = technique.getSortId() << 16; + int texturesSortId = 17; + for (int i = 0; i < paramValues.size(); i++) { + MatParam param = paramValues.getValue(i); + if (!param.getVarType().isTextureType()) { + continue; + } + GlTexture texture = (GlTexture) param.getValue(); + if (texture == null) { + continue; + } + GlImage image = texture.getImage(); + if (image == null) { + continue; + } + int textureId = image.getNativeObject(); + if (textureId == -1) { + textureId = 0; + } + texturesSortId = texturesSortId * 23 + textureId; + } + sortingId |= texturesSortId & 0xFFFF; + } + return sortingId; + } + + /** + * Clones this material. The result is returned. + */ + @Override + public GlMaterial clone() { + try { + GlMaterial mat = (GlMaterial) super.clone(); + + if (additionalState != null) { + mat.additionalState = additionalState.clone(); + } + mat.technique = null; + mat.techniques = new HashMap(); + + mat.paramValues = new ListMap(); + for (int i = 0; i < paramValues.size(); i++) { + Map.Entry entry = paramValues.getEntry(i); + mat.paramValues.put(entry.getKey(), entry.getValue().clone()); + } + + mat.sortingId = -1; + + return mat; + } catch (CloneNotSupportedException ex) { + throw new AssertionError(ex); + } + } + + /** + * Compares two materials for content equality. + * This methods compare definition, parameters, additional render states. + * Since materials are mutable objects, implementing equals() properly is not possible, + * hence the name contentEquals(). + * + * @param otherObj the material to compare to this material + * @return true if the materials are equal. + */ + public boolean contentEquals(Object otherObj) { + if (!(otherObj instanceof GlMaterial)) { + return false; + } + + GlMaterial other = (GlMaterial) otherObj; + + // Early exit if the material are the same object + if (this == other) { + return true; + } + + // Check material definition + if (this.getMaterialDef() != other.getMaterialDef()) { + return false; + } + + // Early exit if the size of the params is different + if (this.paramValues.size() != other.paramValues.size()) { + return false; + } + + // Checking technique + if (this.technique != null || other.technique != null) { + // Techniques are considered equal if their names are the same + // E.g. if user chose custom technique for one material but + // uses default technique for other material, the materials + // are not equal. + String thisDefName = this.technique != null + ? this.technique.getDef().getName() + : TechniqueDef.DEFAULT_TECHNIQUE_NAME; + + String otherDefName = other.technique != null + ? other.technique.getDef().getName() + : TechniqueDef.DEFAULT_TECHNIQUE_NAME; + + if (!thisDefName.equals(otherDefName)) { + return false; + } + } + + // Comparing parameters + for (String paramKey : paramValues.keySet()) { + MatParam thisParam = this.getParam(paramKey); + MatParam otherParam = other.getParam(paramKey); + + // This param does not exist in compared mat + if (otherParam == null) { + return false; + } + + if (!otherParam.equals(thisParam)) { + return false; + } + } + + // Comparing additional render states + if (additionalState == null) { + if (other.additionalState != null) { + return false; + } + } else { + if (!additionalState.equals(other.additionalState)) { + return false; + } + } + + return true; + } + + /** + * Works like {@link Object#hashCode() } except it may change together with the material as the material is mutable by definition. + * + * @return value for use in hashing + */ + public int contentHashCode() { + int hash = 7; + hash = 29 * hash + (this.def != null ? this.def.hashCode() : 0); + hash = 29 * hash + (this.paramValues != null ? this.paramValues.hashCode() : 0); + hash = 29 * hash + (this.technique != null ? this.technique.getDef().getName().hashCode() : 0); + hash = 29 * hash + (this.additionalState != null ? this.additionalState.contentHashCode() : 0); + return hash; + } + + /** + * Returns the currently active technique. + *

+ * The technique is selected automatically by the {@link RenderManager} + * based on system capabilities. Users may select their own + * technique by using + * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) }. + * + * @return the currently active technique. + * + * @see #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) + */ + public Technique getActiveTechnique() { + return technique; + } + + /** + * Check if the transparent value marker is set on this material. + * @return True if the transparent value marker is set on this material. + * @see #setTransparent(boolean) + */ + public boolean isTransparent() { + return transparent; + } + + /** + * Set the transparent value marker. + * + *

This value is merely a marker, by itself it does nothing. + * Generally model loaders will use this marker to indicate further + * up that the material is transparent and therefore any geometries + * using it should be put into the {@link Bucket#Transparent transparent + * bucket}. + * + * @param transparent the transparent value marker. + */ + public void setTransparent(boolean transparent) { + this.transparent = transparent; + } + + /** + * Check if the material should receive shadows or not. + * + * @return True if the material should receive shadows. + * + * @see GlMaterial#setReceivesShadows(boolean) + */ + public boolean isReceivesShadows() { + return receivesShadows; + } + + /** + * Set if the material should receive shadows or not. + * + *

This value is merely a marker, by itself it does nothing. + * Generally model loaders will use this marker to indicate + * the material should receive shadows and therefore any + * geometries using it should have {@link com.jme3.renderer.queue.RenderQueue.ShadowMode#Receive} set + * on them. + * + * @param receivesShadows if the material should receive shadows or not. + */ + public void setReceivesShadows(boolean receivesShadows) { + this.receivesShadows = receivesShadows; + } + + /** + * Acquire the additional {@link RenderState render state} to apply + * for this material. + * + *

The first call to this method will create an additional render + * state which can be modified by the user to apply any render + * states in addition to the ones used by the renderer. Only render + * states which are modified in the additional render state will be applied. + * + * @return The additional render state. + */ + public RenderState getAdditionalRenderState() { + if (additionalState == null) { + additionalState = RenderState.ADDITIONAL.clone(); + } + return additionalState; + } + + /** + * Get the material definition (.j3md file info) that this + * material is implementing. + * + * @return the material definition this material implements. + */ + public MaterialDef getMaterialDef() { + return def; + } + + /** + * Returns the parameter set on this material with the given name, + * returns null if the parameter is not set. + * + * @param name The parameter name to look up. + * @return The MatParam if set, or null if not set. + */ + public MatParam getParam(String name) { + return paramValues.get(name); + } + + /** + * Returns the current parameter's value. + * + * @param the expected type of the parameter value + * @param name the parameter name to look up. + * @return current value or null if the parameter wasn't set. + */ + @SuppressWarnings("unchecked") + public T getParamValue(final String name) { + final MatParam param = paramValues.get(name); + return param == null ? null : (T) param.getValue(); + } + + /** + * Returns the texture parameter set on this material with the given name, + * returns null if the parameter is not set. + * + * @param name The parameter name to look up. + * @return The MatParamTexture if set, or null if not set. + */ + public MatParamTexture getTextureParam(String name) { + MatParam param = paramValues.get(name); + if (param instanceof MatParamTexture) { + return (MatParamTexture) param; + } + return null; + } + + /** + * Returns a collection of all parameters set on this material. + * + * @return a collection of all parameters set on this material. + * + * @see #setParam(java.lang.String, com.jme3.shader.VarType, java.lang.Object) + */ + public Collection getParams() { + return paramValues.values(); + } + + /** + * Returns the ListMap of all parameters set on this material. + * + * @return a ListMap of all parameters set on this material. + * + * @see #setParam(java.lang.String, com.jme3.shader.VarType, java.lang.Object) + */ + public ListMap getParamsMap() { + return paramValues; + } + + /** + * Check if setting the parameter given the type and name is allowed. + * @param type The type that the "set" function is designed to set + * @param name The name of the parameter + */ + private void checkSetParam(VarType type, String name) { + MatParam paramDef = def.getMaterialParam(name); + if (paramDef == null) { + throw new IllegalArgumentException("Material parameter is not defined: " + name); + } + if (type != null && paramDef.getVarType() != type) { + logger.log(Level.WARNING, "Material parameter being set: {0} with " + + "type {1} doesn''t match definition types {2}", new Object[]{name, type.name(), paramDef.getVarType()}); + } + } + + /** + * Pass a parameter to the material shader. + * + * @param name the name of the parameter defined in the material definition (.j3md) + * @param type the type of the parameter {@link VarType} + * @param value the value of the parameter + */ + public void setParam(String name, VarType type, Object value) { + checkSetParam(type, name); + + if (type.isTextureType()) { + setTextureParam(name, type, (GlTexture)value); + } else { + MatParam val = getParam(name); + if (val == null) { + paramValues.put(name, new MatParam(type, name, value)); + } else { + val.setValue(value); + } + + if (technique != null) { + technique.notifyParamChanged(name, type, value); + } + if (type.isImageType()) { + // recompute sort id + sortingId = -1; + } + } + } + + /** + * Pass a parameter to the material shader. + * + * @param name the name of the parameter defined in the material definition (j3md) + * @param value the value of the parameter + */ + @Override + public void setParam(String name, Object value) { + MatParam p = getMaterialDef().getMaterialParam(name); + setParam(name, p.getVarType(), value); + } + + /** + * Clear a parameter from this material. The parameter must exist + * @param name the name of the parameter to clear + */ + public void clearParam(String name) { + checkSetParam(null, name); + MatParam matParam = getParam(name); + if (matParam == null) { + return; + } + + paramValues.remove(name); + if (matParam instanceof MatParamTexture) { + sortingId = -1; + } + if (technique != null) { + technique.notifyParamChanged(name, null, null); + } + } + + /** + * Set a texture parameter. + * + * @param name The name of the parameter + * @param type The variable type {@link VarType} + * @param value The texture value of the parameter. + * + * @throws IllegalArgumentException is value is null + */ + public void setTextureParam(String name, VarType type, GlTexture value) { + if (value == null) { + throw new IllegalArgumentException(); + } + + checkSetParam(type, name); + MatParamTexture param = getTextureParam(name); + + checkTextureParamColorSpace(name, value); + ColorSpace colorSpace = value.getImage() != null ? value.getImage().getColorSpace() : null; + + if (param == null) { + param = new MatParamTexture(type, name, value, colorSpace); + paramValues.put(name, param); + } else { + param.setTextureValue(value); + param.setColorSpace(colorSpace); + } + + if (technique != null) { + technique.notifyParamChanged(name, type, value); + } + + // need to recompute sort ID + sortingId = -1; + } + + private void checkTextureParamColorSpace(String name, GlTexture value) { + MatParamTexture paramDef = (MatParamTexture) def.getMaterialParam(name); + if (paramDef.getColorSpace() != null && paramDef.getColorSpace() != value.getImage().getColorSpace()) { + value.getImage().setColorSpace(paramDef.getColorSpace()); + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Material parameter {0} needs a {1} texture, " + + "texture {2} was switched to {3} color space.", + new Object[]{name, paramDef.getColorSpace().toString(), + value.getName(), + value.getImage().getColorSpace().name()}); + } + } else if (paramDef.getColorSpace() == null && value.getName() != null && value.getImage().getColorSpace() == ColorSpace.Linear) { + logger.log(Level.WARNING, + "The texture {0} has linear color space, but the material " + + "parameter {2} specifies no color space requirement, this may " + + "lead to unexpected behavior.\nCheck if the image " + + "was not set to another material parameter with a linear " + + "color space, or that you did not set the ColorSpace to " + + "Linear using texture.getImage.setColorSpace().", + new Object[]{value.getName(), value.getImage().getColorSpace().name(), name}); + } + } + + /** + * Pass a texture to the material shader. + * + * @param name the name of the texture defined in the material definition + * (.j3md) (e.g. Texture for Lighting.j3md) + * @param value the Texture object previously loaded by the asset manager + */ + @Override + public void setTexture(String name, VersionedResource value) { + if (value == null) { + // clear it + clearParam(name); + return; + } + if (!(value.get() instanceof GlTexture)) { + throw new IllegalArgumentException("Must be a GlTexture."); + } + + VarType paramType = null; + GlTexture.Type type = ((GlTexture)value.get()).getType(); + switch (type) { + case TwoDimensional: + paramType = VarType.Texture2D; + break; + case TwoDimensionalArray: + paramType = VarType.TextureArray; + break; + case ThreeDimensional: + paramType = VarType.Texture3D; + break; + case CubeMap: + paramType = VarType.TextureCubeMap; + break; + default: + throw new UnsupportedOperationException("Unknown texture type: " + type); + } + + setTextureParam(name, paramType, (GlTexture)value); + } + + /** + * Pass a Matrix4f to the material shader. + * + * @param name the name of the matrix defined in the material definition (j3md) + * @param value the Matrix4f object + */ + @Override + public void setMatrix4(String name, Matrix4f value) { + setParam(name, VarType.Matrix4, value); + } + + /** + * Pass a boolean to the material shader. + * + * @param name the name of the boolean defined in the material definition (j3md) + * @param value the boolean value + */ + @Override + public void setBoolean(String name, boolean value) { + setParam(name, VarType.Boolean, value); + } + + /** + * Pass a float to the material shader. + * + * @param name the name of the float defined in the material definition (j3md) + * @param value the float value + */ + @Override + public void setFloat(String name, float value) { + setParam(name, VarType.Float, value); + } + + /** + * Pass a float to the material shader. This version avoids auto-boxing + * if the value is already a Float. + * + * @param name the name of the float defined in the material definition (j3md) + * @param value the float value + */ + @Override + public void setFloat(String name, Float value) { + setParam(name, VarType.Float, value); + } + + /** + * Pass an int to the material shader. + * + * @param name the name of the int defined in the material definition (j3md) + * @param value the int value + */ + @Override + public void setInt(String name, int value) { + setParam(name, VarType.Int, value); + } + + /** + * Pass a Color to the material shader. + * + * @param name the name of the color defined in the material definition (j3md) + * @param value the ColorRGBA value + */ + @Override + public void setColor(String name, ColorRGBA value) { + setParam(name, VarType.Vector4, value); + } + + /** + * Pass a uniform buffer object to the material shader. + * + * @param name the name of the buffer object defined in the material definition (j3md). + * @param value the buffer object. + */ + public void setUniformBufferObject(final String name, final BufferObject value) { + setParam(name, VarType.UniformBufferObject, value); + } + + /** + * Pass a shader storage buffer object to the material shader. + * + * @param name the name of the buffer object defined in the material definition (j3md). + * @param value the buffer object. + */ + public void setShaderStorageBufferObject(final String name, final BufferObject value) { + setParam(name, VarType.ShaderStorageBufferObject, value); + } + + @Override + public void setUniform(String name, VersionedResource buffer) { + + } + + /** + * Pass a Vector2f to the material shader. + * + * @param name the name of the Vector2f defined in the material definition (j3md) + * @param value the Vector2f value + */ + @Override + public void setVector2(String name, Vector2f value) { + setParam(name, VarType.Vector2, value); + } + + /** + * Pass a Vector3f to the material shader. + * + * @param name the name of the Vector3f defined in the material definition (j3md) + * @param value the Vector3f value + */ + @Override + public void setVector3(String name, Vector3f value) { + setParam(name, VarType.Vector3, value); + } + + /** + * Pass a Vector4f to the material shader. + * + * @param name the name of the Vector4f defined in the material definition (j3md) + * @param value the Vector4f value + */ + @Override + public void setVector4(String name, Vector4f value) { + setParam(name, VarType.Vector4, value); + } + + /** + * Select the technique to use for rendering this material. + *

+ * Any candidate technique for selection (either default or named) + * must be verified to be compatible with the system, for that, the + * renderManager is queried for capabilities. + * + * @param name The name of the technique to select, pass + * {@link TechniqueDef#DEFAULT_TECHNIQUE_NAME} to select one of the default + * techniques. + * @param renderManager The {@link RenderManager render manager} + * to query for capabilities. + * + * @throws IllegalArgumentException If no technique exists with the given + * name. + * @throws UnsupportedOperationException If no candidate technique supports + * the system capabilities. + */ + public void selectTechnique(String name, final RenderManager renderManager) { + // check if already created + Technique tech = techniques.get(name); + // When choosing technique, we choose one that + // supports all the caps. + if (tech == null) { + EnumSet rendererCaps = renderManager.getRenderer().getCaps(); + List techDefs = def.getTechniqueDefs(name); + if (techDefs == null || techDefs.isEmpty()) { + throw new IllegalArgumentException( + String.format("The requested technique %s is not available on material %s", name, def.getName())); + } + + TechniqueDef lastTech = null; + float weight = 0; + for (TechniqueDef techDef : techDefs) { + if (rendererCaps.containsAll(techDef.getRequiredCaps())) { + float techWeight = techDef.getWeight() + (techDef.getLightMode() == renderManager.getPreferredLightMode() ? 10f : 0); + if (techWeight > weight) { + tech = new Technique(this, techDef); + techniques.put(name, tech); + weight = techWeight; + } + } + lastTech = techDef; + } + if (tech == null) { + throw new UnsupportedOperationException( + String.format("No technique '%s' on material " + + "'%s' is supported by the video hardware. " + + "The capabilities %s are required.", + name, def.getName(), lastTech.getRequiredCaps())); + } + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, this.getMaterialDef().getName() + " selected technique def " + tech.getDef()); + } + } else if (technique == tech) { + // attempting to switch to an already + // active technique. + return; + } + + technique = tech; + tech.notifyTechniqueSwitched(); + + // shader was changed + sortingId = -1; + } + + private void applyOverrides(Renderer renderer, Shader shader, SafeArrayList overrides, BindUnits bindUnits) { + for (MatParamOverride override : overrides.getArray()) { + VarType type = override.getVarType(); + + MatParam paramDef = def.getMaterialParam(override.getName()); + + if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) { + continue; + } + + Uniform uniform = shader.getUniform(override.getPrefixedName()); + + if (override.getValue() != null) { + updateShaderMaterialParameter(renderer, type, shader, override, bindUnits, true); + } else { + uniform.clearValue(); + } + } + } + + private void updateShaderMaterialParameter(Renderer renderer, VarType type, Shader shader, MatParam param, BindUnits unit, boolean override) { + if (type == VarType.UniformBufferObject || type == VarType.ShaderStorageBufferObject) { + ShaderBufferBlock bufferBlock = shader.getBufferBlock(param.getPrefixedName()); + BufferObject bufferObject = (BufferObject) param.getValue(); + + ShaderBufferBlock.BufferType btype; + if (type == VarType.ShaderStorageBufferObject) { + btype = ShaderBufferBlock.BufferType.ShaderStorageBufferObject; + bufferBlock.setBufferObject(btype, bufferObject); + renderer.setShaderStorageBufferObject(unit.bufferUnit, bufferObject); // TODO: probably not needed + } else { + btype = ShaderBufferBlock.BufferType.UniformBufferObject; + bufferBlock.setBufferObject(btype, bufferObject); + renderer.setUniformBufferObject(unit.bufferUnit, bufferObject); // TODO: probably not needed + } + unit.bufferUnit++; + } else { + Uniform uniform = shader.getUniform(param.getPrefixedName()); + if (!override && uniform.isSetByCurrentMaterial()) + return; + + if (type.isTextureType() || type.isImageType()) { + try { + if (type.isTextureType()) { + renderer.setTexture(unit.textureUnit, (GlTexture) param.getValue()); + } else { + renderer.setTextureImage(unit.textureUnit, (TextureImage) param.getValue()); + } + } catch (TextureUnitException ex) { + int numTexParams = unit.textureUnit + 1; + String message = "Too many texture parameters (" + numTexParams + ") assigned\n to " + this.toString(); + throw new IllegalStateException(message); + } + uniform.setValue(VarType.Int, unit.textureUnit); + unit.textureUnit++; + } else { + uniform.setValue(type, param.getValue()); + } + } + } + + private BindUnits updateShaderMaterialParameters(Renderer renderer, Shader shader, + SafeArrayList worldOverrides, SafeArrayList forcedOverrides) { + + bindUnits.textureUnit = 0; + bindUnits.bufferUnit = 0; + + if (worldOverrides != null) { + applyOverrides(renderer, shader, worldOverrides, bindUnits); + } + if (forcedOverrides != null) { + applyOverrides(renderer, shader, forcedOverrides, bindUnits); + } + + for (int i = 0; i < paramValues.size(); i++) { + MatParam param = paramValues.getValue(i); + VarType type = param.getVarType(); + updateShaderMaterialParameter(renderer, type, shader, param, bindUnits, false); + } + + // TODO: HACKY HACK remove this when texture unit is handled by the uniform. + return bindUnits; + } + + private void updateRenderState(Geometry geometry, RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) { + RenderState finalRenderState; + if (renderManager.getForcedRenderState() != null) { + finalRenderState = mergedRenderState.copyFrom(renderManager.getForcedRenderState()); + } else if (techniqueDef.getRenderState() != null) { + finalRenderState = mergedRenderState.copyFrom(RenderState.DEFAULT); + finalRenderState = techniqueDef.getRenderState().copyMergedTo(additionalState, finalRenderState); + } else { + finalRenderState = mergedRenderState.copyFrom(RenderState.DEFAULT); + finalRenderState = RenderState.DEFAULT.copyMergedTo(additionalState, finalRenderState); + } + // test if the face cull mode should be flipped before render + if (finalRenderState.isFaceCullFlippable() && isNormalsBackward(geometry.getWorldScale())) { + finalRenderState.flipFaceCull(); + } + renderer.applyRenderState(finalRenderState); + } + + /** + * Returns true if the geometry world scale indicates that normals will be backward. + * + * @param scalar The geometry's world scale vector. + * @return true if the normals are effectively backward; false otherwise. + */ + private boolean isNormalsBackward(Vector3f scalar) { + // count number of negative scalar vector components + int n = 0; + if (scalar.x < 0) n++; + if (scalar.y < 0) n++; + if (scalar.z < 0) n++; + // An odd number of negative components means the normal vectors + // are backward to what they should be. + return n == 1 || n == 3; + } + + /** + * Preloads this material for the given render manager. + *

+ * Preloading the material can ensure that when the material is first + * used for rendering, there won't be any delay since the material has + * been already been setup for rendering. + * + * @param renderManager The render manager to preload for + * @param geometry to determine the applicable parameter overrides, if any + */ + public void preload(RenderManager renderManager, Geometry geometry) { + if (technique == null) { + selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); + } + TechniqueDef techniqueDef = technique.getDef(); + Renderer renderer = renderManager.getRenderer(); + EnumSet rendererCaps = renderer.getCaps(); + + if (techniqueDef.isNoRender()) { + return; + } + // Get world overrides + SafeArrayList overrides = geometry.getWorldMatParamOverrides(); + + Shader shader = technique.makeCurrent(renderManager, overrides, null, null, rendererCaps); + updateShaderMaterialParameters(renderer, shader, overrides, null); + renderManager.getRenderer().setShader(shader); + } + + private void clearUniformsSetByCurrent(Shader shader) { + ListMap uniforms = shader.getUniformMap(); + int size = uniforms.size(); + for (int i = 0; i < size; i++) { + Uniform u = uniforms.getValue(i); + u.clearSetByCurrentMaterial(); + } + } + + private void resetUniformsNotSetByCurrent(Shader shader) { + ListMap uniforms = shader.getUniformMap(); + int size = uniforms.size(); + for (int i = 0; i < size; i++) { + Uniform u = uniforms.getValue(i); + if (!u.isSetByCurrentMaterial()) { + if (u.getName().charAt(0) != 'g') { + // Don't reset world globals! + // The benefits gained from this are very minimal + // and cause lots of matrix -> FloatBuffer conversions. + u.clearValue(); + } + } + } + } + + /** + * Called by {@link RenderManager} to render the geometry by + * using this material. + *

+ * The material is rendered as follows: + *

    + *
  • Determine which technique to use to render the material - + * either what the user selected via + * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) + * Material.selectTechnique()}, + * or the first default technique that the renderer supports + * (based on the technique's {@link TechniqueDef#getRequiredCaps() requested rendering capabilities})
      + *
    • If the technique has been changed since the last frame, then it is notified via + * {@link Technique#makeCurrent(com.jme3.renderer.RenderManager, com.jme3.util.SafeArrayList, com.jme3.util.SafeArrayList, com.jme3.light.LightList, java.util.EnumSet) + * Technique.makeCurrent()}. + * If the technique wants to use a shader to render the model, it should load it at this part - + * the shader should have all the proper defines as declared in the technique definition, + * including those that are bound to material parameters. + * The technique can re-use the shader from the last frame if + * no changes to the defines occurred.
    + *
  • Set the {@link RenderState} to use for rendering. The render states are + * applied in this order (later RenderStates override earlier RenderStates):
      + *
    1. {@link TechniqueDef#getRenderState() Technique Definition's RenderState} + * - i.e. specific RenderState that is required for the shader.
    2. + *
    3. {@link #getAdditionalRenderState() Material Instance Additional RenderState} + * - i.e. ad-hoc RenderState set per model
    4. + *
    5. {@link RenderManager#getForcedRenderState() RenderManager's Forced RenderState} + * - i.e. RenderState requested by a {@link com.jme3.post.SceneProcessor} or + * post-processing filter.
    + *
  • If the technique uses a shader, then the uniforms of the shader must be updated.
      + *
    • Uniforms bound to material parameters are updated based on the current material parameter values.
    • + *
    • Uniforms bound to world parameters are updated from the RenderManager. + * Internally {@link UniformBindingManager} is used for this task.
    • + *
    • Uniforms bound to textures will cause the texture to be uploaded as necessary. + * The uniform is set to the texture unit where the texture is bound.
    + *
  • If the technique uses a shader, the model is then rendered according + * to the lighting mode specified on the technique definition.
      + *
    • {@link LightMode#SinglePass single pass light mode} fills the shader's light uniform arrays + * with the first 4 lights and renders the model once.
    • + *
    • {@link LightMode#MultiPass multi pass light mode} light mode renders the model multiple times, + * for the first light it is rendered opaque, on subsequent lights it is + * rendered with {@link BlendMode#AlphaAdditive alpha-additive} blending and depth writing disabled.
    • + *
    + *
  • For techniques that do not use shaders, + * fixed function OpenGL is used to render the model (see {@link com.jme3.renderer.opengl.GLRenderer} interface):
      + *
    • OpenGL state that is bound to material parameters is updated.
    • + *
    • The texture set on the material is uploaded and bound. + * Currently only 1 texture is supported for fixed function techniques.
    • + *
    • If the technique uses lighting, then OpenGL lighting state is updated + * based on the light list on the geometry, otherwise OpenGL lighting is disabled.
    • + *
    • The mesh is uploaded and rendered.
    • + *
    + *
+ * + * @param geometry The geometry to render + * @param lights Presorted and filtered light list to use for rendering + * @param renderManager The render manager requesting the rendering + */ + @Override + public void render(Geometry geometry, LightList lights, RenderManager renderManager) { + if (technique == null) { + selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); + } + + TechniqueDef techniqueDef = technique.getDef(); + Renderer renderer = renderManager.getRenderer(); + EnumSet rendererCaps = renderer.getCaps(); + + if (techniqueDef.isNoRender()) { + return; + } + + // Apply render state + updateRenderState(geometry, renderManager, renderer, techniqueDef); + + // Get world overrides + SafeArrayList overrides = geometry.getWorldMatParamOverrides(); + + // Select shader to use + Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps); + + // Begin tracking which uniforms were changed by material. + clearUniformsSetByCurrent(shader); + + // Set uniform bindings + renderManager.updateUniformBindings(shader); + + // Set material parameters + BindUnits units = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams()); + + // Clear any uniforms not changed by material. + resetUniformsNotSetByCurrent(shader); + + // Delegate rendering to the technique + technique.render(renderManager, shader, geometry, lights, units); + } + + /** + * Called by {@link RenderManager} to render the geometry by + * using this material. + * + * Note that this version of the render method + * does not perform light filtering. + * + * @param geom The geometry to render + * @param rm The render manager requesting the rendering + */ + public void render(Geometry geom, RenderManager rm) { + render(geom, geom.getWorldLightList(), rm); + } + + @Override + public String toString() { + return "Material[name=" + name + + ", def=" + (def != null ? def.getName() : null) + + ", tech=" + (technique != null && technique.getDef() != null ? technique.getDef().getName() : null) + + "]"; + } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule oc = ex.getCapsule(this); + oc.write(def.getAssetName(), "material_def", null); + oc.write(additionalState, "render_state", null); + oc.write(transparent, "is_transparent", false); + oc.write(name, "name", null); + oc.writeStringSavableMap(paramValues, "parameters", null); + } + + @Override + @SuppressWarnings("unchecked") + public void read(JmeImporter im) throws IOException { + InputCapsule ic = im.getCapsule(this); + + name = ic.readString("name", null); + additionalState = (RenderState) ic.readSavable("render_state", null); + transparent = ic.readBoolean("is_transparent", false); + + // Load the material def + String defName = ic.readString("material_def", null); + HashMap params = (HashMap) ic.readStringSavableMap("parameters", null); + + boolean enableVertexColor = false; + boolean separateTexCoord = false; + boolean applyDefaultValues = false; + boolean guessRenderStateApply = false; + + int ver = ic.getSavableVersion(Material.class); + if (ver < 1) { + applyDefaultValues = true; + } + if (ver < 2) { + guessRenderStateApply = true; + } + if (im.getFormatVersion() == 0) { + // Enable compatibility with old models + if (defName.equalsIgnoreCase("Common/MatDefs/Misc/VertexColor.j3md")) { + // Using VertexColor, switch to Unshaded and set VertexColor=true + enableVertexColor = true; + defName = "Common/MatDefs/Misc/Unshaded.j3md"; + } else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/SimpleTextured.j3md") + || defName.equalsIgnoreCase("Common/MatDefs/Misc/SolidColor.j3md")) { + // Using SimpleTextured/SolidColor, just switch to Unshaded + defName = "Common/MatDefs/Misc/Unshaded.j3md"; + } else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/WireColor.j3md")) { + // Using WireColor, set wireframe render state = true and use Unshaded + getAdditionalRenderState().setWireframe(true); + defName = "Common/MatDefs/Misc/Unshaded.j3md"; + } else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/Unshaded.j3md")) { + // Uses unshaded, ensure that the proper param is set + MatParam value = params.get("SeperateTexCoord"); + if (value != null && ((Boolean) value.getValue()) == true) { + params.remove("SeperateTexCoord"); + separateTexCoord = true; + } + } + assert applyDefaultValues && guessRenderStateApply; + } + + def = im.getAssetManager().loadAsset(new AssetKey(defName)); + paramValues = new ListMap(); + + // load the textures and update nextTexUnit + for (Map.Entry entry : params.entrySet()) { + MatParam param = entry.getValue(); + if (param instanceof MatParamTexture) { + MatParamTexture texVal = (MatParamTexture) param; + // the texture failed to load for this param + // do not add to param values + if (texVal.getTextureValue() == null || texVal.getTextureValue().getImage() == null) { + continue; + } + checkTextureParamColorSpace(texVal.getName(), texVal.getTextureValue()); + } + + if (im.getFormatVersion() == 0 && param.getName().startsWith("m_")) { + // Ancient version of jME3 ... + param.setName(param.getName().substring(2)); + } + + if (def.getMaterialParam(param.getName()) == null) { + logger.log(Level.WARNING, "The material parameter is not defined: {0}. Ignoring..", + param.getName()); + } else { + checkSetParam(param.getVarType(), param.getName()); + paramValues.put(param.getName(), param); + } + } + + if (applyDefaultValues) { + // compatibility with old versions where default vars were not available + for (MatParam param : def.getMaterialParams()) { + if (param.getValue() != null && paramValues.get(param.getName()) == null) { + setParam(param.getName(), param.getVarType(), param.getValue()); + } + } + } + if (guessRenderStateApply && additionalState != null) { + // Try to guess values of "apply" render state based on defaults + // if value != default then set apply to true + additionalState.applyPolyOffset = additionalState.offsetEnabled; + additionalState.applyBlendMode = additionalState.blendMode != BlendMode.Off; + additionalState.applyColorWrite = !additionalState.colorWrite; + additionalState.applyCullMode = additionalState.cullMode != FaceCullMode.Back; + additionalState.applyDepthTest = !additionalState.depthTest; + additionalState.applyDepthWrite = !additionalState.depthWrite; + additionalState.applyStencilTest = additionalState.stencilTest; + additionalState.applyWireFrame = additionalState.wireframe; + } + if (enableVertexColor) { + setBoolean("VertexColor", true); + } + if (separateTexCoord) { + setBoolean("SeparateTexCoord", true); + } + } +} + diff --git a/jme3-core/src/main/java/com/jme3/material/MatParam.java b/jme3-core/src/main/java/com/jme3/material/MatParam.java index 8e4168133e..cc5fa51566 100644 --- a/jme3-core/src/main/java/com/jme3/material/MatParam.java +++ b/jme3-core/src/main/java/com/jme3/material/MatParam.java @@ -48,8 +48,8 @@ import com.jme3.math.Vector3f; import com.jme3.math.Vector4f; import com.jme3.shader.VarType; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; /** * Describes a material parameter. This is used for both defining a name and type @@ -283,7 +283,7 @@ public String getValueAsString() { case TextureArray: case TextureBuffer: case TextureCubeMap: - Texture texVal = (Texture) value; + GlTexture texVal = (GlTexture) value; TextureKey texKey = (TextureKey) texVal.getKey(); if (texKey == null) { // throw new UnsupportedOperationException("The specified MatParam cannot be represented in J3M"); @@ -299,20 +299,20 @@ public String getValueAsString() { } // Wrap mode - ret += getWrapMode(texVal, Texture.WrapAxis.S); - ret += getWrapMode(texVal, Texture.WrapAxis.T); - ret += getWrapMode(texVal, Texture.WrapAxis.R); + ret += getWrapMode(texVal, GlTexture.WrapAxis.S); + ret += getWrapMode(texVal, GlTexture.WrapAxis.T); + ret += getWrapMode(texVal, GlTexture.WrapAxis.R); // Min and Mag filter - Texture.MinFilter def = Texture.MinFilter.BilinearNoMipMaps; + GlTexture.MinFilter def = GlTexture.MinFilter.BilinearNoMipMaps; if (texVal.getImage().hasMipmaps() || texKey.isGenerateMips()) { - def = Texture.MinFilter.Trilinear; + def = GlTexture.MinFilter.Trilinear; } if (texVal.getMinFilter() != def) { ret += "Min" + texVal.getMinFilter().name() + " "; } - if (texVal.getMagFilter() != Texture.MagFilter.Bilinear) { + if (texVal.getMagFilter() != GlTexture.MagFilter.Bilinear) { ret += "Mag" + texVal.getMagFilter().name() + " "; } @@ -322,7 +322,7 @@ public String getValueAsString() { } } - private String getWrapMode(Texture texVal, Texture.WrapAxis axis) { + private String getWrapMode(GlTexture texVal, GlTexture.WrapAxis axis) { WrapMode mode = WrapMode.EdgeClamp; try { mode = texVal.getWrap(axis); diff --git a/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java b/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java index 58bd44418d..e75137422b 100644 --- a/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java +++ b/jme3-core/src/main/java/com/jme3/material/MatParamTexture.java @@ -36,7 +36,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.shader.VarType; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.image.ColorSpace; import java.io.IOException; @@ -57,7 +57,7 @@ public class MatParamTexture extends MatParam { * @param texture the texture associated with this parameter * @param colorSpace the required color space for the texture */ - public MatParamTexture(VarType type, String name, Texture texture, ColorSpace colorSpace) { + public MatParamTexture(VarType type, String name, GlTexture texture, ColorSpace colorSpace) { super(type, name, texture); this.colorSpace = colorSpace; } @@ -73,17 +73,17 @@ public MatParamTexture() { * * @return the texture object */ - public Texture getTextureValue() { - return (Texture) getValue(); + public GlTexture getTextureValue() { + return (GlTexture) getValue(); } /** * Sets the texture associated with this material parameter. * * @param value the texture object to set - * @throws RuntimeException if the provided value is not a {@link Texture} + * @throws RuntimeException if the provided value is not a {@link GlTexture} */ - public void setTextureValue(Texture value) { + public void setTextureValue(GlTexture value) { setValue(value); } @@ -113,7 +113,7 @@ public void write(JmeExporter ex) throws IOException { oc.write(colorSpace, "colorSpace", null); // For backwards compatibility oc.write(0, "texture_unit", -1); - oc.write((Texture) value, "texture", null); + oc.write((GlTexture) value, "texture", null); } @Override diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index da88ff30e9..56fc484632 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -31,46 +31,14 @@ */ package com.jme3.material; -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetManager; -import com.jme3.asset.CloneableSmartAsset; -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.light.LightList; -import com.jme3.material.RenderState.BlendMode; -import com.jme3.material.RenderState.FaceCullMode; -import com.jme3.material.TechniqueDef.LightMode; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Matrix4f; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; -import com.jme3.math.Vector4f; -import com.jme3.renderer.Caps; +import com.jme3.math.*; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.Renderer; -import com.jme3.renderer.TextureUnitException; -import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.scene.Geometry; -import com.jme3.shader.*; -import com.jme3.shader.bufferobject.BufferObject; -import com.jme3.texture.Image; import com.jme3.texture.Texture; -import com.jme3.texture.TextureImage; -import com.jme3.texture.image.ColorSpace; -import com.jme3.util.ListMap; -import com.jme3.util.SafeArrayList; - -import java.io.IOException; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; +import com.jme3.vulkan.buffers.GpuBuffer; +import com.jme3.vulkan.frames.VersionedResource; /** * Material describes the rendering style for a given @@ -83,1182 +51,58 @@ * * @author Kirill Vainer */ -public class Material implements CloneableSmartAsset, Cloneable, Savable { - - // Version #2: Fixed issue with RenderState.apply*** flags not getting exported - public static final int SAVABLE_VERSION = 2; - private static final Logger logger = Logger.getLogger(Material.class.getName()); - - private AssetKey key; - private String name; - private MaterialDef def; - private ListMap paramValues = new ListMap<>(); - private Technique technique; - private HashMap techniques = new HashMap<>(); - private RenderState additionalState = null; - private final RenderState mergedRenderState = new RenderState(); - private boolean transparent = false; - private boolean receivesShadows = false; - private int sortingId = -1; - - /** - * Manages and tracks texture and buffer binding units for rendering. - * Used internally by the Material class. - */ - public static class BindUnits { - /** The current texture unit counter. */ - public int textureUnit = 0; - /** The current buffer unit counter. */ - public int bufferUnit = 0; - } - private BindUnits bindUnits = new BindUnits(); - - /** - * Constructs a new Material instance based on a provided MaterialDef. - * The material's parameters will be initialized with default values from the definition. - * - * @param def The material definition to use (cannot be null). - * @throws IllegalArgumentException if def is null. - */ - public Material(MaterialDef def) { - if (def == null) { - throw new IllegalArgumentException("Material definition cannot be null"); - } - this.def = def; - - // Load default values from definition (if any) - for (MatParam param : def.getMaterialParams()) { - if (param.getValue() != null) { - setParam(param.getName(), param.getVarType(), param.getValue()); - } - } - } - - /** - * Constructs a new Material by loading its MaterialDef from the asset manager. - * - * @param assetManager The asset manager to load the MaterialDef from. - * @param defName The asset path of the .j3md file. - */ - public Material(AssetManager assetManager, String defName) { - this(assetManager.loadAsset(new AssetKey(defName))); - } - - /** - * For serialization only. Do not use. - */ - public Material() { - } - - /** - * Returns the asset key name of the asset from which this material was loaded. - *

This value will be null unless this material was loaded from a .j3m file.

- * - * @return Asset key name of the .j3m file, or null if not loaded from a file. - */ - public String getAssetName() { - return key != null ? key.getName() : null; - } - - /** - * Returns the user-defined name of the material. - * This name is distinct from the asset name and may be null or not unique. - * - * @return The name of the material, or null. - */ - public String getName() { - return name; - } - - /** - * Sets the user-defined name of the material. - * The name is not the same as the asset name. - * It can be null, and there is no guarantee of its uniqueness. - * - * @param name The name of the material. - */ - public void setName(String name) { - this.name = name; - } +public interface Material extends Savable { - @Override - public void setKey(AssetKey key) { - this.key = key; - } - - @Override - public AssetKey getKey() { - return key; - } - - /** - * Returns the sorting ID or sorting index for this material. - * - *

The sorting ID is used internally by the system to sort rendering - * of geometries. It sorted to reduce shader switches, if the shaders - * are equal, then it is sorted by textures. - * - * @return The sorting ID used for sorting geometries for rendering. - */ - public int getSortId() { - if (sortingId == -1 && technique != null) { - sortingId = technique.getSortId() << 16; - int texturesSortId = 17; - for (int i = 0; i < paramValues.size(); i++) { - MatParam param = paramValues.getValue(i); - if (!param.getVarType().isTextureType()) { - continue; - } - Texture texture = (Texture) param.getValue(); - if (texture == null) { - continue; - } - Image image = texture.getImage(); - if (image == null) { - continue; - } - int textureId = image.getId(); - if (textureId == -1) { - textureId = 0; - } - texturesSortId = texturesSortId * 23 + textureId; - } - sortingId |= texturesSortId & 0xFFFF; - } - return sortingId; - } - - /** - * Clones this material. The result is returned. - */ - @Override - public Material clone() { - try { - Material mat = (Material) super.clone(); - - if (additionalState != null) { - mat.additionalState = additionalState.clone(); - } - mat.technique = null; - mat.techniques = new HashMap(); - - mat.paramValues = new ListMap(); - for (int i = 0; i < paramValues.size(); i++) { - Map.Entry entry = paramValues.getEntry(i); - mat.paramValues.put(entry.getKey(), entry.getValue().clone()); - } - - mat.sortingId = -1; - - return mat; - } catch (CloneNotSupportedException ex) { - throw new AssertionError(ex); - } - } - - /** - * Compares two materials for content equality. - * This methods compare definition, parameters, additional render states. - * Since materials are mutable objects, implementing equals() properly is not possible, - * hence the name contentEquals(). - * - * @param otherObj the material to compare to this material - * @return true if the materials are equal. - */ - public boolean contentEquals(Object otherObj) { - if (!(otherObj instanceof Material)) { - return false; - } - - Material other = (Material) otherObj; - - // Early exit if the material are the same object - if (this == other) { - return true; - } - - // Check material definition - if (this.getMaterialDef() != other.getMaterialDef()) { - return false; - } + String DEFAULT_UNIFORM_BUFFER = "DefaultUniformBuffer"; - // Early exit if the size of the params is different - if (this.paramValues.size() != other.paramValues.size()) { - return false; - } + void render(Geometry geometry, LightList lights, RenderManager renderManager); - // Checking technique - if (this.technique != null || other.technique != null) { - // Techniques are considered equal if their names are the same - // E.g. if user chose custom technique for one material but - // uses default technique for other material, the materials - // are not equal. - String thisDefName = this.technique != null - ? this.technique.getDef().getName() - : TechniqueDef.DEFAULT_TECHNIQUE_NAME; + void setUniform(String name, VersionedResource buffer); - String otherDefName = other.technique != null - ? other.technique.getDef().getName() - : TechniqueDef.DEFAULT_TECHNIQUE_NAME; + void setTexture(String name, VersionedResource texture); - if (!thisDefName.equals(otherDefName)) { - return false; - } - } + void setParam(String uniform, String param, Object value); - // Comparing parameters - for (String paramKey : paramValues.keySet()) { - MatParam thisParam = this.getParam(paramKey); - MatParam otherParam = other.getParam(paramKey); + /* ----- COMPATABILITY WITH OLD MATERIAL ----- */ - // This param does not exist in compared mat - if (otherParam == null) { - return false; - } - - if (!otherParam.equals(thisParam)) { - return false; - } - } - - // Comparing additional render states - if (additionalState == null) { - if (other.additionalState != null) { - return false; - } - } else { - if (!additionalState.equals(other.additionalState)) { - return false; - } - } - - return true; + default void setParam(String param, Object value) { + setParam(DEFAULT_UNIFORM_BUFFER, param, value); } - /** - * Works like {@link Object#hashCode() } except it may change together with the material as the material is mutable by definition. - * - * @return value for use in hashing - */ - public int contentHashCode() { - int hash = 7; - hash = 29 * hash + (this.def != null ? this.def.hashCode() : 0); - hash = 29 * hash + (this.paramValues != null ? this.paramValues.hashCode() : 0); - hash = 29 * hash + (this.technique != null ? this.technique.getDef().getName().hashCode() : 0); - hash = 29 * hash + (this.additionalState != null ? this.additionalState.contentHashCode() : 0); - return hash; + default void setBoolean(String param, boolean value) { + setParam(param, value); } - /** - * Returns the currently active technique. - *

- * The technique is selected automatically by the {@link RenderManager} - * based on system capabilities. Users may select their own - * technique by using - * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) }. - * - * @return the currently active technique. - * - * @see #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) - */ - public Technique getActiveTechnique() { - return technique; + default void setInt(String param, int value) { + setParam(param, value); } - /** - * Check if the transparent value marker is set on this material. - * @return True if the transparent value marker is set on this material. - * @see #setTransparent(boolean) - */ - public boolean isTransparent() { - return transparent; + default void setFloat(String param, float value) { + setParam(param, value); } - /** - * Set the transparent value marker. - * - *

This value is merely a marker, by itself it does nothing. - * Generally model loaders will use this marker to indicate further - * up that the material is transparent and therefore any geometries - * using it should be put into the {@link Bucket#Transparent transparent - * bucket}. - * - * @param transparent the transparent value marker. - */ - public void setTransparent(boolean transparent) { - this.transparent = transparent; + default void setFloat(String param, Float value) { + setParam(param, value); } - /** - * Check if the material should receive shadows or not. - * - * @return True if the material should receive shadows. - * - * @see Material#setReceivesShadows(boolean) - */ - public boolean isReceivesShadows() { - return receivesShadows; + default void setColor(String param, ColorRGBA value) { + setParam(param, value); } - /** - * Set if the material should receive shadows or not. - * - *

This value is merely a marker, by itself it does nothing. - * Generally model loaders will use this marker to indicate - * the material should receive shadows and therefore any - * geometries using it should have {@link com.jme3.renderer.queue.RenderQueue.ShadowMode#Receive} set - * on them. - * - * @param receivesShadows if the material should receive shadows or not. - */ - public void setReceivesShadows(boolean receivesShadows) { - this.receivesShadows = receivesShadows; + default void setVector2(String param, Vector2f value) { + setParam(param, value); } - /** - * Acquire the additional {@link RenderState render state} to apply - * for this material. - * - *

The first call to this method will create an additional render - * state which can be modified by the user to apply any render - * states in addition to the ones used by the renderer. Only render - * states which are modified in the additional render state will be applied. - * - * @return The additional render state. - */ - public RenderState getAdditionalRenderState() { - if (additionalState == null) { - additionalState = RenderState.ADDITIONAL.clone(); - } - return additionalState; + default void setVector3(String param, Vector3f value) { + setParam(param, value); } - /** - * Get the material definition (.j3md file info) that this - * material is implementing. - * - * @return the material definition this material implements. - */ - public MaterialDef getMaterialDef() { - return def; + default void setVector4(String param, Vector4f value) { + setParam(param, value); } - /** - * Returns the parameter set on this material with the given name, - * returns null if the parameter is not set. - * - * @param name The parameter name to look up. - * @return The MatParam if set, or null if not set. - */ - public MatParam getParam(String name) { - return paramValues.get(name); + default void setMatrix4(String param, Matrix4f value) { + setParam(param, value); } - /** - * Returns the current parameter's value. - * - * @param the expected type of the parameter value - * @param name the parameter name to look up. - * @return current value or null if the parameter wasn't set. - */ - @SuppressWarnings("unchecked") - public T getParamValue(final String name) { - final MatParam param = paramValues.get(name); - return param == null ? null : (T) param.getValue(); - } - - /** - * Returns the texture parameter set on this material with the given name, - * returns null if the parameter is not set. - * - * @param name The parameter name to look up. - * @return The MatParamTexture if set, or null if not set. - */ - public MatParamTexture getTextureParam(String name) { - MatParam param = paramValues.get(name); - if (param instanceof MatParamTexture) { - return (MatParamTexture) param; - } - return null; - } - - /** - * Returns a collection of all parameters set on this material. - * - * @return a collection of all parameters set on this material. - * - * @see #setParam(java.lang.String, com.jme3.shader.VarType, java.lang.Object) - */ - public Collection getParams() { - return paramValues.values(); - } - - /** - * Returns the ListMap of all parameters set on this material. - * - * @return a ListMap of all parameters set on this material. - * - * @see #setParam(java.lang.String, com.jme3.shader.VarType, java.lang.Object) - */ - public ListMap getParamsMap() { - return paramValues; - } - - /** - * Check if setting the parameter given the type and name is allowed. - * @param type The type that the "set" function is designed to set - * @param name The name of the parameter - */ - private void checkSetParam(VarType type, String name) { - MatParam paramDef = def.getMaterialParam(name); - if (paramDef == null) { - throw new IllegalArgumentException("Material parameter is not defined: " + name); - } - if (type != null && paramDef.getVarType() != type) { - logger.log(Level.WARNING, "Material parameter being set: {0} with " - + "type {1} doesn''t match definition types {2}", new Object[]{name, type.name(), paramDef.getVarType()}); - } - } - - /** - * Pass a parameter to the material shader. - * - * @param name the name of the parameter defined in the material definition (.j3md) - * @param type the type of the parameter {@link VarType} - * @param value the value of the parameter - */ - public void setParam(String name, VarType type, Object value) { - checkSetParam(type, name); - - if (type.isTextureType()) { - setTextureParam(name, type, (Texture)value); - } else { - MatParam val = getParam(name); - if (val == null) { - paramValues.put(name, new MatParam(type, name, value)); - } else { - val.setValue(value); - } - - if (technique != null) { - technique.notifyParamChanged(name, type, value); - } - if (type.isImageType()) { - // recompute sort id - sortingId = -1; - } - } - } - - /** - * Pass a parameter to the material shader. - * - * @param name the name of the parameter defined in the material definition (j3md) - * @param value the value of the parameter - */ - public void setParam(String name, Object value) { - MatParam p = getMaterialDef().getMaterialParam(name); - setParam(name, p.getVarType(), value); - } - - /** - * Clear a parameter from this material. The parameter must exist - * @param name the name of the parameter to clear - */ - public void clearParam(String name) { - checkSetParam(null, name); - MatParam matParam = getParam(name); - if (matParam == null) { - return; - } - - paramValues.remove(name); - if (matParam instanceof MatParamTexture) { - sortingId = -1; - } - if (technique != null) { - technique.notifyParamChanged(name, null, null); - } - } - - /** - * Set a texture parameter. - * - * @param name The name of the parameter - * @param type The variable type {@link VarType} - * @param value The texture value of the parameter. - * - * @throws IllegalArgumentException is value is null - */ - public void setTextureParam(String name, VarType type, Texture value) { - if (value == null) { - throw new IllegalArgumentException(); - } - - checkSetParam(type, name); - MatParamTexture param = getTextureParam(name); - - checkTextureParamColorSpace(name, value); - ColorSpace colorSpace = value.getImage() != null ? value.getImage().getColorSpace() : null; - - if (param == null) { - param = new MatParamTexture(type, name, value, colorSpace); - paramValues.put(name, param); - } else { - param.setTextureValue(value); - param.setColorSpace(colorSpace); - } - - if (technique != null) { - technique.notifyParamChanged(name, type, value); - } - - // need to recompute sort ID - sortingId = -1; - } - - private void checkTextureParamColorSpace(String name, Texture value) { - MatParamTexture paramDef = (MatParamTexture) def.getMaterialParam(name); - if (paramDef.getColorSpace() != null && paramDef.getColorSpace() != value.getImage().getColorSpace()) { - value.getImage().setColorSpace(paramDef.getColorSpace()); - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Material parameter {0} needs a {1} texture, " - + "texture {2} was switched to {3} color space.", - new Object[]{name, paramDef.getColorSpace().toString(), - value.getName(), - value.getImage().getColorSpace().name()}); - } - } else if (paramDef.getColorSpace() == null && value.getName() != null && value.getImage().getColorSpace() == ColorSpace.Linear) { - logger.log(Level.WARNING, - "The texture {0} has linear color space, but the material " - + "parameter {2} specifies no color space requirement, this may " - + "lead to unexpected behavior.\nCheck if the image " - + "was not set to another material parameter with a linear " - + "color space, or that you did not set the ColorSpace to " - + "Linear using texture.getImage.setColorSpace().", - new Object[]{value.getName(), value.getImage().getColorSpace().name(), name}); - } - } - - /** - * Pass a texture to the material shader. - * - * @param name the name of the texture defined in the material definition - * (.j3md) (e.g. Texture for Lighting.j3md) - * @param value the Texture object previously loaded by the asset manager - */ - public void setTexture(String name, Texture value) { - if (value == null) { - // clear it - clearParam(name); - return; - } - - VarType paramType = null; - switch (value.getType()) { - case TwoDimensional: - paramType = VarType.Texture2D; - break; - case TwoDimensionalArray: - paramType = VarType.TextureArray; - break; - case ThreeDimensional: - paramType = VarType.Texture3D; - break; - case CubeMap: - paramType = VarType.TextureCubeMap; - break; - default: - throw new UnsupportedOperationException("Unknown texture type: " + value.getType()); - } - - setTextureParam(name, paramType, value); - } - - /** - * Pass a Matrix4f to the material shader. - * - * @param name the name of the matrix defined in the material definition (j3md) - * @param value the Matrix4f object - */ - public void setMatrix4(String name, Matrix4f value) { - setParam(name, VarType.Matrix4, value); - } - - /** - * Pass a boolean to the material shader. - * - * @param name the name of the boolean defined in the material definition (j3md) - * @param value the boolean value - */ - public void setBoolean(String name, boolean value) { - setParam(name, VarType.Boolean, value); - } - - /** - * Pass a float to the material shader. - * - * @param name the name of the float defined in the material definition (j3md) - * @param value the float value - */ - public void setFloat(String name, float value) { - setParam(name, VarType.Float, value); - } - - /** - * Pass a float to the material shader. This version avoids auto-boxing - * if the value is already a Float. - * - * @param name the name of the float defined in the material definition (j3md) - * @param value the float value - */ - public void setFloat(String name, Float value) { - setParam(name, VarType.Float, value); - } - - /** - * Pass an int to the material shader. - * - * @param name the name of the int defined in the material definition (j3md) - * @param value the int value - */ - public void setInt(String name, int value) { - setParam(name, VarType.Int, value); - } - - /** - * Pass a Color to the material shader. - * - * @param name the name of the color defined in the material definition (j3md) - * @param value the ColorRGBA value - */ - public void setColor(String name, ColorRGBA value) { - setParam(name, VarType.Vector4, value); - } - - /** - * Pass a uniform buffer object to the material shader. - * - * @param name the name of the buffer object defined in the material definition (j3md). - * @param value the buffer object. - */ - public void setUniformBufferObject(final String name, final BufferObject value) { - setParam(name, VarType.UniformBufferObject, value); - } - - /** - * Pass a shader storage buffer object to the material shader. - * - * @param name the name of the buffer object defined in the material definition (j3md). - * @param value the buffer object. - */ - public void setShaderStorageBufferObject(final String name, final BufferObject value) { - setParam(name, VarType.ShaderStorageBufferObject, value); - } - - /** - * Pass a Vector2f to the material shader. - * - * @param name the name of the Vector2f defined in the material definition (j3md) - * @param value the Vector2f value - */ - public void setVector2(String name, Vector2f value) { - setParam(name, VarType.Vector2, value); - } - - /** - * Pass a Vector3f to the material shader. - * - * @param name the name of the Vector3f defined in the material definition (j3md) - * @param value the Vector3f value - */ - public void setVector3(String name, Vector3f value) { - setParam(name, VarType.Vector3, value); - } - - /** - * Pass a Vector4f to the material shader. - * - * @param name the name of the Vector4f defined in the material definition (j3md) - * @param value the Vector4f value - */ - public void setVector4(String name, Vector4f value) { - setParam(name, VarType.Vector4, value); - } - - /** - * Select the technique to use for rendering this material. - *

- * Any candidate technique for selection (either default or named) - * must be verified to be compatible with the system, for that, the - * renderManager is queried for capabilities. - * - * @param name The name of the technique to select, pass - * {@link TechniqueDef#DEFAULT_TECHNIQUE_NAME} to select one of the default - * techniques. - * @param renderManager The {@link RenderManager render manager} - * to query for capabilities. - * - * @throws IllegalArgumentException If no technique exists with the given - * name. - * @throws UnsupportedOperationException If no candidate technique supports - * the system capabilities. - */ - public void selectTechnique(String name, final RenderManager renderManager) { - // check if already created - Technique tech = techniques.get(name); - // When choosing technique, we choose one that - // supports all the caps. - if (tech == null) { - EnumSet rendererCaps = renderManager.getRenderer().getCaps(); - List techDefs = def.getTechniqueDefs(name); - if (techDefs == null || techDefs.isEmpty()) { - throw new IllegalArgumentException( - String.format("The requested technique %s is not available on material %s", name, def.getName())); - } - - TechniqueDef lastTech = null; - float weight = 0; - for (TechniqueDef techDef : techDefs) { - if (rendererCaps.containsAll(techDef.getRequiredCaps())) { - float techWeight = techDef.getWeight() + (techDef.getLightMode() == renderManager.getPreferredLightMode() ? 10f : 0); - if (techWeight > weight) { - tech = new Technique(this, techDef); - techniques.put(name, tech); - weight = techWeight; - } - } - lastTech = techDef; - } - if (tech == null) { - throw new UnsupportedOperationException( - String.format("No technique '%s' on material " - + "'%s' is supported by the video hardware. " - + "The capabilities %s are required.", - name, def.getName(), lastTech.getRequiredCaps())); - } - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, this.getMaterialDef().getName() + " selected technique def " + tech.getDef()); - } - } else if (technique == tech) { - // attempting to switch to an already - // active technique. - return; - } - - technique = tech; - tech.notifyTechniqueSwitched(); - - // shader was changed - sortingId = -1; - } - - private void applyOverrides(Renderer renderer, Shader shader, SafeArrayList overrides, BindUnits bindUnits) { - for (MatParamOverride override : overrides.getArray()) { - VarType type = override.getVarType(); - - MatParam paramDef = def.getMaterialParam(override.getName()); - - if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) { - continue; - } - - Uniform uniform = shader.getUniform(override.getPrefixedName()); - - if (override.getValue() != null) { - updateShaderMaterialParameter(renderer, type, shader, override, bindUnits, true); - } else { - uniform.clearValue(); - } - } - } - - private void updateShaderMaterialParameter(Renderer renderer, VarType type, Shader shader, MatParam param, BindUnits unit, boolean override) { - if (type == VarType.UniformBufferObject || type == VarType.ShaderStorageBufferObject) { - ShaderBufferBlock bufferBlock = shader.getBufferBlock(param.getPrefixedName()); - BufferObject bufferObject = (BufferObject) param.getValue(); - - ShaderBufferBlock.BufferType btype; - if (type == VarType.ShaderStorageBufferObject) { - btype = ShaderBufferBlock.BufferType.ShaderStorageBufferObject; - bufferBlock.setBufferObject(btype, bufferObject); - renderer.setShaderStorageBufferObject(unit.bufferUnit, bufferObject); // TODO: probably not needed - } else { - btype = ShaderBufferBlock.BufferType.UniformBufferObject; - bufferBlock.setBufferObject(btype, bufferObject); - renderer.setUniformBufferObject(unit.bufferUnit, bufferObject); // TODO: probably not needed - } - unit.bufferUnit++; - } else { - Uniform uniform = shader.getUniform(param.getPrefixedName()); - if (!override && uniform.isSetByCurrentMaterial()) - return; - - if (type.isTextureType() || type.isImageType()) { - try { - if (type.isTextureType()) { - renderer.setTexture(unit.textureUnit, (Texture) param.getValue()); - } else { - renderer.setTextureImage(unit.textureUnit, (TextureImage) param.getValue()); - } - } catch (TextureUnitException ex) { - int numTexParams = unit.textureUnit + 1; - String message = "Too many texture parameters (" + numTexParams + ") assigned\n to " + this.toString(); - throw new IllegalStateException(message); - } - uniform.setValue(VarType.Int, unit.textureUnit); - unit.textureUnit++; - } else { - uniform.setValue(type, param.getValue()); - } - } - } - - private BindUnits updateShaderMaterialParameters(Renderer renderer, Shader shader, - SafeArrayList worldOverrides, SafeArrayList forcedOverrides) { - - bindUnits.textureUnit = 0; - bindUnits.bufferUnit = 0; - - if (worldOverrides != null) { - applyOverrides(renderer, shader, worldOverrides, bindUnits); - } - if (forcedOverrides != null) { - applyOverrides(renderer, shader, forcedOverrides, bindUnits); - } - - for (int i = 0; i < paramValues.size(); i++) { - MatParam param = paramValues.getValue(i); - VarType type = param.getVarType(); - updateShaderMaterialParameter(renderer, type, shader, param, bindUnits, false); - } - - // TODO: HACKY HACK remove this when texture unit is handled by the uniform. - return bindUnits; - } - - private void updateRenderState(Geometry geometry, RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) { - RenderState finalRenderState; - if (renderManager.getForcedRenderState() != null) { - finalRenderState = mergedRenderState.copyFrom(renderManager.getForcedRenderState()); - } else if (techniqueDef.getRenderState() != null) { - finalRenderState = mergedRenderState.copyFrom(RenderState.DEFAULT); - finalRenderState = techniqueDef.getRenderState().copyMergedTo(additionalState, finalRenderState); - } else { - finalRenderState = mergedRenderState.copyFrom(RenderState.DEFAULT); - finalRenderState = RenderState.DEFAULT.copyMergedTo(additionalState, finalRenderState); - } - // test if the face cull mode should be flipped before render - if (finalRenderState.isFaceCullFlippable() && isNormalsBackward(geometry.getWorldScale())) { - finalRenderState.flipFaceCull(); - } - renderer.applyRenderState(finalRenderState); - } - - /** - * Returns true if the geometry world scale indicates that normals will be backward. - * - * @param scalar The geometry's world scale vector. - * @return true if the normals are effectively backward; false otherwise. - */ - private boolean isNormalsBackward(Vector3f scalar) { - // count number of negative scalar vector components - int n = 0; - if (scalar.x < 0) n++; - if (scalar.y < 0) n++; - if (scalar.z < 0) n++; - // An odd number of negative components means the normal vectors - // are backward to what they should be. - return n == 1 || n == 3; - } - - /** - * Preloads this material for the given render manager. - *

- * Preloading the material can ensure that when the material is first - * used for rendering, there won't be any delay since the material has - * been already been setup for rendering. - * - * @param renderManager The render manager to preload for - * @param geometry to determine the applicable parameter overrides, if any - */ - public void preload(RenderManager renderManager, Geometry geometry) { - if (technique == null) { - selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); - } - TechniqueDef techniqueDef = technique.getDef(); - Renderer renderer = renderManager.getRenderer(); - EnumSet rendererCaps = renderer.getCaps(); - - if (techniqueDef.isNoRender()) { - return; - } - // Get world overrides - SafeArrayList overrides = geometry.getWorldMatParamOverrides(); - - Shader shader = technique.makeCurrent(renderManager, overrides, null, null, rendererCaps); - updateShaderMaterialParameters(renderer, shader, overrides, null); - renderManager.getRenderer().setShader(shader); - } - - private void clearUniformsSetByCurrent(Shader shader) { - ListMap uniforms = shader.getUniformMap(); - int size = uniforms.size(); - for (int i = 0; i < size; i++) { - Uniform u = uniforms.getValue(i); - u.clearSetByCurrentMaterial(); - } - } - - private void resetUniformsNotSetByCurrent(Shader shader) { - ListMap uniforms = shader.getUniformMap(); - int size = uniforms.size(); - for (int i = 0; i < size; i++) { - Uniform u = uniforms.getValue(i); - if (!u.isSetByCurrentMaterial()) { - if (u.getName().charAt(0) != 'g') { - // Don't reset world globals! - // The benefits gained from this are very minimal - // and cause lots of matrix -> FloatBuffer conversions. - u.clearValue(); - } - } - } - } - - /** - * Called by {@link RenderManager} to render the geometry by - * using this material. - *

- * The material is rendered as follows: - *

    - *
  • Determine which technique to use to render the material - - * either what the user selected via - * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) - * Material.selectTechnique()}, - * or the first default technique that the renderer supports - * (based on the technique's {@link TechniqueDef#getRequiredCaps() requested rendering capabilities})
      - *
    • If the technique has been changed since the last frame, then it is notified via - * {@link Technique#makeCurrent(com.jme3.renderer.RenderManager, com.jme3.util.SafeArrayList, com.jme3.util.SafeArrayList, com.jme3.light.LightList, java.util.EnumSet) - * Technique.makeCurrent()}. - * If the technique wants to use a shader to render the model, it should load it at this part - - * the shader should have all the proper defines as declared in the technique definition, - * including those that are bound to material parameters. - * The technique can re-use the shader from the last frame if - * no changes to the defines occurred.
    - *
  • Set the {@link RenderState} to use for rendering. The render states are - * applied in this order (later RenderStates override earlier RenderStates):
      - *
    1. {@link TechniqueDef#getRenderState() Technique Definition's RenderState} - * - i.e. specific RenderState that is required for the shader.
    2. - *
    3. {@link #getAdditionalRenderState() Material Instance Additional RenderState} - * - i.e. ad-hoc RenderState set per model
    4. - *
    5. {@link RenderManager#getForcedRenderState() RenderManager's Forced RenderState} - * - i.e. RenderState requested by a {@link com.jme3.post.SceneProcessor} or - * post-processing filter.
    - *
  • If the technique uses a shader, then the uniforms of the shader must be updated.
      - *
    • Uniforms bound to material parameters are updated based on the current material parameter values.
    • - *
    • Uniforms bound to world parameters are updated from the RenderManager. - * Internally {@link UniformBindingManager} is used for this task.
    • - *
    • Uniforms bound to textures will cause the texture to be uploaded as necessary. - * The uniform is set to the texture unit where the texture is bound.
    - *
  • If the technique uses a shader, the model is then rendered according - * to the lighting mode specified on the technique definition.
      - *
    • {@link LightMode#SinglePass single pass light mode} fills the shader's light uniform arrays - * with the first 4 lights and renders the model once.
    • - *
    • {@link LightMode#MultiPass multi pass light mode} light mode renders the model multiple times, - * for the first light it is rendered opaque, on subsequent lights it is - * rendered with {@link BlendMode#AlphaAdditive alpha-additive} blending and depth writing disabled.
    • - *
    - *
  • For techniques that do not use shaders, - * fixed function OpenGL is used to render the model (see {@link com.jme3.renderer.opengl.GLRenderer} interface):
      - *
    • OpenGL state that is bound to material parameters is updated.
    • - *
    • The texture set on the material is uploaded and bound. - * Currently only 1 texture is supported for fixed function techniques.
    • - *
    • If the technique uses lighting, then OpenGL lighting state is updated - * based on the light list on the geometry, otherwise OpenGL lighting is disabled.
    • - *
    • The mesh is uploaded and rendered.
    • - *
    - *
- * - * @param geometry The geometry to render - * @param lights Presorted and filtered light list to use for rendering - * @param renderManager The render manager requesting the rendering - */ - public void render(Geometry geometry, LightList lights, RenderManager renderManager) { - if (technique == null) { - selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); - } - - TechniqueDef techniqueDef = technique.getDef(); - Renderer renderer = renderManager.getRenderer(); - EnumSet rendererCaps = renderer.getCaps(); - - if (techniqueDef.isNoRender()) { - return; - } - - // Apply render state - updateRenderState(geometry, renderManager, renderer, techniqueDef); - - // Get world overrides - SafeArrayList overrides = geometry.getWorldMatParamOverrides(); - - // Select shader to use - Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps); - - // Begin tracking which uniforms were changed by material. - clearUniformsSetByCurrent(shader); - - // Set uniform bindings - renderManager.updateUniformBindings(shader); - - // Set material parameters - BindUnits units = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams()); - - // Clear any uniforms not changed by material. - resetUniformsNotSetByCurrent(shader); - - // Delegate rendering to the technique - technique.render(renderManager, shader, geometry, lights, units); - } - - /** - * Called by {@link RenderManager} to render the geometry by - * using this material. - * - * Note that this version of the render method - * does not perform light filtering. - * - * @param geom The geometry to render - * @param rm The render manager requesting the rendering - */ - public void render(Geometry geom, RenderManager rm) { - render(geom, geom.getWorldLightList(), rm); - } - - @Override - public String toString() { - return "Material[name=" + name + - ", def=" + (def != null ? def.getName() : null) + - ", tech=" + (technique != null && technique.getDef() != null ? technique.getDef().getName() : null) + - "]"; - } - - @Override - public void write(JmeExporter ex) throws IOException { - OutputCapsule oc = ex.getCapsule(this); - oc.write(def.getAssetName(), "material_def", null); - oc.write(additionalState, "render_state", null); - oc.write(transparent, "is_transparent", false); - oc.write(name, "name", null); - oc.writeStringSavableMap(paramValues, "parameters", null); - } - - @Override - @SuppressWarnings("unchecked") - public void read(JmeImporter im) throws IOException { - InputCapsule ic = im.getCapsule(this); - - name = ic.readString("name", null); - additionalState = (RenderState) ic.readSavable("render_state", null); - transparent = ic.readBoolean("is_transparent", false); - - // Load the material def - String defName = ic.readString("material_def", null); - HashMap params = (HashMap) ic.readStringSavableMap("parameters", null); - - boolean enableVertexColor = false; - boolean separateTexCoord = false; - boolean applyDefaultValues = false; - boolean guessRenderStateApply = false; - - int ver = ic.getSavableVersion(Material.class); - if (ver < 1) { - applyDefaultValues = true; - } - if (ver < 2) { - guessRenderStateApply = true; - } - if (im.getFormatVersion() == 0) { - // Enable compatibility with old models - if (defName.equalsIgnoreCase("Common/MatDefs/Misc/VertexColor.j3md")) { - // Using VertexColor, switch to Unshaded and set VertexColor=true - enableVertexColor = true; - defName = "Common/MatDefs/Misc/Unshaded.j3md"; - } else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/SimpleTextured.j3md") - || defName.equalsIgnoreCase("Common/MatDefs/Misc/SolidColor.j3md")) { - // Using SimpleTextured/SolidColor, just switch to Unshaded - defName = "Common/MatDefs/Misc/Unshaded.j3md"; - } else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/WireColor.j3md")) { - // Using WireColor, set wireframe render state = true and use Unshaded - getAdditionalRenderState().setWireframe(true); - defName = "Common/MatDefs/Misc/Unshaded.j3md"; - } else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/Unshaded.j3md")) { - // Uses unshaded, ensure that the proper param is set - MatParam value = params.get("SeperateTexCoord"); - if (value != null && ((Boolean) value.getValue()) == true) { - params.remove("SeperateTexCoord"); - separateTexCoord = true; - } - } - assert applyDefaultValues && guessRenderStateApply; - } - - def = im.getAssetManager().loadAsset(new AssetKey(defName)); - paramValues = new ListMap(); - - // load the textures and update nextTexUnit - for (Map.Entry entry : params.entrySet()) { - MatParam param = entry.getValue(); - if (param instanceof MatParamTexture) { - MatParamTexture texVal = (MatParamTexture) param; - // the texture failed to load for this param - // do not add to param values - if (texVal.getTextureValue() == null || texVal.getTextureValue().getImage() == null) { - continue; - } - checkTextureParamColorSpace(texVal.getName(), texVal.getTextureValue()); - } - - if (im.getFormatVersion() == 0 && param.getName().startsWith("m_")) { - // Ancient version of jME3 ... - param.setName(param.getName().substring(2)); - } - - if (def.getMaterialParam(param.getName()) == null) { - logger.log(Level.WARNING, "The material parameter is not defined: {0}. Ignoring..", - param.getName()); - } else { - checkSetParam(param.getVarType(), param.getName()); - paramValues.put(param.getName(), param); - } - } - - if (applyDefaultValues) { - // compatibility with old versions where default vars were not available - for (MatParam param : def.getMaterialParams()) { - if (param.getValue() != null && paramValues.get(param.getName()) == null) { - setParam(param.getName(), param.getVarType(), param.getValue()); - } - } - } - if (guessRenderStateApply && additionalState != null) { - // Try to guess values of "apply" render state based on defaults - // if value != default then set apply to true - additionalState.applyPolyOffset = additionalState.offsetEnabled; - additionalState.applyBlendMode = additionalState.blendMode != BlendMode.Off; - additionalState.applyColorWrite = !additionalState.colorWrite; - additionalState.applyCullMode = additionalState.cullMode != FaceCullMode.Back; - additionalState.applyDepthTest = !additionalState.depthTest; - additionalState.applyDepthWrite = !additionalState.depthWrite; - additionalState.applyStencilTest = additionalState.stencilTest; - additionalState.applyWireFrame = additionalState.wireframe; - } - if (enableVertexColor) { - setBoolean("VertexColor", true); - } - if (separateTexCoord) { - setBoolean("SeparateTexCoord", true); - } - } } diff --git a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java index 9cbd482e00..deccf713ca 100644 --- a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java +++ b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java @@ -38,7 +38,7 @@ import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * Describes a J3MD (Material definition). @@ -133,7 +133,7 @@ public void addMaterialParam(VarType type, String name, Object value) { * @param value Default value of the parameter * @see ColorSpace */ - public void addMaterialParamTexture(VarType type, String name, ColorSpace colorSpace,Texture value) { + public void addMaterialParamTexture(VarType type, String name, ColorSpace colorSpace, GlTexture value) { matParams.put(name, new MatParamTexture(type, name, value, colorSpace)); } diff --git a/jme3-core/src/main/java/com/jme3/material/RenderState.java b/jme3-core/src/main/java/com/jme3/material/RenderState.java index 7f21e8abfa..be79559957 100644 --- a/jme3-core/src/main/java/com/jme3/material/RenderState.java +++ b/jme3-core/src/main/java/com/jme3/material/RenderState.java @@ -982,7 +982,7 @@ public void setDepthFunc(TestFunction depthFunc) { /** * Sets the mesh line width. * Use this in conjunction with {@link #setWireframe(boolean)} or with a mesh in - * {@link com.jme3.scene.Mesh.Mode#Lines} mode. + * {@link Mesh.Mode#Lines} mode. * Note: this does not work in OpenGL core profile. It only works in * compatibility profile. * diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java index 5091028a85..3575bfc29d 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -33,7 +33,7 @@ import com.jme3.asset.AssetManager; import com.jme3.light.LightList; -import com.jme3.material.Material.BindUnits; +import com.jme3.material.GlMaterial.BindUnits; import com.jme3.material.TechniqueDef.LightMode; import com.jme3.material.logic.TechniqueDefLogic; import com.jme3.renderer.Caps; @@ -52,7 +52,7 @@ public final class Technique { private final TechniqueDef def; - private final Material owner; + private final GlMaterial owner; private final DefineList paramDefines; private final DefineList dynamicDefines; @@ -63,7 +63,7 @@ public final class Technique { * @param owner The material that will own this technique * @param def The technique definition being implemented. */ - public Technique(Material owner, TechniqueDef def) { + public Technique(GlMaterial owner, TechniqueDef def) { this.owner = owner; this.def = def; this.paramDefines = def.createDefineList(); @@ -161,7 +161,7 @@ Shader makeCurrent(RenderManager renderManager, SafeArrayList * {@link #makeCurrent(RenderManager, SafeArrayList, SafeArrayList, LightList, EnumSet)}. * @param geometry The geometry to render * @param lights Lights which influence the geometry. - * @param lastTexUnit the index of the most recently used texture unit + * @param lastBindUnits the index of the most recently used texture unit */ void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { TechniqueDefLogic logic = def.getLogic(); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java index ca8f7d1efa..d3818215a0 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java @@ -33,15 +33,13 @@ import com.jme3.asset.AssetManager; import com.jme3.light.*; +import com.jme3.material.GlMaterial; import com.jme3.material.TechniqueDef; -import com.jme3.material.Material.BindUnits; import com.jme3.math.ColorRGBA; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; -import com.jme3.scene.instancing.InstancedGeometry; import com.jme3.shader.DefineList; import com.jme3.shader.Shader; import java.util.EnumSet; @@ -61,17 +59,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager } public static void renderMeshFromGeometry(Renderer renderer, Geometry geom) { - Mesh mesh = geom.getMesh(); - int lodLevel = geom.getLodLevel(); - if (geom instanceof InstancedGeometry) { - InstancedGeometry instGeom = (InstancedGeometry) geom; - int numVisibleInstances = instGeom.getNumVisibleInstances(); - if (numVisibleInstances > 0) { - renderer.renderMesh(mesh, lodLevel, numVisibleInstances, instGeom.getAllInstanceData()); - } - } else { - renderer.renderMesh(mesh, lodLevel, 1, null); - } + geom.draw(renderer); } protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLights, ColorRGBA ambientLightColor) { @@ -92,7 +80,7 @@ protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLi @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, GlMaterial.BindUnits lastBindUnits) { Renderer renderer = renderManager.getRenderer(); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java index 9340d3560d..cfeceb1c2a 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/MultiPassLightingLogic.java @@ -36,9 +36,9 @@ import com.jme3.light.LightList; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; +import com.jme3.material.GlMaterial; import com.jme3.material.RenderState; import com.jme3.material.TechniqueDef; -import com.jme3.material.Material.BindUnits; import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; @@ -68,7 +68,7 @@ public MultiPassLightingLogic(TechniqueDef techniqueDef) { } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, GlMaterial.BindUnits lastBindUnits) { Renderer r = renderManager.getRenderer(); Uniform lightDir = shader.getUniform("g_LightDirection"); Uniform lightColor = shader.getUniform("g_LightColor"); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java index 8e38f2e6ca..91e66ab006 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassAndImageBasedLightingLogic.java @@ -34,7 +34,6 @@ import com.jme3.asset.AssetManager; import com.jme3.light.*; import com.jme3.material.*; -import com.jme3.material.Material.BindUnits; import com.jme3.material.RenderState.BlendMode; import com.jme3.math.*; import com.jme3.renderer.*; @@ -263,7 +262,7 @@ private int setProbeData(RenderManager rm, int lastTexUnit, Uniform lightProbeDa } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, GlMaterial.BindUnits lastBindUnits) { int nbRenderedLights = 0; Renderer renderer = renderManager.getRenderer(); int batchSize = renderManager.getSinglePassLightBatchSize(); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java index 58240569ef..caee9bb30c 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/SinglePassLightingLogic.java @@ -37,10 +37,10 @@ import com.jme3.light.LightList; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; +import com.jme3.material.GlMaterial; import com.jme3.material.RenderState; import com.jme3.material.RenderState.BlendMode; import com.jme3.material.TechniqueDef; -import com.jme3.material.Material.BindUnits; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.math.Vector4f; @@ -207,7 +207,7 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, GlMaterial.BindUnits lastBindUnits) { int nbRenderedLights = 0; Renderer renderer = renderManager.getRenderer(); int batchSize = renderManager.getSinglePassLightBatchSize(); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java index fe35dc4c4d..a6f3b0a3ec 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/StaticPassLightingLogic.java @@ -37,8 +37,8 @@ import com.jme3.light.LightList; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; +import com.jme3.material.GlMaterial; import com.jme3.material.TechniqueDef; -import com.jme3.material.Material.BindUnits; import com.jme3.math.ColorRGBA; import com.jme3.math.Matrix4f; import com.jme3.math.Vector3f; @@ -172,7 +172,7 @@ private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightLi } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { + public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, GlMaterial.BindUnits lastBindUnits) { Renderer renderer = renderManager.getRenderer(); Matrix4f viewMatrix = renderManager.getCurrentCamera().getViewMatrix(); updateLightListUniforms(viewMatrix, shader, lights); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java index 31f970a176..ad1ecc109e 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java @@ -33,14 +33,14 @@ import com.jme3.asset.AssetManager; import com.jme3.light.LightList; -import com.jme3.material.Material.BindUnits; +import com.jme3.material.GlMaterial; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.shader.DefineList; import com.jme3.shader.Shader; import com.jme3.shader.Uniform; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.util.EnumSet; /** @@ -73,7 +73,7 @@ public interface TechniqueDefLogic { * * @return The shader to use for rendering. */ - public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines); /** @@ -83,7 +83,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager * {@link com.jme3.material.MatParam material parameters}, and * {@link com.jme3.shader.UniformBinding uniform bindings} * have already been applied by the material, however, - * {@link com.jme3.material.RenderState}, {@link Uniform uniforms}, {@link Texture textures}, + * {@link com.jme3.material.RenderState}, {@link Uniform uniforms}, {@link GlTexture textures}, * can still be overridden. * * @param renderManager The render manager to perform the rendering against. @@ -91,7 +91,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager * {@link #makeCurrent(com.jme3.asset.AssetManager, com.jme3.renderer.RenderManager, java.util.EnumSet, com.jme3.light.LightList, com.jme3.shader.DefineList)}. * @param geometry The geometry to render * @param lights Lights which influence the geometry. - * @param lastTexUnit the index of the most recently used texture unit + * @param lastBindUnits the index of the most recently used texture unit */ - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits); + void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, GlMaterial.BindUnits lastBindUnits); } diff --git a/jme3-core/src/main/java/com/jme3/math/Matrix4f.java b/jme3-core/src/main/java/com/jme3/math/Matrix4f.java index 4f9a6e2f35..e097de818b 100644 --- a/jme3-core/src/main/java/com/jme3/math/Matrix4f.java +++ b/jme3-core/src/main/java/com/jme3/math/Matrix4f.java @@ -2560,4 +2560,16 @@ public Matrix4f clone() { throw new AssertionError(); // can not happen } } + + /** + * Flips the sign of the Y scalar component (m11) to make Vulkan renderings + * appear upright in clip space. + * + * @return this instance + */ + public Matrix4f flipYScalarForVulkan() { + m11 = -m11; + return this; + } + } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index e25f893e24..33ba40166a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -40,7 +40,8 @@ import com.jme3.opencl.Image.ImageType; import com.jme3.scene.VertexBuffer; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -229,7 +230,7 @@ public Buffer createBufferFromHost(ByteBuffer data) { * @param access the allowed memory access for kernels * @return the OpenCL image */ - public abstract Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int miplevel, MemoryAccess access); + public abstract Image bindImage(GlImage image, GlTexture.Type textureType, int miplevel, MemoryAccess access); /** * Creates a shared image object from a jME3 texture. @@ -254,19 +255,19 @@ public Buffer createBufferFromHost(ByteBuffer data) { * @param access the allowed memory access for kernels * @return the OpenCL image */ - public Image bindImage(Texture texture, int miplevel, MemoryAccess access) { + public Image bindImage(GlTexture texture, int miplevel, MemoryAccess access) { return bindImage(texture.getImage(), texture.getType(), miplevel, access); } /** - * Alternative version to {@link #bindImage(com.jme3.texture.Texture, int, com.jme3.opencl.MemoryAccess) }, + * Alternative version to {@link #bindImage(GlTexture, int, com.jme3.opencl.MemoryAccess) }, * uses {@code miplevel=0}. * * @param texture the jME3 texture * @param access the allowed memory access for kernels * @return the OpenCL image */ - public Image bindImage(Texture texture, MemoryAccess access) { + public Image bindImage(GlTexture texture, MemoryAccess access) { return bindImage(texture, 0, access); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 5b07d0f376..026fa516f5 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -32,6 +32,9 @@ package com.jme3.opencl; import com.jme3.math.ColorRGBA; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; + import java.nio.ByteBuffer; import java.util.Objects; @@ -48,7 +51,7 @@ * An image is created from scratch using * {@link Context#createImage(com.jme3.opencl.MemoryAccess, com.jme3.opencl.Image.ImageFormat, com.jme3.opencl.Image.ImageDescriptor) } * or from OpenGL by - * {@link Context#bindImage(com.jme3.texture.Image, com.jme3.texture.Texture.Type, int, com.jme3.opencl.MemoryAccess) } + * {@link Context#bindImage(GlImage, GlTexture.Type, int, com.jme3.opencl.MemoryAccess) } * (and alternative versions). * *

@@ -504,7 +507,7 @@ public ImageMapping(ByteBuffer buffer, long rowPitch, long slicePitch) { /** * Acquires this image object for using. Only call this method if this image * represents a shared object from OpenGL, created with e.g. - * {@link Context#bindImage(com.jme3.texture.Image, com.jme3.texture.Texture.Type, int, com.jme3.opencl.MemoryAccess) } + * {@link Context#bindImage(GlImage, GlTexture.Type, int, com.jme3.opencl.MemoryAccess) } * or variations. * This method must be called before the image is used. After the work is * done, the image must be released by calling @@ -519,7 +522,7 @@ public ImageMapping(ByteBuffer buffer, long rowPitch, long slicePitch) { /** * Acquires this image object for using. Only call this method if this image * represents a shared object from OpenGL, created with e.g. - * {@link Context#bindImage(com.jme3.texture.Image, com.jme3.texture.Texture.Type, int, com.jme3.opencl.MemoryAccess) } + * {@link Context#bindImage(GlImage, GlTexture.Type, int, com.jme3.opencl.MemoryAccess) } * or variations. * This method must be called before the image is used. After the work is * done, the image must be released by calling diff --git a/jme3-core/src/main/java/com/jme3/opencl/package-info.java b/jme3-core/src/main/java/com/jme3/opencl/package-info.java index 0a19e3a24a..922e4e1f1d 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/package-info.java +++ b/jme3-core/src/main/java/com/jme3/opencl/package-info.java @@ -107,8 +107,8 @@ * by calling {@link com.jme3.opencl.Context#bindVertexBuffer(com.jme3.scene.VertexBuffer, com.jme3.opencl.MemoryAccess) } * resulting in a {@link com.jme3.opencl.Buffer} object. This buffer object * can then be used as usual, allowing e.g. the dynamic modification of position buffers for particle systems.
- * {@link com.jme3.texture.Image} and {@link com.jme3.texture.Texture} objects can be used in OpenCL with the method - * {@link com.jme3.opencl.Context#bindImage(com.jme3.texture.Texture, com.jme3.opencl.MemoryAccess) } + * {@link com.jme3.texture.GlImage} and {@link com.jme3.texture.GlTexture} objects can be used in OpenCL with the method + * {@link com.jme3.opencl.Context#bindImage(GlTexture, com.jme3.opencl.MemoryAccess) } * or variations of this method. The same holds for {@link com.jme3.texture.FrameBuffer.RenderBuffer} objects * using {@link com.jme3.opencl.Context#bindRenderBuffer(com.jme3.texture.FrameBuffer.RenderBuffer, com.jme3.opencl.MemoryAccess) }. * These methods result in an OpenCL-Image. Usages are e.g. animated textures, @@ -157,3 +157,5 @@ package com.jme3.opencl; //TODO: add profiling to Kernel, CommandQueue + +import com.jme3.texture.GlTexture; \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/post/Filter.java b/jme3-core/src/main/java/com/jme3/post/Filter.java index efdb19b04a..a7ea09851a 100644 --- a/jme3-core/src/main/java/com/jme3/post/Filter.java +++ b/jme3-core/src/main/java/com/jme3/post/Filter.java @@ -40,8 +40,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import java.io.IOException; @@ -306,7 +306,7 @@ protected void cleanUpFilter(Renderer r) { * * @param depthTexture the desired Texture */ - protected void setDepthTexture(Texture depthTexture){ + protected void setDepthTexture(GlTexture depthTexture){ getMaterial().setTexture("DepthTexture", depthTexture); } diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java index aa8896a951..749ca97566 100644 --- a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java +++ b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java @@ -38,8 +38,8 @@ import com.jme3.renderer.*; import com.jme3.renderer.queue.RenderQueue; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.ui.Picture; @@ -227,7 +227,8 @@ private void renderProcessing(Renderer r, FrameBuffer buff, Material mat) { } - fsQuad.setMaterial(mat); + // fixme + //fsQuad.setMaterial(mat); fsQuad.updateGeometricState(); r.setFrameBuffer(buff); @@ -307,8 +308,8 @@ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { boolean wantsBilinear = filter.isRequiresBilinear(); if (wantsBilinear) { - tex.setMagFilter(Texture.MagFilter.Bilinear); - tex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + tex.setMagFilter(GlTexture.MagFilter.Bilinear); + tex.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); } buff = outputBuffer; @@ -323,8 +324,8 @@ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { filter.postFilter(r, buff); if (wantsBilinear) { - tex.setMagFilter(Texture.MagFilter.Nearest); - tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps); + tex.setMagFilter(GlTexture.MagFilter.Nearest); + tex.setMinFilter(GlTexture.MinFilter.NearestNoMipMaps); } } } diff --git a/jme3-core/src/main/java/com/jme3/post/HDRRenderer.java b/jme3-core/src/main/java/com/jme3/post/HDRRenderer.java index 857e78dbc3..81dcd48b2d 100644 --- a/jme3-core/src/main/java/com/jme3/post/HDRRenderer.java +++ b/jme3-core/src/main/java/com/jme3/post/HDRRenderer.java @@ -38,11 +38,11 @@ import com.jme3.renderer.*; import com.jme3.renderer.queue.RenderQueue; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; import java.util.Collection; @@ -91,7 +91,7 @@ public class HDRRenderer implements SceneProcessor { private float whiteLevel = 100f; private float throttle = -1; private int maxIterations = -1; - private Image.Format bufFormat = Format.RGB8; + private GlImage.Format bufFormat = Format.RGB8; private MinFilter fbMinFilter = MinFilter.BilinearNoMipMaps; private MagFilter fbMagFilter = MagFilter.Bilinear; @@ -172,7 +172,7 @@ public Picture createDisplayQuad(/*int mode, Texture tex*/) { } private Material createLumShader(int srcW, int srcH, int bufW, int bufH, int mode, - int iters, Texture tex) { + int iters, GlTexture tex) { Material mat = new Material(manager, "Common/MatDefs/Hdr/LogLum.j3md"); Vector2f blockSize = new Vector2f(1f / bufW, 1f / bufH); diff --git a/jme3-core/src/main/java/com/jme3/renderer/Camera.java b/jme3-core/src/main/java/com/jme3/renderer/Camera.java index b05c3bd86a..9635905d38 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Camera.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Camera.java @@ -1248,7 +1248,6 @@ public void updateViewProjection() { if (overrideProjection) { viewProjectionMatrix.set(projectionMatrixOverride).multLocal(viewMatrix); } else { - //viewProjectionMatrix.set(viewMatrix).multLocal(projectionMatrix); viewProjectionMatrix.set(projectionMatrix).multLocal(viewMatrix); } } @@ -1358,7 +1357,9 @@ public void onFrustumChange() { projectionMatrix.fromFrustum(frustumNear, frustumFar, frustumLeft, frustumRight, frustumTop, frustumBottom, parallelProjection); -// projectionMatrix.transposeLocal(); + + // for Vulkan rendering + projectionMatrix.flipYScalarForVulkan(); // The frame is affected by the frustum values // update it as well diff --git a/jme3-core/src/main/java/com/jme3/renderer/Caps.java b/jme3-core/src/main/java/com/jme3/renderer/Caps.java index 647d44a9a6..af2745d268 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Caps.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Caps.java @@ -35,9 +35,9 @@ import com.jme3.shader.Shader.ShaderSource; import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer.RenderBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import java.util.Collection; /** @@ -378,12 +378,12 @@ public enum Caps { * *

Use of NPOT textures is allowed iff: *

    - *
  • The {@link com.jme3.texture.Texture.WrapMode} is set to - * {@link com.jme3.texture.Texture.WrapMode#EdgeClamp}.
  • + *
  • The {@link GlTexture.WrapMode} is set to + * {@link GlTexture.WrapMode#EdgeClamp}.
  • *
  • Mip-mapping is not used, meaning - * {@link com.jme3.texture.Texture.MinFilter} is set to - * {@link com.jme3.texture.Texture.MinFilter#BilinearNoMipMaps} or - * {@link com.jme3.texture.Texture.MinFilter#NearestNoMipMaps}
  • + * {@link GlTexture.MinFilter} is set to + * {@link GlTexture.MinFilter#BilinearNoMipMaps} or + * {@link GlTexture.MinFilter#NearestNoMipMaps} *
*/ PartialNonPowerOfTwoTextures, @@ -474,18 +474,18 @@ public enum Caps { * @param tex The texture to check * @return True if it is supported, false otherwise. */ - public static boolean supports(Collection caps, Texture tex) { - if (tex.getType() == Texture.Type.TwoDimensionalArray + public static boolean supports(Collection caps, GlTexture tex) { + if (tex.getType() == GlTexture.Type.TwoDimensionalArray && !caps.contains(Caps.TextureArray)) { return false; } - Image img = tex.getImage(); + GlImage img = tex.getImage(); if (img == null) { return true; } - Format fmt = img.getFormat(); + Format fmt = img.getGlFormat(); switch (fmt) { case Depth24Stencil8: return caps.contains(Caps.PackedDepthStencilBuffer); diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java index ea6088afb9..0b3a570332 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderContext.java @@ -33,12 +33,14 @@ import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; +import com.jme3.scene.Mesh; import com.jme3.scene.VertexBuffer; import com.jme3.shader.Shader; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import java.lang.ref.WeakReference; import com.jme3.shader.bufferobject.BufferObject; +import com.jme3.texture.GlTexture; /** * Represents the current state of the graphics library. This class is used @@ -226,21 +228,21 @@ public class RenderContext { /** * Currently bound element array vertex buffer. * - * @see Renderer#renderMesh(com.jme3.scene.Mesh, int, int, com.jme3.scene.VertexBuffer[]) + * @see Renderer#renderMesh(Mesh, int, int, com.jme3.scene.VertexBuffer[]) */ public int boundElementArrayVBO; /** * ID of the bound vertex array. * - * @see Renderer#renderMesh(com.jme3.scene.Mesh, int, int, com.jme3.scene.VertexBuffer[]) + * @see Renderer#renderMesh(Mesh, int, int, com.jme3.scene.VertexBuffer[]) */ public int boundVertexArray; /** * Currently bound array vertex buffer. * - * @see Renderer#renderMesh(com.jme3.scene.Mesh, int, int, com.jme3.scene.VertexBuffer[]) + * @see Renderer#renderMesh(Mesh, int, int, com.jme3.scene.VertexBuffer[]) */ public int boundArrayVBO; @@ -257,9 +259,9 @@ public class RenderContext { /** * Current bound texture IDs for each texture unit. * - * @see Renderer#setTexture(int, com.jme3.texture.Texture) + * @see Renderer#setTexture(int, GlTexture) */ - public final WeakReference boundTextures[] + public final WeakReference boundTextures[] = new WeakReference[maxTextureUnits]; @@ -274,14 +276,14 @@ public class RenderContext { /** * IDList for texture units. * - * @see Renderer#setTexture(int, com.jme3.texture.Texture) + * @see Renderer#setTexture(int, GlTexture) */ public final IDList textureIndexList = new IDList(); /** * Currently bound texture unit. * - * @see Renderer#setTexture(int, com.jme3.texture.Texture) + * @see Renderer#setTexture(int, GlTexture) */ public int boundTextureUnit; diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index c59ffd9084..9558f30266 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -57,7 +57,6 @@ import com.jme3.scene.Mesh; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.scene.VertexBuffer; import com.jme3.shader.Shader; import com.jme3.shader.UniformBinding; import com.jme3.shader.UniformBindingManager; @@ -66,6 +65,7 @@ import com.jme3.system.Timer; import com.jme3.texture.FrameBuffer; import com.jme3.util.SafeArrayList; + import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -798,7 +798,9 @@ public void renderGeometry(Geometry geom, LightList lightList) { this.boundDrawBufferId.setValue(currentFb.getTargetIndex()); } - Material material = geom.getMaterial(); + // fixme + //Material material = geom.getMaterial(); + Material material = null; // If forcedTechnique exists, we try to force it for the render. // If it does not exist in the mat def, we check for forcedMaterial and render the geom if not null. @@ -813,14 +815,15 @@ public void renderGeometry(Geometry geom, LightList lightList) { ? activeTechnique.getDef().getName() : TechniqueDef.DEFAULT_TECHNIQUE_NAME; - geom.getMaterial().selectTechnique(forcedTechnique, this); + // fixme + //geom.getMaterial().selectTechnique(forcedTechnique, this); //saving forcedRenderState for future calls RenderState tmpRs = forcedRenderState; - if (geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) { + //if (geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) { //forcing forced technique renderState - forcedRenderState - = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); - } + // forcedRenderState + // = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); + //} // use geometry's material material.render(geom, lightList, this); material.selectTechnique(previousTechniqueName, this); @@ -889,16 +892,18 @@ public void preloadScene(Spatial scene) { throw new IllegalStateException("No material is set for Geometry: " + gm.getName()); } - gm.getMaterial().preload(this, gm); + // fixme + //gm.getMaterial().preload(this, gm); Mesh mesh = gm.getMesh(); if (mesh != null && mesh.getVertexCount() != 0 && mesh.getTriangleCount() != 0) { - for (VertexBuffer vb : mesh.getBufferList().getArray()) { - if (vb.getData() != null && vb.getUsage() != VertexBuffer.Usage.CpuOnly) { - renderer.updateBufferData(vb); - } - } + // fixme +// for (VertexBuffer vb : mesh.getBufferList().getArray()) { +// if (vb.getData() != null && vb.getUsage() != VertexBuffer.Usage.CpuOnly) { +// renderer.updateBufferData(vb); +// } +// } } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java index acd0d599e1..3a88afa46a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java @@ -33,15 +33,15 @@ import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.shader.bufferobject.BufferObject; import com.jme3.shader.Shader; import com.jme3.shader.Shader.ShaderSource; import com.jme3.system.AppSettings; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.TextureImage; import com.jme3.util.NativeObject; import java.nio.ByteBuffer; @@ -256,7 +256,7 @@ public interface Renderer { * @param byteBuf The bytebuffer to transfer color data to * @param format the image format to use when reading the frameBuffer. */ - public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format); + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, GlImage.Format format); /** * Deletes a framebuffer and all attached renderbuffers. @@ -272,7 +272,7 @@ public interface Renderer { * @param tex the Texture to assign * @throws TextureUnitException if the texture unit doesn't exist */ - public void setTexture(int unit, Texture tex) + public void setTexture(int unit, GlTexture tex) throws TextureUnitException; /** @@ -295,14 +295,14 @@ public void setTexture(int unit, Texture tex) * @param x the x position to put the image into the texture * @param y the y position to put the image into the texture */ - public void modifyTexture(Texture tex, Image pixels, int x, int y); + public void modifyTexture(GlTexture tex, GlImage pixels, int x, int y); /** * Deletes a texture from the GPU. * * @param image the texture to delete */ - public void deleteImage(Image image); + public void deleteImage(GlImage image); /** * Uploads a vertex buffer to the GPU. @@ -356,7 +356,7 @@ public void setTexture(int unit, Texture tex) * @param instanceData When count is greater than 1, these buffers provide * the per-instance attributes. */ - public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData); + public void renderMesh(GlMesh mesh, int lod, int count, VertexBuffer[] instanceData); /** * Resets all previously used {@link NativeObject Native Objects} on this Renderer. @@ -381,7 +381,7 @@ public void setTexture(int unit, Texture tex) * Sets the default anisotropic filter level for textures. * *

If the - * {@link Texture#setAnisotropicFilter(int) texture anisotropic filter} is + * {@link GlTexture#setAnisotropicFilter(int) texture anisotropic filter} is * set to 0, then the default level is used. Otherwise, if the texture level * is 1 or greater, then the texture's value overrides the default value. * @@ -432,19 +432,19 @@ public void setTexture(int unit, Texture tex) public void setMainFrameBufferSrgb(boolean srgb); /** - * If enabled, all {@link Image images} with the - * {@link Image#setColorSpace(com.jme3.texture.image.ColorSpace) sRGB flag} + * If enabled, all {@link GlImage images} with the + * {@link GlImage#setColorSpace(com.jme3.texture.image.ColorSpace) sRGB flag} * set shall undergo an sRGB to linear RGB color conversion when read by a shader. * *

The conversion is performed for the following formats: - * - {@link com.jme3.texture.Image.Format#RGB8} - * - {@link com.jme3.texture.Image.Format#RGBA8} - * - {@link com.jme3.texture.Image.Format#Luminance8} - * - {@link com.jme3.texture.Image.Format#Luminance8Alpha8} - * - {@link com.jme3.texture.Image.Format#DXT1} - * - {@link com.jme3.texture.Image.Format#DXT1A} - * - {@link com.jme3.texture.Image.Format#DXT3} - * - {@link com.jme3.texture.Image.Format#DXT5} + * - {@link GlImage.Format#RGB8} + * - {@link GlImage.Format#RGBA8} + * - {@link GlImage.Format#Luminance8} + * - {@link GlImage.Format#Luminance8Alpha8} + * - {@link GlImage.Format#DXT1} + * - {@link GlImage.Format#DXT1A} + * - {@link GlImage.Format#DXT3} + * - {@link GlImage.Format#DXT5} * *

For all other formats, no conversion is performed. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/Statistics.java b/jme3-core/src/main/java/com/jme3/renderer/Statistics.java index b2766df154..56a287a63c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Statistics.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Statistics.java @@ -34,7 +34,7 @@ import com.jme3.scene.Mesh; import com.jme3.shader.Shader; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.util.IntMap; /** @@ -235,15 +235,15 @@ public void onUniformSet() { * @param image The image that was set * @param wasSwitched If true, the texture has required a state switch */ - public void onTextureUse(Image image, boolean wasSwitched) { - assert image.getId() >= 1; + public void onTextureUse(GlImage image, boolean wasSwitched) { + assert image.getNativeObject() >= 1; if (!enabled) { return; } - if (!texturesUsed.containsKey(image.getId())) { - texturesUsed.put(image.getId(), null); + if (!texturesUsed.containsKey(image.getNativeObject())) { + texturesUsed.put(image.getNativeObject(), null); } if (wasSwitched) { 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 c73943c54e..31955b927a 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 @@ -32,8 +32,8 @@ package com.jme3.renderer.opengl; import com.jme3.renderer.Caps; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import java.util.EnumSet; /** @@ -45,21 +45,21 @@ public final class GLImageFormats { private GLImageFormats() { } - private static void format(GLImageFormat[][] formatToGL, Image.Format format, + private static void format(GLImageFormat[][] formatToGL, GlImage.Format format, int glInternalFormat, int glFormat, int glDataType){ formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType); } - private static void formatSwiz(GLImageFormat[][] formatToGL, Image.Format format, + private static void formatSwiz(GLImageFormat[][] formatToGL, GlImage.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, + private static void formatSrgb(GLImageFormat[][] formatToGL, GlImage.Format format, int glInternalFormat, int glFormat, int glDataType) @@ -67,7 +67,7 @@ private static void formatSrgb(GLImageFormat[][] formatToGL, Image.Format format formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType); } - private static void formatSrgbSwiz(GLImageFormat[][] formatToGL, Image.Format format, + private static void formatSrgbSwiz(GLImageFormat[][] formatToGL, GlImage.Format format, int glInternalFormat, int glFormat, int glDataType) @@ -75,14 +75,14 @@ private static void formatSrgbSwiz(GLImageFormat[][] formatToGL, Image.Format fo formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, false, true); } - private static void formatComp(GLImageFormat[][] formatToGL, Image.Format format, + private static void formatComp(GLImageFormat[][] formatToGL, GlImage.Format format, int glCompressedFormat, int glFormat, int glDataType){ formatToGL[0][format.ordinal()] = new GLImageFormat(glCompressedFormat, glFormat, glDataType, true); } - private static void formatCompSrgb(GLImageFormat[][] formatToGL, Image.Format format, + private static void formatCompSrgb(GLImageFormat[][] formatToGL, GlImage.Format format, int glCompressedFormat, int glFormat, int glDataType) @@ -101,7 +101,7 @@ private static void formatCompSrgb(GLImageFormat[][] formatToGL, Image.Format fo * @return An 2D array containing supported texture formats. */ public static GLImageFormat[][] getFormatsForCaps(EnumSet caps) { - GLImageFormat[][] formatToGL = new GLImageFormat[2][Image.Format.values().length]; + GLImageFormat[][] formatToGL = new GLImageFormat[2][GlImage.Format.values().length]; int halfFloatFormat = GLExt.GL_HALF_FLOAT_ARB; if (caps.contains(Caps.OpenGLES20)) { 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 09a560d4a6..06a5e93ae6 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 @@ -39,8 +39,8 @@ import com.jme3.math.*; import com.jme3.opencl.OpenCLObjectManager; import com.jme3.renderer.*; -import com.jme3.scene.Mesh; -import com.jme3.scene.Mesh.Mode; +import com.jme3.scene.GlMesh; +import com.jme3.scene.GlMesh.Mode; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; @@ -56,11 +56,11 @@ import com.jme3.shader.bufferobject.DirtyRegionsIterator; import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer.RenderBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; -import com.jme3.texture.Texture.ShadowCompareMode; -import com.jme3.texture.Texture.WrapAxis; +import com.jme3.texture.GlTexture.ShadowCompareMode; +import com.jme3.texture.GlTexture.WrapAxis; import com.jme3.texture.TextureImage; import com.jme3.texture.image.LastTextureState; import com.jme3.util.BufferUtils; @@ -1977,8 +1977,8 @@ private int convertAttachmentSlot(int attachmentSlot) { } public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { - Texture tex = rb.getTexture(); - Image image = tex.getImage(); + GlTexture tex = rb.getTexture(); + GlImage image = tex.getImage(); if (image.isUpdateNeeded()) { // Check NPOT requirements checkNonPowerOfTwo(tex); @@ -1995,12 +1995,12 @@ public void updateRenderTexture(FrameBuffer fb, RenderBuffer rb) { glfbo.glFramebufferTexture2DEXT(GLFbo.GL_FRAMEBUFFER_EXT, convertAttachmentSlot(rb.getSlot()), convertTextureType(tex.getType(), image.getMultiSamples(), rb.getFace()), - image.getId(), + image.getNativeObject(), rb.getLevel()); } else { glfbo.glFramebufferTextureLayerEXT(GLFbo.GL_FRAMEBUFFER_EXT, convertAttachmentSlot(rb.getSlot()), - image.getId(), + image.getNativeObject(), rb.getLevel(), rb.getLayer()); } @@ -2191,7 +2191,7 @@ public void setFrameBuffer(FrameBuffer fb) { if (context.boundFB != null && (context.boundFB.getMipMapsGenerationHint()!=null?context.boundFB.getMipMapsGenerationHint():generateMipmapsForFramebuffers)) { for (int i = 0; i < context.boundFB.getNumColorBuffers(); i++) { RenderBuffer rb = context.boundFB.getColorBuffer(i); - Texture tex = rb.getTexture(); + GlTexture tex = rb.getTexture(); if (tex != null && tex.getMinFilter().usesMipMapLevels()) { try { final int textureUnitIndex = 0; @@ -2199,7 +2199,7 @@ public void setFrameBuffer(FrameBuffer fb) { } catch (TextureUnitException exception) { throw new RuntimeException("Renderer lacks texture units?"); } - if (tex.getType() == Texture.Type.CubeMap) { + if (tex.getType() == GlTexture.Type.CubeMap) { glfbo.glGenerateMipmapEXT(GL.GL_TEXTURE_CUBE_MAP); } else { int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace()); @@ -2255,7 +2255,7 @@ private void readFrameBufferWithGLFormat(FrameBuffer fb, ByteBuffer byteBuf, int } @Override - public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, GlImage.Format format) { GLImageFormat glFormat = texUtil.getImageFormatWithError(format, false); readFrameBufferWithGLFormat(fb, byteBuf, glFormat.format, glFormat.dataType); } @@ -2291,7 +2291,7 @@ public void deleteFrameBuffer(FrameBuffer fb) { /*********************************************************************\ |* Textures *| \*********************************************************************/ - private int convertTextureType(Texture.Type type, int samples, int face) { + private int convertTextureType(GlTexture.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."); @@ -2333,7 +2333,7 @@ private int convertTextureType(Texture.Type type, int samples, int face) { } } - private int convertMagFilter(Texture.MagFilter filter) { + private int convertMagFilter(GlTexture.MagFilter filter) { switch (filter) { case Bilinear: return GL.GL_LINEAR; @@ -2344,7 +2344,7 @@ private int convertMagFilter(Texture.MagFilter filter) { } } - private int convertMinFilter(Texture.MinFilter filter, boolean haveMips) { + private int convertMinFilter(GlTexture.MinFilter filter, boolean haveMips) { if (haveMips){ switch (filter) { case Trilinear: @@ -2378,7 +2378,7 @@ private int convertMinFilter(Texture.MinFilter filter, boolean haveMips) { } } - private int convertWrapMode(Texture.WrapMode mode) { + private int convertWrapMode(GlTexture.WrapMode mode) { switch (mode) { case BorderClamp: case Clamp: @@ -2395,8 +2395,8 @@ private int convertWrapMode(Texture.WrapMode mode) { } @SuppressWarnings("fallthrough") - private void setupTextureParams(int unit, Texture tex) { - Image image = tex.getImage(); + private void setupTextureParams(int unit, GlTexture tex) { + GlImage image = tex.getImage(); int samples = image != null ? image.getMultiSamples() : 1; int target = convertTextureType(tex.getType(), samples, -1); @@ -2492,7 +2492,7 @@ private void setupTextureParams(int unit, Texture tex) { * @param tex The texture to validate. * @throws RendererException If the texture is not supported by the hardware */ - private void checkNonPowerOfTwo(Texture tex) { + private void checkNonPowerOfTwo(GlTexture tex) { if (!tex.getImage().isNPOT()) { // Texture is power-of-2, safe to use. return; @@ -2519,15 +2519,15 @@ private void checkNonPowerOfTwo(Texture tex) { switch (tex.getType()) { case CubeMap: case ThreeDimensional: - if (tex.getWrap(WrapAxis.R) != Texture.WrapMode.EdgeClamp) { + if (tex.getWrap(WrapAxis.R) != GlTexture.WrapMode.EdgeClamp) { throw new RendererException("repeating non-power-of-2 textures " + "are not supported by the video hardware"); } // fallthrough intentional!!! case TwoDimensionalArray: case TwoDimensional: - if (tex.getWrap(WrapAxis.S) != Texture.WrapMode.EdgeClamp - || tex.getWrap(WrapAxis.T) != Texture.WrapMode.EdgeClamp) { + if (tex.getWrap(WrapAxis.S) != GlTexture.WrapMode.EdgeClamp + || tex.getWrap(WrapAxis.T) != GlTexture.WrapMode.EdgeClamp) { throw new RendererException("repeating non-power-of-2 textures " + "are not supported by the video hardware"); } @@ -2545,13 +2545,13 @@ private void checkNonPowerOfTwo(Texture tex) { * @param img The image texture to bind * @param unit At what unit to bind the texture. */ - private void bindTextureAndUnit(int target, Image img, int unit) { + private void bindTextureAndUnit(int target, GlImage img, int unit) { if (context.boundTextureUnit != unit) { gl.glActiveTexture(GL.GL_TEXTURE0 + unit); context.boundTextureUnit = unit; } if (context.boundTextures[unit]==null||context.boundTextures[unit].get() != img.getWeakRef().get()) { - gl.glBindTexture(target, img.getId()); + gl.glBindTexture(target, img.getNativeObject()); context.boundTextures[unit] = img.getWeakRef(); statistics.onTextureUse(img, true); } else { @@ -2567,13 +2567,13 @@ private void bindTextureAndUnit(int target, Image img, int unit) { * @param img The image texture to bind * @param unit At what unit to bind the texture. */ - private void bindTextureOnly(int target, Image img, int unit) { + private void bindTextureOnly(int target, GlImage img, int unit) { if (context.boundTextures[unit] == null || context.boundTextures[unit].get() != img.getWeakRef().get()) { if (context.boundTextureUnit != unit) { gl.glActiveTexture(GL.GL_TEXTURE0 + unit); context.boundTextureUnit = unit; } - gl.glBindTexture(target, img.getId()); + gl.glBindTexture(target, img.getNativeObject()); context.boundTextures[unit] = img.getWeakRef(); statistics.onTextureUse(img, true); } else { @@ -2590,14 +2590,14 @@ private void bindTextureOnly(int target, Image img, int unit) { * @param scaleToPot If true, the image will be scaled to power-of-2 dimensions * before being uploaded. */ - public void updateTexImageData(Image img, Texture.Type type, int unit, boolean scaleToPot) { - int texId = img.getId(); + public void updateTexImageData(GlImage img, GlTexture.Type type, int unit, boolean scaleToPot) { + int texId = img.getNativeObject(); if (texId == -1) { // create texture gl.glGenTextures(intBuf1); texId = intBuf1.get(0); - img.setId(texId); - objManager.registerObject(img); + img.setId(this, texId); // setId automatically updates the native state + //objManager.registerObject(img); statistics.onNewTexture(); } @@ -2640,7 +2640,7 @@ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean s throw new RendererException("Multisample textures do not support mipmaps"); } - if (img.getFormat().isDepthFormat()) { + if (img.getGlFormat().isDepthFormat()) { img.setMultiSamples(Math.min(limits.get(Limits.DepthTextureSamples), imageSamples)); } else { img.setMultiSamples(Math.min(limits.get(Limits.ColorTextureSamples), imageSamples)); @@ -2650,7 +2650,7 @@ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean s } // Check if graphics card doesn't support depth textures - if (img.getFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) { + if (img.getGlFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) { throw new RendererException("Depth textures are not supported by the video hardware"); } @@ -2670,7 +2670,7 @@ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean s } } - Image imageForUpload; + GlImage imageForUpload; if (scaleToPot) { imageForUpload = MipMapGenerator.resizeToPowerOf2(img); } else { @@ -2720,12 +2720,12 @@ public void updateTexImageData(Image img, Texture.Type type, int unit, boolean s } @Override - public void setTexture(int unit, Texture tex) throws TextureUnitException { + public void setTexture(int unit, GlTexture tex) throws TextureUnitException { if (unit < 0 || unit >= RenderContext.maxTextureUnits) { throw new TextureUnitException(); } - Image image = tex.getImage(); + GlImage image = tex.getImage(); if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) { // Check NPOT requirements boolean scaleToPot = false; @@ -2747,12 +2747,12 @@ public void setTexture(int unit, Texture tex) throws TextureUnitException { updateTexImageData(image, tex.getType(), unit, scaleToPot); } - int texId = image.getId(); + int texId = image.getNativeObject(); assert texId != -1; setupTextureParams(unit, tex); if (debug && caps.contains(Caps.GLDebug)) { - if (tex.getName() != null) glext.glObjectLabel(GL.GL_TEXTURE, tex.getImage().getId(), tex.getName()); + if (tex.getName() != null) glext.glObjectLabel(GL.GL_TEXTURE, tex.getImage().getNativeObject(), tex.getName()); } } @@ -2761,7 +2761,7 @@ public void setTextureImage(int unit, TextureImage tex) throws TextureUnitExcept if (unit < 0 || unit >= RenderContext.maxTextureUnits) { throw new TextureUnitException(); } - WeakReference ref = context.boundTextures[unit]; + WeakReference ref = context.boundTextures[unit]; boolean bindRequired = tex.clearUpdateNeeded() || ref == null || ref.get() != tex.getImage().getWeakRef().get(); setTexture(unit, tex.getTexture()); if (gl4 != null && bindRequired) { @@ -2811,7 +2811,7 @@ public void setShaderStorageBufferObject(int bindingPoint, BufferObject bufferOb */ @Deprecated @Override - public void modifyTexture(Texture tex, Image pixels, int x, int y) { + public void modifyTexture(GlTexture tex, GlImage pixels, int x, int y) { final int textureUnitIndex = 0; try { setTexture(textureUnitIndex, tex); @@ -2819,7 +2819,7 @@ public void modifyTexture(Texture tex, Image pixels, int x, int y) { throw new RuntimeException("Renderer lacks texture units?"); } - if(caps.contains(Caps.OpenGLES20) && pixels.getFormat()!=tex.getImage().getFormat()) { + if(caps.contains(Caps.OpenGLES20) && pixels.getGlFormat()!=tex.getImage().getGlFormat()) { logger.log(Level.WARNING, "Incompatible texture subimage"); } int target = convertTextureType(tex.getType(), pixels.getMultiSamples(), -1); @@ -2838,8 +2838,8 @@ public void modifyTexture(Texture tex, Image pixels, int x, int y) { * @param areaW Width of the area to copy * @param areaH Height of the area to copy */ - public void modifyTexture(Texture2D dest, Image src, int destX, int destY, - int srcX, int srcY, int areaW, int areaH) { + public void modifyTexture(Texture2D dest, GlImage src, int destX, int destY, + int srcX, int srcY, int areaW, int areaH) { final int textureUnitIndex = 0; try { setTexture(textureUnitIndex, dest); @@ -2847,7 +2847,7 @@ public void modifyTexture(Texture2D dest, Image src, int destX, int destY, throw new RuntimeException("Renderer lacks texture units?"); } - if(caps.contains(Caps.OpenGLES20) && src.getFormat()!=dest.getImage().getFormat()) { + if(caps.contains(Caps.OpenGLES20) && src.getGlFormat()!=dest.getImage().getGlFormat()) { logger.log(Level.WARNING, "Incompatible texture subimage"); } int target = convertTextureType(dest.getType(), src.getMultiSamples(), -1); @@ -2856,8 +2856,8 @@ public void modifyTexture(Texture2D dest, Image src, int destX, int destY, } @Override - public void deleteImage(Image image) { - int texId = image.getId(); + public void deleteImage(GlImage image) { + int texId = image.getNativeObject(); if (texId != -1) { intBuf1.put(0, texId); intBuf1.position(0).limit(1); @@ -3227,7 +3227,7 @@ public void setVertexAttrib(VertexBuffer vb) { setVertexAttrib(vb, null); } - public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) { + public void drawTriangleArray(GlMesh.Mode mode, int count, int vertCount) { boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing); if (useInstancing) { glext.glDrawArraysInstancedARB(convertElementMode(mode), 0, @@ -3237,7 +3237,7 @@ public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) { } } - public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { + public void drawTriangleList(VertexBuffer indexBuf, GlMesh mesh, int count) { if (indexBuf.getBufferType() != VertexBuffer.Type.Index) { throw new IllegalArgumentException("Only index buffers are allowed as triangle lists."); } @@ -3340,7 +3340,7 @@ public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) { * @param mode input enum value (not null) * @return the corresponding GL value */ - public int convertElementMode(Mesh.Mode mode) { + public int convertElementMode(GlMesh.Mode mode) { switch (mode) { case Points: return GL.GL_POINTS; @@ -3363,7 +3363,7 @@ public int convertElementMode(Mesh.Mode mode) { } } - public void updateVertexArray(Mesh mesh, VertexBuffer instanceData) { + public void updateVertexArray(GlMesh mesh, VertexBuffer instanceData) { int id = mesh.getId(); if (id == -1) { IntBuffer temp = intBuf1; @@ -3403,7 +3403,7 @@ public void updateVertexArray(Mesh mesh, VertexBuffer instanceData) { } } - private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { + private void renderMeshDefault(GlMesh 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 @@ -3453,7 +3453,7 @@ private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] ins } @Override - public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { + public void renderMesh(GlMesh mesh, int lod, int count, VertexBuffer[] instanceData) { if (mesh.getVertexCount() == 0 || mesh.getTriangleCount() == 0 || count == 0) { return; } 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 7064f7ce2e..786856e1d4 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 @@ -33,8 +33,8 @@ import com.jme3.renderer.Caps; import com.jme3.renderer.RendererException; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.image.ColorSpace; import java.nio.ByteBuffer; import java.util.EnumSet; @@ -242,13 +242,13 @@ private void uploadTextureLevel(GLImageFormat format, int target, int level, int } } - public void uploadTexture(Image image, + public void uploadTexture(GlImage image, int target, int index, boolean linearizeSrgb) { boolean getSrgbFormat = image.getColorSpace() == ColorSpace.sRGB && linearizeSrgb; - Image.Format jmeFormat = image.getFormat(); + GlImage.Format jmeFormat = image.getGlFormat(); GLImageFormat oglFormat = getImageFormatWithError(jmeFormat, getSrgbFormat); ByteBuffer data = null; @@ -304,7 +304,7 @@ public void uploadTexture(Image image, * @deprecated Use uploadSubTexture(int target, Image src, int index,int targetX, int targetY,int srcX,int srcY, int areaWidth,int areaHeight, boolean linearizeSrgb) */ @Deprecated - public void uploadSubTexture(Image image, int target, int index, int x, int y, boolean linearizeSrgb) { + public void uploadSubTexture(GlImage image, int target, int index, int x, int y, boolean linearizeSrgb) { if (target != GL.GL_TEXTURE_2D || image.getDepth() > 1) { throw new UnsupportedOperationException("Updating non-2D texture is not supported"); } @@ -317,7 +317,7 @@ public void uploadSubTexture(Image image, int target, int index, int x, int y, b throw new UnsupportedOperationException("Updating multisampled images is not supported"); } - Image.Format jmeFormat = image.getFormat(); + GlImage.Format jmeFormat = image.getGlFormat(); if (jmeFormat.isCompressed()) { throw new UnsupportedOperationException("Updating compressed images is not supported"); @@ -345,7 +345,7 @@ public void uploadSubTexture(Image image, int target, int index, int x, int y, b oglFormat.format, oglFormat.dataType, data); } - public void uploadSubTexture(int target, Image src, int index, int targetX, int targetY, int areaX, int areaY, int areaWidth, int areaHeight, boolean linearizeSrgb) { + public void uploadSubTexture(int target, GlImage src, int index, int targetX, int targetY, int areaX, int areaY, int areaWidth, int areaHeight, boolean linearizeSrgb) { if (target != GL.GL_TEXTURE_2D || src.getDepth() > 1) { throw new UnsupportedOperationException("Updating non-2D texture is not supported"); } @@ -358,7 +358,7 @@ public void uploadSubTexture(int target, Image src, int index, int targetX, int throw new UnsupportedOperationException("Updating multisampled images is not supported"); } - Image.Format jmeFormat = src.getFormat(); + GlImage.Format jmeFormat = src.getGlFormat(); if (jmeFormat.isCompressed()) { throw new UnsupportedOperationException("Updating compressed images is not supported"); @@ -375,7 +375,7 @@ public void uploadSubTexture(int target, Image src, int index, int targetX, int throw new IndexOutOfBoundsException("The image index " + index + " is not valid for the given image"); } - int Bpp = src.getFormat().getBitsPerPixel() / 8; + int Bpp = src.getGlFormat().getBitsPerPixel() / 8; int srcWidth = src.getWidth(); int cpos = data.position(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/vulkan/VulkanRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/vulkan/VulkanRenderer.java new file mode 100644 index 0000000000..a41424268c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/vulkan/VulkanRenderer.java @@ -0,0 +1,10 @@ +package com.jme3.renderer.vulkan; + +import com.jme3.system.NullRenderer; + +/** + * Temporary placeholder. + */ +public class VulkanRenderer extends NullRenderer { + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/vulkan/VulkanUtils.java b/jme3-core/src/main/java/com/jme3/renderer/vulkan/VulkanUtils.java new file mode 100644 index 0000000000..c251de6b5a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/vulkan/VulkanUtils.java @@ -0,0 +1,179 @@ +package com.jme3.renderer.vulkan; + +import com.jme3.util.natives.Native; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.system.Struct; +import org.lwjgl.system.StructBuffer; +import org.lwjgl.vulkan.VkInstance; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.util.Collection; +import java.util.Iterator; +import java.util.function.*; +import java.util.stream.Stream; + +import static org.lwjgl.vulkan.VK10.*; + +public class VulkanUtils { + + public static final int UINT32_MAX = 0xFFFFFFFF; + + public static int check(int vulkanCode, String message) { + if (vulkanCode != VK_SUCCESS) { + throw new RuntimeException(message); + } + return vulkanCode; + } + + public static int check(int vulkanCode) { + return check(vulkanCode, "Operation unsuccessful: " + vulkanCode); + } + + public static long nonNull(long id, String message) { + if (id == MemoryUtil.NULL) { + throw new NullPointerException(message); + } + return id; + } + + public static long nonNull(long id) { + return nonNull(id, "Pointer ID is NULL."); + } + + public static T enumerateBuffer(MemoryStack stack, IntFunction factory, BiConsumer fetch) { + IntBuffer count = stack.callocInt(1); + fetch.accept(count, null); + if (count.get(0) <= 0) { + return null; + } + T buffer = factory.apply(count.get(0)); + fetch.accept(count, buffer); + return buffer; + } + + public static T enumerateBuffer(IntFunction factory, BiConsumer fetch) { + IntBuffer count = MemoryUtil.memAllocInt(1); + fetch.accept(count, null); + if (count.get(0) <= 0) { + return null; + } + T buffer = factory.apply(count.get(0)); + fetch.accept(count, buffer); + MemoryUtil.memFree(count); + return buffer; + } + + public static PointerBuffer toPointers(MemoryStack stack, Stream stream, int count, Function toBytes) { + PointerBuffer ptrs = stack.mallocPointer(count); + stream.map(toBytes).forEach(ptrs::put); + return ptrs.rewind(); + } + + public static PointerBuffer toPointers(MemoryStack stack, Collection collection, Function toBytes) { + return toPointers(stack, collection.stream(), collection.size(), toBytes); + } + + public static long getPointer(MemoryStack stack, Consumer action) { + PointerBuffer ptr = stack.mallocPointer(1); + action.accept(ptr); + return ptr.get(0); + } + + public static long getLong(MemoryStack stack, Consumer action) { + LongBuffer l = stack.mallocLong(1); + action.accept(l); + return l.get(0); + } + + public static int getInt(MemoryStack stack, Consumer action) { + IntBuffer i = stack.mallocInt(1); + action.accept(i); + return i.get(0); + } + + public static PointerBuffer gatherPointers(MemoryStack stack, Collection pointers) { + int size = 0; + for (PointerBuffer p : pointers) { + size += p.limit(); + } + PointerBuffer gather = stack.mallocPointer(size); + for (PointerBuffer p : pointers) { + gather.put(p); + } + return gather.rewind(); + } + + public static void printListed(String label, Iterable list, Function toString) { + System.out.println(label); + for (T o : list) { + System.out.println(" " + toString.apply(o)); + } + } + + public static void verifyExtensionMethod(VkInstance instance, String name) { + if (vkGetInstanceProcAddr(instance, name) == MemoryUtil.NULL) { + throw new NullPointerException("Extension method " + name + " does not exist."); + } + } + + public static NativeIterator iteratePointers(PointerBuffer buffer, LongFunction func) { + return new NativeIterator<>(buffer, func); + } + + public static boolean isBitSet(int n, int bit) { + return (n & bit) > 0; + } + + public static int sharingMode(boolean concurrent) { + return concurrent ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE; + } + + public static , E extends Struct> T accumulate(Collection collection, IntFunction allocate) { + T buffer = allocate.apply(collection.size()); + for (E e : collection) { + buffer.put(e); + } + return buffer.rewind(); + } + + public static LongBuffer accumulate(MemoryStack stack, Native... natives) { + LongBuffer buf = stack.mallocLong(natives.length); + for (int i = 0; i < buf.limit(); i++) { + buf.put(i, natives[i].getNativeObject()); + } + return buf; + } + + public static class NativeIterator implements Iterable, Iterator { + + private final PointerBuffer pointers; + private final LongFunction func; + private int index = 0; + + public NativeIterator(PointerBuffer pointers, LongFunction func) { + this.pointers = pointers; + this.func = func; + } + + @Override + public Iterator iterator() { + return this; + } + + @Override + public boolean hasNext() { + return index < pointers.limit(); + } + + @Override + public T next() { + return func.apply(pointers.get(index++)); + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/scene/Geometry.java b/jme3-core/src/main/java/com/jme3/scene/Geometry.java index 008e987f1d..cd12be2717 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Geometry.java +++ b/jme3-core/src/main/java/com/jme3/scene/Geometry.java @@ -42,11 +42,17 @@ import com.jme3.material.Material; import com.jme3.math.Matrix4f; import com.jme3.renderer.Camera; -import com.jme3.scene.VertexBuffer.Type; +import com.jme3.renderer.Renderer; import com.jme3.scene.mesh.MorphTarget; import com.jme3.util.TempVars; import com.jme3.util.clone.Cloner; import com.jme3.util.clone.IdentityCloneFunction; +import com.jme3.vulkan.buffers.GpuBuffer; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.material.MatrixTransformMaterial; +import com.jme3.vulkan.material.NewMaterial; +import com.jme3.vulkan.pipelines.Pipeline; + import java.io.IOException; import java.util.Queue; import java.util.logging.Level; @@ -68,6 +74,7 @@ public class Geometry extends Spatial { protected Mesh mesh; protected transient int lodLevel = 0; protected Material material; + protected MatrixTransformMaterial transforms; // stores the matrices unique to this geometry /** * When true, the geometry's transform will not be applied. */ @@ -136,6 +143,11 @@ public Geometry(String name, Mesh mesh) { this.mesh = mesh; } + public Geometry(String name, Mesh mesh, MatrixTransformMaterial transforms) { + this(name, mesh); + this.transforms = transforms; + } + /** * Create a geometry node with mesh data and material. * @@ -143,11 +155,28 @@ public Geometry(String name, Mesh mesh) { * @param mesh The mesh data for this geometry * @param material The material for this geometry */ - public Geometry(String name, Mesh mesh, Material material) { + public Geometry(String name, Mesh mesh, NewMaterial material) { this(name, mesh); setMaterial(material); } + public void updateTransformMaterial(Camera cam) { + Matrix4f worldViewProjection = cam.getViewProjectionMatrix().mult(worldTransform.toTransformMatrix()); + GpuBuffer matBuffer = transforms.getTransforms().getResource().get(); + worldViewProjection.fillFloatBuffer(matBuffer.mapFloats(), true); + matBuffer.unmap(); + } + + public void draw(CommandBuffer cmd, Pipeline pipeline) { + transforms.bind(cmd, pipeline); + material.bind(cmd, pipeline, transforms.getSets().size()); + mesh.draw(cmd, this); + } + + public void draw(Renderer renderer) { + mesh.draw(renderer, this, 1, null); + } + @Override public boolean checkCulling(Camera cam) { if (isGrouped()) { @@ -177,7 +206,7 @@ public void setIgnoreTransform(boolean ignoreTransform) { * Sets the LOD level to use when rendering the mesh of this geometry. * Level 0 indicates that the default index buffer should be used, * levels [1, LodLevels + 1] represent the levels set on the mesh - * with {@link Mesh#setLodLevels(com.jme3.scene.VertexBuffer[]) }. + * with {@link GlMesh#setLodLevels(com.jme3.scene.VertexBuffer[]) }. * * @param lod The lod level to set */ @@ -256,7 +285,7 @@ public void setMesh(Mesh mesh) { * * @return the mesh to use for this geometry * - * @see #setMesh(com.jme3.scene.Mesh) + * @see #setMesh(Mesh) */ public Mesh getMesh() { return mesh; @@ -281,7 +310,7 @@ public void setMaterial(Material material) { * * @return the material that is used for this geometry * - * @see #setMaterial(com.jme3.material.Material) + * @see #setMaterial(NewMaterial) */ public Material getMaterial() { return material; @@ -480,7 +509,7 @@ public int collideWith(Collidable other, CollisionResults results) { // NOTE: BIHTree in mesh already checks collision with the // mesh's bound int prevSize = results.size(); - int added = mesh.collideWith(other, cachedWorldMat, worldBound, results); + int added = mesh.collideWith(other, this, results); int newSize = results.size(); for (int i = prevSize; i < newSize; i++) { results.getCollisionDirect(i).setGeometry(this); @@ -551,10 +580,13 @@ public Spatial deepClone() { return super.deepClone(); } + @Deprecated public Spatial oldDeepClone() { Geometry geomClone = clone(true); - geomClone.mesh = mesh.deepClone(); - return geomClone; + // fixme + //geomClone.mesh = mesh.deepClone(); + //return geomClone; + throw new UnsupportedOperationException("Mesh deep clone not yet supported."); } /** @@ -589,9 +621,11 @@ public void cloneFields(Cloner cloner, Object original) { // See if we clone the mesh using the special animation // semi-deep cloning - if (shallowClone && mesh != null && mesh.getBuffer(Type.BindPosePosition) != null) { + // fixme + if (shallowClone && mesh != null && false /*mesh.getBuffer(Type.BindPosePosition) != null*/) { // Then we need to clone the mesh a little deeper - this.mesh = mesh.cloneForAnim(); + //this.mesh = mesh.cloneForAnim(); + throw new UnsupportedOperationException("Animation cloning not yet supported."); } else { // Do whatever the cloner wants to do about it this.mesh = cloner.clone(mesh); @@ -600,18 +634,20 @@ public void cloneFields(Cloner cloner, Object original) { this.material = cloner.clone(material); } - public void setMorphState(float[] state) { - if (mesh == null || mesh.getMorphTargets().length == 0) { - return; - } - - int nbMorphTargets = mesh.getMorphTargets().length; + // todo: fix morph animations - if (morphState == null) { - morphState = new float[nbMorphTargets]; - } - System.arraycopy(state, 0, morphState, 0, morphState.length); - this.dirtyMorph = true; + public void setMorphState(float[] state) { +// if (mesh == null || mesh.getMorphTargets().length == 0) { +// return; +// } +// +// int nbMorphTargets = mesh.getMorphTargets().length; +// +// if (morphState == null) { +// morphState = new float[nbMorphTargets]; +// } +// System.arraycopy(state, 0, morphState, 0, morphState.length); +// this.dirtyMorph = true; } /** @@ -623,11 +659,11 @@ public void setMorphState(float[] state) { * @param state The state to set the morph to */ public void setMorphState(String morphTarget, float state) { - int index = mesh.getMorphIndex(morphTarget); - if (index >= 0) { - morphState[index] = state; - this.dirtyMorph = true; - } +// int index = mesh.getMorphIndex(morphTarget); +// if (index >= 0) { +// morphState[index] = state; +// this.dirtyMorph = true; +// } } /** @@ -656,8 +692,10 @@ public void setDirtyMorph(boolean dirtyMorph) { * @return an array */ public float[] getMorphState() { + // fixme if (morphState == null) { - morphState = new float[mesh.getMorphTargets().length]; + //morphState = new float[mesh.getMorphTargets().length]; + morphState = new float[0]; } return morphState; } @@ -669,7 +707,9 @@ public float[] getMorphState() { * @return the state of the morph, or -1 if the morph is not found */ public float getMorphState(String morphTarget) { - int index = mesh.getMorphIndex(morphTarget); + // fixme + //int index = mesh.getMorphIndex(morphTarget); + int index = -1; if (index < 0) { return -1; } else { @@ -720,10 +760,11 @@ public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule oc = ex.getCapsule(this); oc.write(mesh, "mesh", null); - if (material != null) { - oc.write(material.getAssetName(), "materialName", null); - } - oc.write(material, "material", null); + // fixme +// if (material != null) { +// oc.write(material.getAssetName(), "materialName", null); +// } +// oc.write(material, "material", null); oc.write(ignoreTransform, "ignoreTransform", false); } @@ -732,14 +773,14 @@ public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule ic = im.getCapsule(this); mesh = (Mesh) ic.readSavable("mesh", null); - material = null; String matName = ic.readString("materialName", null); if (matName != null) { // Material name is set, // Attempt to load material via J3M try { - material = im.getAssetManager().loadMaterial(matName); + // fixme + //material = im.getAssetManager().loadMaterial(matName); } catch (AssetNotFoundException ex) { // Cannot find J3M file. if (logger.isLoggable(Level.FINE)) { @@ -750,7 +791,8 @@ public void read(JmeImporter im) throws IOException { } // If material is NULL, try to load it from the geometry if (material == null) { - material = (Material) ic.readSavable("material", null); + // fixme + material = (NewMaterial) ic.readSavable("material", null); } ignoreTransform = ic.readBoolean("ignoreTransform", false); @@ -758,9 +800,17 @@ public void read(JmeImporter im) throws IOException { // Fix shared mesh (if set) Mesh sharedMesh = getUserData(UserData.JME_SHAREDMESH); if (sharedMesh != null) { - getMesh().extractVertexData(sharedMesh); + // fixme + //getMesh().extractVertexData(sharedMesh); setUserData(UserData.JME_SHAREDMESH, null); + throw new UnsupportedOperationException("Shared meshes not yet supported."); } } } + + @Override + protected void findNextIteration(GraphIterator iterator) { + iterator.moveUp(); + } + } diff --git a/jme3-core/src/main/java/com/jme3/scene/GeometryGroupNode.java b/jme3-core/src/main/java/com/jme3/scene/GeometryGroupNode.java index db245392ca..be5e0f0492 100644 --- a/jme3-core/src/main/java/com/jme3/scene/GeometryGroupNode.java +++ b/jme3-core/src/main/java/com/jme3/scene/GeometryGroupNode.java @@ -57,7 +57,7 @@ public GeometryGroupNode(String name) { /** * Called by {@link Geometry geom} to specify that its - * {@link Geometry#setMesh(com.jme3.scene.Mesh) mesh} + * {@link Geometry#setMesh(Mesh) mesh} * has been changed. * * This is also called when the geometry's diff --git a/jme3-core/src/main/java/com/jme3/scene/GlMesh.java b/jme3-core/src/main/java/com/jme3/scene/GlMesh.java new file mode 100644 index 0000000000..205e057f3d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/scene/GlMesh.java @@ -0,0 +1,1759 @@ +/* + * Copyright (c) 2009-2022 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.scene; + +import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingVolume; +import com.jme3.collision.Collidable; +import com.jme3.collision.CollisionResults; +import com.jme3.collision.UnsupportedCollisionException; +import com.jme3.collision.bih.BIHTree; +import com.jme3.export.*; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.*; +import com.jme3.renderer.Renderer; +import com.jme3.scene.VertexBuffer.*; +import com.jme3.scene.mesh.*; +import com.jme3.util.*; +import com.jme3.util.IntMap.Entry; +import com.jme3.util.clone.Cloner; +import com.jme3.util.clone.JmeCloneable; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.mesh.AttributeModifier; + +import java.io.IOException; +import java.nio.*; +import java.util.ArrayList; + +/** + * Mesh is used to store rendering data. + *

+ * All visible elements in a scene are represented by meshes. + * Meshes may contain three types of geometric primitives: + *

    + *
  • Points - Every vertex represents a single point in space. + *
  • Lines - 2 vertices represent a line segment, with the width specified + * via {@link Material#getAdditionalRenderState()} and {@link RenderState#setLineWidth(float)}.
  • + *
  • Triangles - 3 vertices represent a solid triangle primitive.
  • + *
+ * + * @author Kirill Vainer + */ +public class GlMesh implements Mesh, Savable, Cloneable, JmeCloneable { + + @Override + public int collideWith(Collidable other, CollisionResults results) throws UnsupportedCollisionException { + return 0; + } + + /** + * The mode of the Mesh specifies both the type of primitive represented + * by the mesh and how the data should be interpreted. + */ + public enum Mode { + /** + * A primitive is a single point in space. The size of {@link Mode#Points points} are + * determined via the vertex shader's gl_PointSize output. + */ + Points(true), + /** + * A primitive is a line segment. Every two vertices specify + * a single line. {@link Material#getAdditionalRenderState()} + * and {@link RenderState#setLineWidth(float)} can be used + * to set the width of the lines. + */ + Lines(true), + /** + * A primitive is a line segment. The first two vertices specify + * a single line, while subsequent vertices are combined with the + * previous vertex to make a line. {@link Material#getAdditionalRenderState()} + * and {@link RenderState#setLineWidth(float)} can + * be used to set the width of the lines. + */ + LineStrip(false), + /** + * Identical to {@link #LineStrip} except that at the end + * the last vertex is connected with the first to form a line. + * {@link Material#getAdditionalRenderState()} + * and {@link RenderState#setLineWidth(float)} can be used + * to set the width of the lines. + */ + LineLoop(false), + /** + * A primitive is a triangle. Each 3 vertices specify a single + * triangle. + */ + Triangles(true), + /** + * Similar to {@link #Triangles}, the first 3 vertices + * specify a triangle, while subsequent vertices are combined with + * the previous two to form a triangle. + */ + TriangleStrip(false), + /** + * Similar to {@link #Triangles}, the first 3 vertices + * specify a triangle, each 2 subsequent vertices are combined + * with the very first vertex to make a triangle. + */ + TriangleFan(false), + /** + * A combination of various triangle modes. It is best to avoid + * using this mode as it may not be supported by all renderers. + * The {@link GlMesh#setModeStart(int[]) mode start points} and + * {@link GlMesh#setElementLengths(int[]) element lengths} must + * be specified for this mode. + */ + Hybrid(false), + /** + * Used for Tessellation only. Requires to set the number of vertices + * for each patch (default is 3 for triangle tessellation) + */ + Patch(true); + + private boolean listMode = false; + + private Mode(boolean listMode) { + this.listMode = listMode; + } + + /** + * Returns true if the specified mode is a list mode (meaning + * ,it specifies the indices as a linear list and not some special + * format). + * Will return true for the types {@link #Points}, {@link #Lines} and + * {@link #Triangles}. + * + * @return true if the mode is a list type mode + */ + public boolean isListMode() { + return listMode; + } + } + + /** + * Default Variables + */ + private static final int DEFAULT_VERTEX_ARRAY_ID = -1; + private static final CollisionData DEFAULT_COLLISION_TREE = null; + + private static final float DEFAULT_POINT_SIZE = 1.0f; + private static final float DEFAULT_LINE_WIDTH = 1.0f; + + private static final int DEFAULT_VERT_COUNT = -1; + private static final int DEFAULT_ELEMENT_COUNT = -1; + private static final int DEFAULT_INSTANCE_COUNT = -1; + private static final int DEFAULT_PATCH_VERTEX_COUNT = 3; + private static final int DEFAULT_MAX_NUM_WEIGHTS = -1; + + /** + * The bounding volume that contains the mesh entirely. + * By default a BoundingBox (AABB). + */ + private BoundingVolume meshBound = new BoundingBox(); + + private CollisionData collisionTree = DEFAULT_COLLISION_TREE; + + private SafeArrayList buffersList = new SafeArrayList<>(VertexBuffer.class); + private IntMap buffers = new IntMap<>(); + private VertexBuffer[] lodLevels; + + private float pointSize = DEFAULT_POINT_SIZE; + private float lineWidth = DEFAULT_LINE_WIDTH; + + private transient int vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; + + private int vertCount = DEFAULT_VERT_COUNT; + private int elementCount = DEFAULT_ELEMENT_COUNT; + private int instanceCount = DEFAULT_INSTANCE_COUNT; + private int patchVertexCount = DEFAULT_PATCH_VERTEX_COUNT; //only used for tessellation + private int maxNumWeights = DEFAULT_MAX_NUM_WEIGHTS; // only if using skeletal animation + + private int[] elementLengths; + private int[] modeStart; + + private Mode mode = Mode.Triangles; + + private SafeArrayList morphTargets; + + /** + * Creates a new mesh with no {@link VertexBuffer vertex buffers}. + */ + public GlMesh() { + } + + /** + * Create a shallow clone of this Mesh. The {@link VertexBuffer vertex + * buffers} are shared between this and the clone mesh, the rest + * of the data is cloned. + * + * @return A shallow clone of the mesh + */ + @Override + public GlMesh clone() { + try { + GlMesh clone = (GlMesh) super.clone(); + clone.meshBound = meshBound.clone(); + clone.collisionTree = collisionTree != null ? collisionTree : null; + clone.buffers = buffers.clone(); + clone.buffersList = new SafeArrayList<>(VertexBuffer.class, buffersList); + clone.vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; + if (elementLengths != null) { + clone.elementLengths = elementLengths.clone(); + } + if (modeStart != null) { + clone.modeStart = modeStart.clone(); + } + return clone; + } catch (CloneNotSupportedException ex) { + throw new AssertionError(); + } + } + + /** + * Creates a deep clone of this mesh. + * The {@link VertexBuffer vertex buffers} and the data inside them + * is cloned. + * + * @return a deep clone of this mesh. + */ + public GlMesh deepClone() { + try { + GlMesh clone = (GlMesh) super.clone(); + clone.meshBound = meshBound != null ? meshBound.clone() : null; + + // TODO: Collision tree cloning + //clone.collisionTree = collisionTree != null ? collisionTree : null; + clone.collisionTree = DEFAULT_COLLISION_TREE; // it will get re-generated in any case + + clone.buffers = new IntMap<>(); + clone.buffersList = new SafeArrayList<>(VertexBuffer.class); + for (VertexBuffer vb : buffersList.getArray()) { + VertexBuffer bufClone = vb.clone(); + clone.buffers.put(vb.getBufferType().ordinal(), bufClone); + clone.buffersList.add(bufClone); + } + + clone.vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; + clone.vertCount = vertCount; + clone.elementCount = elementCount; + clone.instanceCount = instanceCount; + + // although this could change + // if the bone weight/index buffers are modified + clone.maxNumWeights = maxNumWeights; + + clone.elementLengths = elementLengths != null ? elementLengths.clone() : null; + clone.modeStart = modeStart != null ? modeStart.clone() : null; + return clone; + } catch (CloneNotSupportedException ex) { + throw new AssertionError(); + } + } + + /** + * Clone the mesh for animation use. + * This creates a shallow clone of the mesh, sharing most + * of the {@link VertexBuffer vertex buffer} data, however the + * {@link Type#Position}, {@link Type#Normal}, and {@link Type#Tangent} buffers + * are deeply cloned. + * + * @return A clone of the mesh for animation use. + */ + public GlMesh cloneForAnim() { + GlMesh clone = clone(); + if (getBuffer(Type.BindPosePosition) != null) { + VertexBuffer oldPos = getBuffer(Type.Position); + + // NOTE: creates deep clone + VertexBuffer newPos = oldPos.clone(); + clone.clearBuffer(Type.Position); + clone.setBuffer(newPos); + + if (getBuffer(Type.BindPoseNormal) != null) { + VertexBuffer oldNorm = getBuffer(Type.Normal); + VertexBuffer newNorm = oldNorm.clone(); + clone.clearBuffer(Type.Normal); + clone.setBuffer(newNorm); + + if (getBuffer(Type.BindPoseTangent) != null) { + VertexBuffer oldTang = getBuffer(Type.Tangent); + VertexBuffer newTang = oldTang.clone(); + clone.clearBuffer(Type.Tangent); + clone.setBuffer(newTang); + } + } + } + return clone; + } + + /** + * Called internally by com.jme3.util.clone.Cloner. Do not call directly. + */ + @Override + public GlMesh jmeClone() { + try { + GlMesh clone = (GlMesh) super.clone(); + clone.vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; + return clone; + } catch (CloneNotSupportedException ex) { + throw new AssertionError(); + } + } + + /** + * Called internally by com.jme3.util.clone.Cloner. Do not call directly. + */ + @Override + public void cloneFields(Cloner cloner, Object original) { + // Probably could clone this now but it will get regenerated anyway. + this.collisionTree = DEFAULT_COLLISION_TREE; + + this.meshBound = cloner.clone(meshBound); + this.buffersList = cloner.clone(buffersList); + this.buffers = cloner.clone(buffers); + this.lodLevels = cloner.clone(lodLevels); + this.elementLengths = cloner.clone(elementLengths); + this.modeStart = cloner.clone(modeStart); + } + + /** + * @param forSoftwareAnim ignored + * @deprecated use generateBindPose(); + */ + @Deprecated + public void generateBindPose(boolean forSoftwareAnim) { + generateBindPose(); + } + + /** + * Generates the {@link Type#BindPosePosition}, {@link Type#BindPoseNormal}, + * and {@link Type#BindPoseTangent} + * buffers for this mesh by duplicating them based on the position and normal + * buffers already set on the mesh. + * This method does nothing if the mesh has no bone weight or index + * buffers. + */ + public void generateBindPose() { + VertexBuffer pos = getBuffer(Type.Position); + if (pos == null || getBuffer(Type.BoneIndex) == null) { + // ignore, this mesh doesn't have positional data + // or it doesn't have bone-vertex assignments, so it's not animated + return; + } + + VertexBuffer bindPos = new VertexBuffer(Type.BindPosePosition); + bindPos.setupData(Usage.CpuOnly, + pos.getNumComponents(), + pos.getFormat(), + BufferUtils.clone(pos.getData())); + setBuffer(bindPos); + + // XXX: note that this method also sets stream mode + // so that animation is faster. this is not needed for hardware skinning + pos.setUsage(Usage.Stream); + + VertexBuffer norm = getBuffer(Type.Normal); + if (norm != null) { + VertexBuffer bindNorm = new VertexBuffer(Type.BindPoseNormal); + bindNorm.setupData(Usage.CpuOnly, + norm.getNumComponents(), + norm.getFormat(), + BufferUtils.clone(norm.getData())); + setBuffer(bindNorm); + norm.setUsage(Usage.Stream); + } + + VertexBuffer tangents = getBuffer(Type.Tangent); + if (tangents != null) { + VertexBuffer bindTangents = new VertexBuffer(Type.BindPoseTangent); + bindTangents.setupData(Usage.CpuOnly, + tangents.getNumComponents(), + tangents.getFormat(), + BufferUtils.clone(tangents.getData())); + setBuffer(bindTangents); + tangents.setUsage(Usage.Stream); + }// else hardware setup does nothing, mesh already in bind pose + + } + + /** + * Prepares the mesh for software skinning by converting the bone index + * and weight buffers to heap buffers. + * + * @param forSoftwareAnim Should be true to enable the conversion. + */ + public void prepareForAnim(boolean forSoftwareAnim) { + if (forSoftwareAnim) { + // convert indices to ubytes on the heap + VertexBuffer indices = getBuffer(Type.BoneIndex); + if (!indices.getData().hasArray()) { + if (indices.getFormat() == Format.UnsignedByte) { + ByteBuffer originalIndex = (ByteBuffer) indices.getData(); + ByteBuffer arrayIndex = ByteBuffer.allocate(originalIndex.capacity()); + originalIndex.clear(); + arrayIndex.put(originalIndex); + indices.updateData(arrayIndex); + } else { + //bone indices can be stored in an UnsignedShort buffer + ShortBuffer originalIndex = (ShortBuffer) indices.getData(); + ShortBuffer arrayIndex = ShortBuffer.allocate(originalIndex.capacity()); + originalIndex.clear(); + arrayIndex.put(originalIndex); + indices.updateData(arrayIndex); + } + } + indices.setUsage(Usage.CpuOnly); + + // convert weights on the heap + VertexBuffer weights = getBuffer(Type.BoneWeight); + if (!weights.getData().hasArray()) { + FloatBuffer originalWeight = (FloatBuffer) weights.getData(); + FloatBuffer arrayWeight = FloatBuffer.allocate(originalWeight.capacity()); + originalWeight.clear(); + arrayWeight.put(originalWeight); + weights.updateData(arrayWeight); + } + weights.setUsage(Usage.CpuOnly); + // position, normal, and tangent buffers to be in "Stream" mode + VertexBuffer positions = getBuffer(Type.Position); + VertexBuffer normals = getBuffer(Type.Normal); + VertexBuffer tangents = getBuffer(Type.Tangent); + positions.setUsage(Usage.Stream); + if (normals != null) { + normals.setUsage(Usage.Stream); + } + if (tangents != null) { + tangents.setUsage(Usage.Stream); + } + } else { + //if HWBoneIndex and HWBoneWeight are empty, we setup them as direct + //buffers with software anim buffers data + VertexBuffer indicesHW = getBuffer(Type.HWBoneIndex); + Buffer result; + if (indicesHW.getData() == null) { + VertexBuffer indices = getBuffer(Type.BoneIndex); + if (indices.getFormat() == Format.UnsignedByte) { + ByteBuffer originalIndex = (ByteBuffer) indices.getData(); + ByteBuffer directIndex + = BufferUtils.createByteBuffer(originalIndex.capacity()); + originalIndex.clear(); + directIndex.put(originalIndex); + result = directIndex; + } else { + //bone indices can be stored in an UnsignedShort buffer + ShortBuffer originalIndex = (ShortBuffer) indices.getData(); + ShortBuffer directIndex + = BufferUtils.createShortBuffer(originalIndex.capacity()); + originalIndex.clear(); + directIndex.put(originalIndex); + result = directIndex; + } + indicesHW.setupData(Usage.Static, indices.getNumComponents(), + indices.getFormat(), result); + } + + VertexBuffer weightsHW = getBuffer(Type.HWBoneWeight); + if (weightsHW.getData() == null) { + VertexBuffer weights = getBuffer(Type.BoneWeight); + FloatBuffer originalWeight = (FloatBuffer) weights.getData(); + FloatBuffer directWeight + = BufferUtils.createFloatBuffer(originalWeight.capacity()); + originalWeight.clear(); + directWeight.put(originalWeight); + weightsHW.setupData(Usage.Static, weights.getNumComponents(), + weights.getFormat(), directWeight); + } + + // position, normal, and tangent buffers to be in "Static" mode + VertexBuffer positions = getBuffer(Type.Position); + VertexBuffer normals = getBuffer(Type.Normal); + VertexBuffer tangents = getBuffer(Type.Tangent); + + VertexBuffer positionsBP = getBuffer(Type.BindPosePosition); + VertexBuffer normalsBP = getBuffer(Type.BindPoseNormal); + VertexBuffer tangentsBP = getBuffer(Type.BindPoseTangent); + + positions.setUsage(Usage.Static); + positionsBP.copyElements(0, positions, 0, positionsBP.getNumElements()); + positions.setUpdateNeeded(); + + if (normals != null) { + normals.setUsage(Usage.Static); + normalsBP.copyElements(0, normals, 0, normalsBP.getNumElements()); + normals.setUpdateNeeded(); + } + + if (tangents != null) { + tangents.setUsage(Usage.Static); + tangentsBP.copyElements(0, tangents, 0, tangentsBP.getNumElements()); + tangents.setUpdateNeeded(); + } + } + } + + /** + * Set the LOD (level of detail) index buffers on this mesh. + * + * @param lodLevels The LOD levels to set + */ + public void setLodLevels(VertexBuffer[] lodLevels) { + this.lodLevels = lodLevels; + } + + /** + * @return The number of LOD levels set on this mesh, including the main + * index buffer, returns zero if there are no lod levels. + */ + @Override + public int getNumLodLevels() { + return lodLevels != null ? lodLevels.length : 0; + } + + /** + * Returns the lod level at the given index. + * + * @param lod The lod level index, this does not include + * the main index buffer. + * @return The LOD index buffer at the index + * + * @throws IndexOutOfBoundsException If the index is outside of the + * range [0, {@link #getNumLodLevels()}]. + * + * @see #setLodLevels(com.jme3.scene.VertexBuffer[]) + */ + public VertexBuffer getLodLevel(int lod) { + return lodLevels[lod]; + } + + /** + * Get the element lengths for {@link Mode#Hybrid} mesh mode. + * + * @return element lengths + */ + public int[] getElementLengths() { + return elementLengths; + } + + /** + * Set the element lengths for {@link Mode#Hybrid} mesh mode. + * + * @param elementLengths The element lengths to set + */ + public void setElementLengths(int[] elementLengths) { + this.elementLengths = elementLengths; + } + + /** + * Set the mode start indices for {@link Mode#Hybrid} mesh mode. + * + * @return mode start indices + */ + public int[] getModeStart() { + return modeStart; + } + + /** + * Get the mode start indices for {@link Mode#Hybrid} mesh mode. + * + * @param modeStart the pre-existing array + */ + public void setModeStart(int[] modeStart) { + this.modeStart = modeStart; + } + + /** + * Returns the mesh mode + * + * @return the mesh mode + * + * @see #setMode(GlMesh.Mode) + */ + public Mode getMode() { + return mode; + } + + /** + * Change the Mesh's mode. By default the mode is {@link Mode#Triangles}. + * + * @param mode The new mode to set + * + * @see Mode + */ + public void setMode(Mode mode) { + this.mode = mode; + updateCounts(); + } + + /** + * Returns the maximum number of weights per vertex on this mesh. + * + * @return maximum number of weights per vertex + * + * @see #setMaxNumWeights(int) + */ + public int getMaxNumWeights() { + return maxNumWeights; + } + + /** + * Set the maximum number of weights per vertex on this mesh. + * Only relevant if this mesh has bone index/weight buffers. + * This value should be between 0 and 4. + * + * @param maxNumWeights the desired number (between 0 and 4, inclusive) + */ + public void setMaxNumWeights(int maxNumWeights) { + this.maxNumWeights = maxNumWeights; + } + + /** + * @deprecated Always returns 1.0 since point size is + * determined in the vertex shader. + * + * @return 1.0 + */ + @Deprecated + public float getPointSize() { + return DEFAULT_POINT_SIZE; + } + + /** + * Returns the line width for line meshes. + * + * @return the line width + * @deprecated use {@link Material#getAdditionalRenderState()} + * and {@link RenderState#getLineWidth()} + */ + @Deprecated + public float getLineWidth() { + return lineWidth; + } + + /** + * Specify the line width for meshes of the line modes, such + * as {@link Mode#Lines}. The line width is specified as on-screen pixels, + * the default value is 1.0. + * + * @param lineWidth The line width + * @deprecated use {@link GlMesh#getAdditionalRenderState()} + * and {@link RenderState#setLineWidth(float)} + */ + @Deprecated + public void setLineWidth(float lineWidth) { + if (lineWidth < 1f) { + throw new IllegalArgumentException("lineWidth must be greater than or equal to 1.0"); + } + this.lineWidth = lineWidth; + } + + /** + * Indicates to the GPU that this mesh will not be modified (a hint). + * Sets the usage mode to {@link Usage#Static} + * for all {@link VertexBuffer vertex buffers} on this Mesh. + */ + public void setStatic() { + for (VertexBuffer vb : buffersList.getArray()) { + vb.setUsage(Usage.Static); + } + } + + /** + * Indicates to the GPU that this mesh will be modified occasionally (a hint). + * Sets the usage mode to {@link Usage#Dynamic} + * for all {@link VertexBuffer vertex buffers} on this Mesh. + */ + public void setDynamic() { + for (VertexBuffer vb : buffersList.getArray()) { + vb.setUsage(Usage.Dynamic); + } + } + + /** + * Indicates to the GPU that this mesh will be modified every frame (a hint). + * Sets the usage mode to {@link Usage#Stream} + * for all {@link VertexBuffer vertex buffers} on this Mesh. + */ + public void setStreamed() { + for (VertexBuffer vb : buffersList.getArray()) { + vb.setUsage(Usage.Stream); + } + } + + /** + * Interleaves the data in this mesh. This operation cannot be reversed. + * Some GPUs may prefer the data in this format, however it is a good idea + * to avoid using this method as it disables some engine features. + */ + @Deprecated + public void setInterleaved() { + ArrayList vbs = new ArrayList<>(); + vbs.addAll(buffersList); + +// ArrayList vbs = new ArrayList(buffers.values()); + // index buffer not included when interleaving + vbs.remove(getBuffer(Type.Index)); + + int stride = 0; // aka bytes per vertex + for (int i = 0; i < vbs.size(); i++) { + VertexBuffer vb = vbs.get(i); +// if (vb.getFormat() != Format.Float){ +// throw new UnsupportedOperationException("Cannot interleave vertex buffer.\n" + +// "Contains not-float data."); +// } + stride += vb.componentsLength; + vb.getData().clear(); // reset position & limit (used later) + } + + VertexBuffer allData = new VertexBuffer(Type.InterleavedData); + ByteBuffer dataBuf = BufferUtils.createByteBuffer(stride * getVertexCount()); + allData.setupData(Usage.Static, 1, Format.UnsignedByte, dataBuf); + + // adding buffer directly so that no update counts is forced + buffers.put(Type.InterleavedData.ordinal(), allData); + buffersList.add(allData); + + for (int vert = 0; vert < getVertexCount(); vert++) { + for (int i = 0; i < vbs.size(); i++) { + VertexBuffer vb = vbs.get(i); + switch (vb.getFormat()) { + case Float: + FloatBuffer fb = (FloatBuffer) vb.getData(); + for (int comp = 0; comp < vb.components; comp++) { + dataBuf.putFloat(fb.get()); + } + break; + case Byte: + case UnsignedByte: + ByteBuffer bb = (ByteBuffer) vb.getData(); + for (int comp = 0; comp < vb.components; comp++) { + dataBuf.put(bb.get()); + } + break; + case Half: + case Short: + case UnsignedShort: + ShortBuffer sb = (ShortBuffer) vb.getData(); + for (int comp = 0; comp < vb.components; comp++) { + dataBuf.putShort(sb.get()); + } + break; + case Int: + case UnsignedInt: + IntBuffer ib = (IntBuffer) vb.getData(); + for (int comp = 0; comp < vb.components; comp++) { + dataBuf.putInt(ib.get()); + } + break; + case Double: + DoubleBuffer db = (DoubleBuffer) vb.getData(); + for (int comp = 0; comp < vb.components; comp++) { + dataBuf.putDouble(db.get()); + } + break; + } + } + } + + int offset = 0; + for (VertexBuffer vb : vbs) { + vb.setOffset(offset); + vb.setStride(stride); + + vb.updateData(null); + //vb.setupData(vb.usage, vb.components, vb.format, null); + offset += vb.componentsLength; + } + } + + private int computeNumElements(int bufSize) { + switch (mode) { + case Triangles: + return bufSize / 3; + case TriangleFan: + case TriangleStrip: + return bufSize - 2; + case Points: + return bufSize; + case Lines: + return bufSize / 2; + case LineLoop: + return bufSize; + case LineStrip: + return bufSize - 1; + case Patch: + return bufSize / patchVertexCount; + default: + throw new UnsupportedOperationException(); + } + } + + private int computeInstanceCount() { + // Whatever the max of the base instance counts + int max = 0; + for (VertexBuffer vb : buffersList) { + if (vb.getBaseInstanceCount() > max) { + max = vb.getBaseInstanceCount(); + } + } + return max; + } + + /** + * Update the {@link #getVertexCount() vertex} and + * {@link #getTriangleCount() triangle} counts for this mesh + * based on the current data. This method should be called + * after the {@link Buffer#capacity() capacities} of the mesh's + * {@link VertexBuffer vertex buffers} has been altered. + * + * @throws IllegalStateException If this mesh is in + * {@link #setInterleaved() interleaved} format. + */ + public void updateCounts() { + if (getBuffer(Type.InterleavedData) != null) { + throw new IllegalStateException("Should update counts before interleave"); + } + + VertexBuffer pb = getBuffer(Type.Position); + VertexBuffer ib = getBuffer(Type.Index); + if (pb != null) { + vertCount = pb.getData().limit() / pb.getNumComponents(); + } + if (ib != null) { + elementCount = computeNumElements(ib.getData().limit()); + } else { + elementCount = computeNumElements(vertCount); + } + instanceCount = computeInstanceCount(); + } + + /** + * Returns the triangle count for the given LOD level. + * + * @param lod The lod level to look up + * @return The triangle count for that LOD level + */ + public int getTriangleCount(int lod) { + if (lodLevels != null) { + if (lod < 0) { + throw new IllegalArgumentException("LOD level cannot be < 0"); + } + + if (lod >= lodLevels.length) { + throw new IllegalArgumentException("LOD level " + lod + " does not exist!"); + } + + return computeNumElements(lodLevels[lod].getData().limit()); + } else if (lod == 0) { + return elementCount; + } else { + throw new IllegalArgumentException("There are no LOD levels on the mesh!"); + } + } + + /** + * Returns how many triangles or elements are on this Mesh. + * This value is only updated when {@link #updateCounts() } is called. + * If the mesh mode is not a triangle mode, then this returns the + * number of elements/primitives, e.g. how many lines or how many points, + * instead of how many triangles. + * + * @return how many triangles/elements are on this Mesh. + */ + @Override + public int getTriangleCount() { + return elementCount; + } + + @Override + public int collideWith(Collidable other, Geometry geometry, CollisionResults results) { + return 0; + } + + @Override + public void draw(CommandBuffer cmd, Geometry geometry) { + + } + + @Override + public void draw(Renderer renderer, Geometry geometry, int instances, VertexBuffer[] instanceData) { + renderer.renderMesh(this, geometry.getLodLevel(), instances, instanceData); + } + + @Override + public AttributeModifier modifyAttribute(String name) { + return null; + } + + /** + * Returns the number of vertices on this mesh. + * The value is computed based on the position buffer, which + * must be set on all meshes. + * + * @return Number of vertices on the mesh + */ + @Override + public int getVertexCount() { + return vertCount; + } + + /** + * Returns the number of instances this mesh contains. The instance + * count is based on any VertexBuffers with instancing set. + * + * @return the number of instances + */ + public int getInstanceCount() { + return instanceCount; + } + + /** + * Gets the triangle vertex positions at the given triangle index + * and stores them into the v1, v2, v3 arguments. + * + * @param index The index of the triangle. + * Should be between 0 and {@link #getTriangleCount()}. + * + * @param v1 Vector to contain first vertex position + * @param v2 Vector to contain second vertex position + * @param v3 Vector to contain third vertex position + */ + public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3) { + VertexBuffer pb = getBuffer(Type.Position); + IndexBuffer ib = getIndicesAsList(); + if (pb != null && pb.getFormat() == Format.Float && pb.getNumComponents() == 3) { + FloatBuffer fpb = (FloatBuffer) pb.getData(); + + // acquire triangle's vertex indices + int vertIndex = index * 3; + int vert1 = ib.get(vertIndex); + int vert2 = ib.get(vertIndex + 1); + int vert3 = ib.get(vertIndex + 2); + + BufferUtils.populateFromBuffer(v1, fpb, vert1); + BufferUtils.populateFromBuffer(v2, fpb, vert2); + BufferUtils.populateFromBuffer(v3, fpb, vert3); + } else { + throw new UnsupportedOperationException("Position buffer not set or " + + " has incompatible format"); + } + } + + /** + * Gets the triangle vertex positions at the given triangle index + * and stores them into the {@link Triangle} argument. + * Also sets the triangle index to the index argument. + * + * @param index The index of the triangle. + * Should be between 0 and {@link #getTriangleCount()}. + * + * @param tri The triangle to store the positions in + */ + public void getTriangle(int index, Triangle tri) { + getTriangle(index, tri.get1(), tri.get2(), tri.get3()); + tri.setIndex(index); + tri.setCenter(null); // invalidate previously cached centroid, if any + tri.setNormal(null); + } + + /** + * Gets the triangle vertex indices at the given triangle index + * and stores them into the given int array. + * + * @param index The index of the triangle. + * Should be between 0 and {@link #getTriangleCount()}. + * + * @param indices Indices of the triangle's vertices + */ + public void getTriangle(int index, int[] indices) { + IndexBuffer ib = getIndicesAsList(); + + // acquire triangle's vertex indices + int vertIndex = index * 3; + indices[0] = ib.get(vertIndex); + indices[1] = ib.get(vertIndex + 1); + indices[2] = ib.get(vertIndex + 2); + } + + /** + * Returns the mesh's VAO ID. Internal use only. + * + * @return the array ID + */ + public int getId() { + return vertexArrayID; + } + + /** + * Sets the mesh's VAO ID. Internal use only. + * + * @param id the array ID + */ + public void setId(int id) { + if (vertexArrayID != DEFAULT_VERTEX_ARRAY_ID) { + throw new IllegalStateException("ID has already been set."); + } + + vertexArrayID = id; + } + + /** + * Generates a collision tree for the mesh. + * Called automatically by {@link #collideWith(com.jme3.collision.Collidable, + * com.jme3.math.Matrix4f, + * com.jme3.bounding.BoundingVolume, + * com.jme3.collision.CollisionResults) }. + */ + public void createCollisionData() { + throw new UnsupportedOperationException("Collision tree not supported."); +// BIHTree tree = new BIHTree(this); +// tree.construct(); +// collisionTree = tree; + } + + /** + * Clears any previously generated collision data. Use this if + * the mesh has changed in some way that invalidates any previously + * generated BIHTree. + */ + public void clearCollisionData() { + collisionTree = DEFAULT_COLLISION_TREE; + } + + /** + * Handles collision detection, internal use only. + * User code should only use collideWith() on scene + * graph elements such as {@link Spatial}s. + * + * @param other the other Collidable + * @param worldMatrix the world matrix + * @param worldBound the world bound + * @param results storage for the results + * @return the number of collisions detected (≥0) + */ + public int collideWith(Collidable other, + Matrix4f worldMatrix, + BoundingVolume worldBound, + CollisionResults results) { + + switch (mode) { + case Points: + case Lines: + case LineStrip: + case LineLoop: + /* + * Collisions can be detected only with triangles, + * and there are no triangles in this mesh. + */ + return 0; + } + + if (getVertexCount() == 0) { + return 0; + } + + if (collisionTree == null) { + createCollisionData(); + } + + return collisionTree.collideWith(other, worldMatrix, worldBound, results); + } + + /** + * Sets the {@link VertexBuffer} on the mesh. + * This will update the vertex/triangle counts if needed. + * + * @param vb The buffer to set + * @throws IllegalArgumentException If the buffer type is already set + */ + public void setBuffer(VertexBuffer vb) { + if (buffers.containsKey(vb.getBufferType().ordinal())) { + throw new IllegalArgumentException("Buffer type already set: " + vb.getBufferType()); + } + + buffers.put(vb.getBufferType().ordinal(), vb); + buffersList.add(vb); + updateCounts(); + } + + /** + * Unsets the {@link VertexBuffer} set on this mesh + * with the given type. Does nothing if the vertex buffer type is not set + * initially. + * + * @param type The buffer type to remove + */ + public void clearBuffer(VertexBuffer.Type type) { + VertexBuffer vb = buffers.remove(type.ordinal()); + if (vb != null) { + buffersList.remove(vb); + updateCounts(); + } + } + + /** + * Creates a {@link VertexBuffer} for the mesh or modifies + * the existing one per the parameters given. + * + * @param type The type of the buffer + * @param components Number of components + * @param format Data format + * @param buf The buffer data + * + * @throws UnsupportedOperationException If the buffer already set is + * incompatible with the parameters given. + */ + public void setBuffer(Type type, int components, Format format, Buffer buf) { + VertexBuffer vb = buffers.get(type.ordinal()); + if (vb == null) { + vb = new VertexBuffer(type); + vb.setupData(Usage.Dynamic, components, format, buf); + setBuffer(vb); + } else { + if (vb.getNumComponents() != components || vb.getFormat() != format) { + throw new UnsupportedOperationException("The buffer already set " + + "is incompatible with the given parameters"); + } + vb.updateData(buf); + updateCounts(); + } + } + + /** + * Set a floating point {@link VertexBuffer} on the mesh. + * + * @param type The type of {@link VertexBuffer}, + * e.g. {@link Type#Position}, {@link Type#Normal}, etc. + * + * @param components Number of components on the vertex buffer, should + * be between 1 and 4. + * + * @param buf The floating point data to contain + */ + public void setBuffer(Type type, int components, FloatBuffer buf) { + setBuffer(type, components, Format.Float, buf); + } + + public void setBuffer(Type type, int components, float[] buf) { + setBuffer(type, components, BufferUtils.createFloatBuffer(buf)); + } + + public void setBuffer(Type type, int components, IntBuffer buf) { + setBuffer(type, components, Format.UnsignedInt, buf); + } + + public void setBuffer(Type type, int components, int[] buf) { + setBuffer(type, components, BufferUtils.createIntBuffer(buf)); + } + + public void setBuffer(Type type, int components, ShortBuffer buf) { + setBuffer(type, components, Format.UnsignedShort, buf); + } + + public void setBuffer(Type type, int components, byte[] buf) { + setBuffer(type, components, BufferUtils.createByteBuffer(buf)); + } + + public void setBuffer(Type type, int components, ByteBuffer buf) { + setBuffer(type, components, Format.UnsignedByte, buf); + } + + public void setBuffer(Type type, int components, short[] buf) { + setBuffer(type, components, BufferUtils.createShortBuffer(buf)); + } + + /** + * Get the {@link VertexBuffer} stored on this mesh with the given + * type. + * + * @param type The type of VertexBuffer + * @return the VertexBuffer data, or null if not set + */ + public VertexBuffer getBuffer(Type type) { + return buffers.get(type.ordinal()); + } + + /** + * Get the {@link VertexBuffer} data stored on this mesh in float + * format. + * + * @param type The type of VertexBuffer + * @return the VertexBuffer data, or null if not set + */ + public FloatBuffer getFloatBuffer(Type type) { + VertexBuffer vb = getBuffer(type); + if (vb == null) { + return null; + } + + return (FloatBuffer) vb.getData(); + } + + /** + * Get the {@link VertexBuffer} data stored on this mesh in short + * format. + * + * @param type The type of VertexBuffer + * @return the VertexBuffer data, or null if not set + */ + public ShortBuffer getShortBuffer(Type type) { + VertexBuffer vb = getBuffer(type); + if (vb == null) { + return null; + } + + return (ShortBuffer) vb.getData(); + } + + /** + * Acquires an index buffer that will read the vertices on the mesh + * as a list. + * + * @return A virtual or wrapped index buffer to read the data as a list + */ + public IndexBuffer getIndicesAsList() { + if (mode == Mode.Hybrid) { + throw new UnsupportedOperationException("Hybrid mode not supported"); + } + + IndexBuffer ib = getIndexBuffer(); + if (ib != null) { + if (mode.isListMode()) { + // already in list mode + return ib; + } else { + // not in list mode but it does have an index buffer + // wrap it so the data is converted to list format + return new WrappedIndexBuffer(this); + } + } else { + // return a virtual index buffer that will supply + // "fake" indices in list format + return new VirtualIndexBuffer(vertCount, mode); + } + } + + /** + * Get the index buffer for this mesh. + * Will return null if no index buffer is set. + * + * @return The index buffer of this mesh. + * + * @see Type#Index + */ + public IndexBuffer getIndexBuffer() { + VertexBuffer vb = getBuffer(Type.Index); + if (vb == null) { + return null; + } + + return IndexBuffer.wrapIndexBuffer(vb.getData()); + } + + /** + * Extracts the vertex attributes from the given mesh into + * this mesh, by using this mesh's {@link #getIndexBuffer() index buffer} + * to index into the attributes of the other mesh. + * Note that this will also change this mesh's index buffer so that + * the references to the vertex data match the new indices. + * + * @param other The mesh to extract the vertex data from + */ + public void extractVertexData(GlMesh other) { + // Determine the number of unique vertices need to + // be created. Also determine the mappings + // between old indices to new indices (since we avoid duplicating + // vertices, this is a map and not an array). + VertexBuffer oldIdxBuf = getBuffer(Type.Index); + IndexBuffer indexBuf = getIndexBuffer(); + int numIndices = indexBuf.size(); + + IntMap oldIndicesToNewIndices = new IntMap<>(numIndices); + ArrayList newIndicesToOldIndices = new ArrayList<>(); + int newIndex = 0; + + for (int i = 0; i < numIndices; i++) { + int oldIndex = indexBuf.get(i); + + if (!oldIndicesToNewIndices.containsKey(oldIndex)) { + // this vertex has not been added, so allocate a + // new index for it and add it to the map + oldIndicesToNewIndices.put(oldIndex, newIndex); + newIndicesToOldIndices.add(oldIndex); + + // increment to have the next index + newIndex++; + } + } + + // Number of unique verts to be created now available + int newNumVerts = newIndicesToOldIndices.size(); + + if (newIndex != newNumVerts) { + throw new AssertionError(); + } + + // Create the new index buffer. + // Do not overwrite the old one because we might be able to + // convert from int index buffer to short index buffer + IndexBuffer newIndexBuf; + if (newNumVerts >= 65536) { + newIndexBuf = new IndexIntBuffer(BufferUtils.createIntBuffer(numIndices)); + } else { + newIndexBuf = new IndexShortBuffer(BufferUtils.createShortBuffer(numIndices)); + } + + for (int i = 0; i < numIndices; i++) { + // Map the old indices to the new indices + int oldIndex = indexBuf.get(i); + newIndex = oldIndicesToNewIndices.get(oldIndex); + + newIndexBuf.put(i, newIndex); + } + + VertexBuffer newIdxBuf = new VertexBuffer(Type.Index); + newIdxBuf.setupData(oldIdxBuf.getUsage(), + oldIdxBuf.getNumComponents(), + newIndexBuf instanceof IndexIntBuffer ? Format.UnsignedInt : Format.UnsignedShort, + newIndexBuf.getBuffer()); + clearBuffer(Type.Index); + setBuffer(newIdxBuf); + + // Now, create the vertex buffers + SafeArrayList oldVertexData = other.getBufferList(); + for (VertexBuffer oldVb : oldVertexData) { + if (oldVb.getBufferType() == VertexBuffer.Type.Index) { + // ignore the index buffer + continue; + } + + VertexBuffer newVb = new VertexBuffer(oldVb.getBufferType()); + newVb.setNormalized(oldVb.isNormalized()); + //check for data before copying, some buffers are just empty shells + //for caching purpose (HW skinning buffers), and will be filled when + //needed + if (oldVb.getData() != null) { + // Create a new vertex buffer with similar configuration, but + // with the capacity of number of unique vertices + Buffer buffer = VertexBuffer.createBuffer(oldVb.getFormat(), + oldVb.getNumComponents(), newNumVerts); + newVb.setupData(oldVb.getUsage(), oldVb.getNumComponents(), + oldVb.getFormat(), buffer); + + // Copy the vertex data from the old buffer into the new buffer + for (int i = 0; i < newNumVerts; i++) { + int oldIndex = newIndicesToOldIndices.get(i); + + // Copy the vertex attribute from the old index + // to the new index + oldVb.copyElement(oldIndex, newVb, i); + } + } + + // Set the buffer on the mesh + clearBuffer(newVb.getBufferType()); + setBuffer(newVb); + } + + // Copy max weights per vertex as well + setMaxNumWeights(other.getMaxNumWeights()); + + // The data has been copied over, update information + updateCounts(); + updateBound(); + } + + /** + * Scales the texture coordinate buffer on this mesh by the given scale + * factor. + *

+ * Note that values above 1 will cause the + * texture to tile, while values below 1 will cause the texture + * to stretch. + *

+ * + * @param scaleFactor The scale factor to scale by. Every texture + * coordinate is multiplied by this vector to get the result. + * + * @throws IllegalStateException If there's no texture coordinate + * buffer on the mesh + * @throws UnsupportedOperationException If the texture coordinate + * buffer is not in 2D float format. + */ + public void scaleTextureCoordinates(Vector2f scaleFactor) { + VertexBuffer tc = getBuffer(Type.TexCoord); + if (tc == null) { + throw new IllegalStateException("The mesh has no texture coordinates"); + } + + if (tc.getFormat() != VertexBuffer.Format.Float) { + throw new UnsupportedOperationException("Only float texture coord format is supported"); + } + + if (tc.getNumComponents() != 2) { + throw new UnsupportedOperationException("Only 2D texture coords are supported"); + } + + FloatBuffer fb = (FloatBuffer) tc.getData(); + fb.clear(); + for (int i = 0; i < fb.limit() / 2; i++) { + float x = fb.get(); + float y = fb.get(); + fb.position(fb.position() - 2); + x *= scaleFactor.getX(); + y *= scaleFactor.getY(); + fb.put(x).put(y); + } + fb.clear(); + tc.updateData(fb); + } + + /** + * Updates the bounding volume of this mesh. + * The method does nothing if the mesh has no {@link Type#Position} buffer. + * It is expected that the position buffer is a float buffer with 3 components. + */ + @Override + public void updateBound() { + VertexBuffer posBuf = getBuffer(VertexBuffer.Type.Position); + if (meshBound != null && posBuf != null) { + meshBound.computeFromPoints((FloatBuffer) posBuf.getData()); + } + } + + /** + * Returns the {@link BoundingVolume} of this Mesh. + * By default the bounding volume is a {@link BoundingBox}. + * + * @return the bounding volume of this mesh + */ + @Override + public BoundingVolume getBound() { + return meshBound; + } + + /** + * Sets the {@link BoundingVolume} for this Mesh. + * The bounding volume is recomputed by calling {@link #updateBound() }. + * + * @param modelBound The model bound to set + */ + @Override + public void setBound(BoundingVolume modelBound) { + meshBound = modelBound; + } + + /** + * Returns a map of all {@link VertexBuffer vertex buffers} on this Mesh. + * The integer key for the map is the {@link Enum#ordinal() ordinal} + * of the vertex buffer's {@link Type}. + * Note that the returned map is a reference to the map used internally, + * modifying it will cause undefined results. + * + * @return map of vertex buffers on this mesh. + */ + public IntMap getBuffers() { + return buffers; + } + + /** + * Returns a list of all {@link VertexBuffer vertex buffers} on this Mesh. + * Using a list instead an IntMap via the {@link #getBuffers() } method is + * better for iteration as there's no need to create an iterator instance. + * Note that the returned list is a reference to the list used internally, + * modifying it will cause undefined results. + * + * @return list of vertex buffers on this mesh. + */ + public SafeArrayList getBufferList() { + return buffersList; + } + + /** + * Determines if the mesh uses bone animation. + * + * A mesh uses bone animation if it has bone index / weight buffers + * such as {@link Type#BoneIndex} or {@link Type#HWBoneIndex}. + * + * @return true if the mesh uses bone animation, false otherwise + */ + public boolean isAnimated() { + return getBuffer(Type.BoneIndex) != null + || getBuffer(Type.HWBoneIndex) != null; + } + + /** + * @deprecated use isAnimatedByJoint + * @param boneIndex the bone's index in its skeleton + * @return true if animated by that bone, otherwise false + */ + @Deprecated + public boolean isAnimatedByBone(int boneIndex) { + return isAnimatedByJoint(boneIndex); + } + + /** + * Test whether the specified bone animates this mesh. + * + * @param jointIndex the bone's index in its skeleton + * @return true if the specified bone animates this mesh, otherwise false + */ + public boolean isAnimatedByJoint(int jointIndex) { + VertexBuffer biBuf = getBuffer(VertexBuffer.Type.BoneIndex); + VertexBuffer wBuf = getBuffer(VertexBuffer.Type.BoneWeight); + if (biBuf == null || wBuf == null) { + return false; // no bone animation data + } + + IndexBuffer boneIndexBuffer = IndexBuffer.wrapIndexBuffer(biBuf.getData()); + boneIndexBuffer.rewind(); + int numBoneIndices = boneIndexBuffer.remaining(); + assert numBoneIndices % 4 == 0 : numBoneIndices; + int numVertices = boneIndexBuffer.remaining() / 4; + + FloatBuffer weightBuffer = (FloatBuffer) wBuf.getData(); + weightBuffer.rewind(); + int numWeights = weightBuffer.remaining(); + assert numWeights == numVertices * 4 : numWeights; + /* + * Test each vertex to determine whether the bone affects it. + */ + int biByte = jointIndex; + for (int vIndex = 0; vIndex < numVertices; vIndex++) { + for (int wIndex = 0; wIndex < 4; wIndex++) { + int bIndex = boneIndexBuffer.get(); + float weight = weightBuffer.get(); + if (wIndex < maxNumWeights && bIndex == biByte && weight != 0f) { + return true; + } + } + } + return false; + } + + /** + * Sets the count of vertices used for each tessellation patch + * + * @param patchVertexCount the desired count + */ + public void setPatchVertexCount(int patchVertexCount) { + this.patchVertexCount = patchVertexCount; + } + + /** + * Gets the amount of vertices used for each patch; + * + * @return the count (≥0) + */ + public int getPatchVertexCount() { + return patchVertexCount; + } + + public void addMorphTarget(MorphTarget target) { + if (morphTargets == null) { + morphTargets = new SafeArrayList<>(MorphTarget.class); + } + morphTargets.add(target); + } + + /** + * Remove the given MorphTarget from the Mesh + * @param target The MorphTarget to remove + * @return If the MorphTarget was removed + */ + public boolean removeMorphTarget(MorphTarget target) { + return morphTargets != null ? morphTargets.remove(target) : false; + } + + /** + * Remove the MorphTarget from the Mesh at the given index + * @throws IndexOutOfBoundsException if the index outside the number of morph targets + * @param index Index of the MorphTarget to remove + * @return The MorphTarget that was removed + */ + public MorphTarget removeMorphTarget(int index) { + if (morphTargets == null) { + throw new IndexOutOfBoundsException("Index:" + index + ", Size:0"); + } + return morphTargets.remove(index); + } + + /** + * Get the MorphTarget at the given index + * @throws IndexOutOfBoundsException if the index outside the number of morph targets + * @param index The index of the morph target to get + * @return The MorphTarget at the index + */ + public MorphTarget getMorphTarget(int index) { + if (morphTargets == null) { + throw new IndexOutOfBoundsException("Index:" + index + ", Size:0"); + } + return morphTargets.get(index); + } + + public MorphTarget[] getMorphTargets() { + if (morphTargets == null) { + return new MorphTarget[0]; + } else { + return morphTargets.getArray(); + } + } + + /** + * Get the name of all morphs in order. + * Morphs without names will be null + * @return an array + */ + public String[] getMorphTargetNames() { + MorphTarget[] nbMorphTargets = getMorphTargets(); + if (nbMorphTargets.length == 0) { + return new String[0]; + } + String[] targets = new String[nbMorphTargets.length]; + + for (int index = 0; index < nbMorphTargets.length; index++) { + targets[index] = nbMorphTargets[index].getName(); + } + return targets; + } + + public boolean hasMorphTargets() { + return morphTargets != null && !morphTargets.isEmpty(); + } + + /** + * Get the index of the morph that has the given name. + * + * @param morphName The name of the morph to search for + * @return The index of the morph, or -1 if not found. + */ + public int getMorphIndex(String morphName) { + int index = -1; + MorphTarget[] nbMorphTargets = getMorphTargets(); + for (int i = 0; i < nbMorphTargets.length; i++) { + if (nbMorphTargets[i].getName().equals(morphName)) { + index = i; + break; + } + } + return index; + } + + @Override + @SuppressWarnings("unchecked") + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + + out.write(meshBound, "modelBound", null); + out.write(vertCount, "vertCount", DEFAULT_VERT_COUNT); + out.write(elementCount, "elementCount", DEFAULT_ELEMENT_COUNT); + out.write(instanceCount, "instanceCount", DEFAULT_INSTANCE_COUNT); + out.write(maxNumWeights, "max_num_weights", DEFAULT_MAX_NUM_WEIGHTS); + out.write(mode, "mode", Mode.Triangles); + out.write(collisionTree, "collisionTree", DEFAULT_COLLISION_TREE); + out.write(elementLengths, "elementLengths", null); + out.write(modeStart, "modeStart", null); + out.write(pointSize, "pointSize", DEFAULT_POINT_SIZE); + + //Removing HW skinning buffers to not save them + VertexBuffer hwBoneIndex = null; + VertexBuffer hwBoneWeight = null; + hwBoneIndex = getBuffer(Type.HWBoneIndex); + if (hwBoneIndex != null) { + buffers.remove(Type.HWBoneIndex.ordinal()); + } + hwBoneWeight = getBuffer(Type.HWBoneWeight); + if (hwBoneWeight != null) { + buffers.remove(Type.HWBoneWeight.ordinal()); + } + + out.writeIntSavableMap(buffers, "buffers", null); + + //restoring Hw skinning buffers. + if (hwBoneIndex != null) { + buffers.put(hwBoneIndex.getBufferType().ordinal(), hwBoneIndex); + } + if (hwBoneWeight != null) { + buffers.put(hwBoneWeight.getBufferType().ordinal(), hwBoneWeight); + } + + out.write(lodLevels, "lodLevels", null); + if (morphTargets != null) { + out.writeSavableArrayList(new ArrayList(morphTargets), "morphTargets", null); + } + } + + @Override + @SuppressWarnings("unchecked") + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + meshBound = (BoundingVolume) in.readSavable("modelBound", null); + vertCount = in.readInt("vertCount", DEFAULT_VERT_COUNT); + elementCount = in.readInt("elementCount", DEFAULT_ELEMENT_COUNT); + instanceCount = in.readInt("instanceCount", DEFAULT_INSTANCE_COUNT); + maxNumWeights = in.readInt("max_num_weights", DEFAULT_MAX_NUM_WEIGHTS); + mode = in.readEnum("mode", Mode.class, Mode.Triangles); + elementLengths = in.readIntArray("elementLengths", null); + modeStart = in.readIntArray("modeStart", null); + collisionTree = (BIHTree) in.readSavable("collisionTree", DEFAULT_COLLISION_TREE); + elementLengths = in.readIntArray("elementLengths", null); + modeStart = in.readIntArray("modeStart", null); + pointSize = in.readFloat("pointSize", DEFAULT_POINT_SIZE); + +// in.readStringSavableMap("buffers", null); + buffers = (IntMap) in.readIntSavableMap("buffers", null); + for (Entry entry : buffers) { + buffersList.add(entry.getValue()); + } + + //creating hw animation buffers empty so that they are put in the cache + if (isAnimated()) { + VertexBuffer hwBoneIndex = new VertexBuffer(Type.HWBoneIndex); + hwBoneIndex.setUsage(Usage.CpuOnly); + setBuffer(hwBoneIndex); + VertexBuffer hwBoneWeight = new VertexBuffer(Type.HWBoneWeight); + hwBoneWeight.setUsage(Usage.CpuOnly); + setBuffer(hwBoneWeight); + } + + Savable[] lodLevelsSavable = in.readSavableArray("lodLevels", null); + if (lodLevelsSavable != null) { + lodLevels = new VertexBuffer[lodLevelsSavable.length]; + System.arraycopy(lodLevelsSavable, 0, lodLevels, 0, lodLevels.length); + } + + ArrayList l = in.readSavableArrayList("morphTargets", null); + if (l != null) { + morphTargets = new SafeArrayList(MorphTarget.class, l); + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/scene/Mesh.java b/jme3-core/src/main/java/com/jme3/scene/Mesh.java index 2819c2838f..fc653904fb 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Mesh.java +++ b/jme3-core/src/main/java/com/jme3/scene/Mesh.java @@ -31,24 +31,16 @@ */ package com.jme3.scene; -import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingVolume; import com.jme3.collision.Collidable; import com.jme3.collision.CollisionResults; -import com.jme3.collision.bih.BIHTree; import com.jme3.export.*; import com.jme3.material.Material; import com.jme3.material.RenderState; -import com.jme3.math.*; -import com.jme3.scene.VertexBuffer.*; -import com.jme3.scene.mesh.*; -import com.jme3.util.*; -import com.jme3.util.IntMap.Entry; -import com.jme3.util.clone.Cloner; -import com.jme3.util.clone.JmeCloneable; -import java.io.IOException; -import java.nio.*; -import java.util.ArrayList; +import com.jme3.renderer.Renderer; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.mesh.AttributeModifier; +import com.jme3.vulkan.mesh.BuiltInAttribute; /** * Mesh is used to store rendering data. @@ -64,1659 +56,30 @@ * * @author Kirill Vainer */ -public class Mesh implements Savable, Cloneable, JmeCloneable { +public interface Mesh extends Collidable, Savable { - /** - * The mode of the Mesh specifies both the type of primitive represented - * by the mesh and how the data should be interpreted. - */ - public enum Mode { - /** - * A primitive is a single point in space. The size of {@link Mode#Points points} are - * determined via the vertex shader's gl_PointSize output. - */ - Points(true), - /** - * A primitive is a line segment. Every two vertices specify - * a single line. {@link Material#getAdditionalRenderState()} - * and {@link RenderState#setLineWidth(float)} can be used - * to set the width of the lines. - */ - Lines(true), - /** - * A primitive is a line segment. The first two vertices specify - * a single line, while subsequent vertices are combined with the - * previous vertex to make a line. {@link Material#getAdditionalRenderState()} - * and {@link RenderState#setLineWidth(float)} can - * be used to set the width of the lines. - */ - LineStrip(false), - /** - * Identical to {@link #LineStrip} except that at the end - * the last vertex is connected with the first to form a line. - * {@link Material#getAdditionalRenderState()} - * and {@link RenderState#setLineWidth(float)} can be used - * to set the width of the lines. - */ - LineLoop(false), - /** - * A primitive is a triangle. Each 3 vertices specify a single - * triangle. - */ - Triangles(true), - /** - * Similar to {@link #Triangles}, the first 3 vertices - * specify a triangle, while subsequent vertices are combined with - * the previous two to form a triangle. - */ - TriangleStrip(false), - /** - * Similar to {@link #Triangles}, the first 3 vertices - * specify a triangle, each 2 subsequent vertices are combined - * with the very first vertex to make a triangle. - */ - TriangleFan(false), - /** - * A combination of various triangle modes. It is best to avoid - * using this mode as it may not be supported by all renderers. - * The {@link Mesh#setModeStart(int[]) mode start points} and - * {@link Mesh#setElementLengths(int[]) element lengths} must - * be specified for this mode. - */ - Hybrid(false), - /** - * Used for Tessellation only. Requires to set the number of vertices - * for each patch (default is 3 for triangle tessellation) - */ - Patch(true); + void draw(CommandBuffer cmd, Geometry geometry); - private boolean listMode = false; + void draw(Renderer renderer, Geometry geometry, int instances, VertexBuffer[] instanceData); - private Mode(boolean listMode) { - this.listMode = listMode; - } + AttributeModifier modifyAttribute(String name); - /** - * Returns true if the specified mode is a list mode (meaning - * ,it specifies the indices as a linear list and not some special - * format). - * Will return true for the types {@link #Points}, {@link #Lines} and - * {@link #Triangles}. - * - * @return true if the mode is a list type mode - */ - public boolean isListMode() { - return listMode; - } - } - - /** - * Default Variables - */ - private static final int DEFAULT_VERTEX_ARRAY_ID = -1; - private static final CollisionData DEFAULT_COLLISION_TREE = null; - - private static final float DEFAULT_POINT_SIZE = 1.0f; - private static final float DEFAULT_LINE_WIDTH = 1.0f; - - private static final int DEFAULT_VERT_COUNT = -1; - private static final int DEFAULT_ELEMENT_COUNT = -1; - private static final int DEFAULT_INSTANCE_COUNT = -1; - private static final int DEFAULT_PATCH_VERTEX_COUNT = 3; - private static final int DEFAULT_MAX_NUM_WEIGHTS = -1; - - /** - * The bounding volume that contains the mesh entirely. - * By default a BoundingBox (AABB). - */ - private BoundingVolume meshBound = new BoundingBox(); - - private CollisionData collisionTree = DEFAULT_COLLISION_TREE; - - private SafeArrayList buffersList = new SafeArrayList<>(VertexBuffer.class); - private IntMap buffers = new IntMap<>(); - private VertexBuffer[] lodLevels; - - private float pointSize = DEFAULT_POINT_SIZE; - private float lineWidth = DEFAULT_LINE_WIDTH; - - private transient int vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; - - private int vertCount = DEFAULT_VERT_COUNT; - private int elementCount = DEFAULT_ELEMENT_COUNT; - private int instanceCount = DEFAULT_INSTANCE_COUNT; - private int patchVertexCount = DEFAULT_PATCH_VERTEX_COUNT; //only used for tessellation - private int maxNumWeights = DEFAULT_MAX_NUM_WEIGHTS; // only if using skeletal animation - - private int[] elementLengths; - private int[] modeStart; - - private Mode mode = Mode.Triangles; - - private SafeArrayList morphTargets; - - /** - * Creates a new mesh with no {@link VertexBuffer vertex buffers}. - */ - public Mesh() { - } - - /** - * Create a shallow clone of this Mesh. The {@link VertexBuffer vertex - * buffers} are shared between this and the clone mesh, the rest - * of the data is cloned. - * - * @return A shallow clone of the mesh - */ - @Override - public Mesh clone() { - try { - Mesh clone = (Mesh) super.clone(); - clone.meshBound = meshBound.clone(); - clone.collisionTree = collisionTree != null ? collisionTree : null; - clone.buffers = buffers.clone(); - clone.buffersList = new SafeArrayList<>(VertexBuffer.class, buffersList); - clone.vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; - if (elementLengths != null) { - clone.elementLengths = elementLengths.clone(); - } - if (modeStart != null) { - clone.modeStart = modeStart.clone(); - } - return clone; - } catch (CloneNotSupportedException ex) { - throw new AssertionError(); - } - } - - /** - * Creates a deep clone of this mesh. - * The {@link VertexBuffer vertex buffers} and the data inside them - * is cloned. - * - * @return a deep clone of this mesh. - */ - public Mesh deepClone() { - try { - Mesh clone = (Mesh) super.clone(); - clone.meshBound = meshBound != null ? meshBound.clone() : null; - - // TODO: Collision tree cloning - //clone.collisionTree = collisionTree != null ? collisionTree : null; - clone.collisionTree = DEFAULT_COLLISION_TREE; // it will get re-generated in any case - - clone.buffers = new IntMap<>(); - clone.buffersList = new SafeArrayList<>(VertexBuffer.class); - for (VertexBuffer vb : buffersList.getArray()) { - VertexBuffer bufClone = vb.clone(); - clone.buffers.put(vb.getBufferType().ordinal(), bufClone); - clone.buffersList.add(bufClone); - } - - clone.vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; - clone.vertCount = vertCount; - clone.elementCount = elementCount; - clone.instanceCount = instanceCount; - - // although this could change - // if the bone weight/index buffers are modified - clone.maxNumWeights = maxNumWeights; - - clone.elementLengths = elementLengths != null ? elementLengths.clone() : null; - clone.modeStart = modeStart != null ? modeStart.clone() : null; - return clone; - } catch (CloneNotSupportedException ex) { - throw new AssertionError(); - } - } - - /** - * Clone the mesh for animation use. - * This creates a shallow clone of the mesh, sharing most - * of the {@link VertexBuffer vertex buffer} data, however the - * {@link Type#Position}, {@link Type#Normal}, and {@link Type#Tangent} buffers - * are deeply cloned. - * - * @return A clone of the mesh for animation use. - */ - public Mesh cloneForAnim() { - Mesh clone = clone(); - if (getBuffer(Type.BindPosePosition) != null) { - VertexBuffer oldPos = getBuffer(Type.Position); - - // NOTE: creates deep clone - VertexBuffer newPos = oldPos.clone(); - clone.clearBuffer(Type.Position); - clone.setBuffer(newPos); - - if (getBuffer(Type.BindPoseNormal) != null) { - VertexBuffer oldNorm = getBuffer(Type.Normal); - VertexBuffer newNorm = oldNorm.clone(); - clone.clearBuffer(Type.Normal); - clone.setBuffer(newNorm); - - if (getBuffer(Type.BindPoseTangent) != null) { - VertexBuffer oldTang = getBuffer(Type.Tangent); - VertexBuffer newTang = oldTang.clone(); - clone.clearBuffer(Type.Tangent); - clone.setBuffer(newTang); - } - } - } - return clone; - } - - /** - * Called internally by com.jme3.util.clone.Cloner. Do not call directly. - */ - @Override - public Mesh jmeClone() { - try { - Mesh clone = (Mesh) super.clone(); - clone.vertexArrayID = DEFAULT_VERTEX_ARRAY_ID; - return clone; - } catch (CloneNotSupportedException ex) { - throw new AssertionError(); - } - } - - /** - * Called internally by com.jme3.util.clone.Cloner. Do not call directly. - */ - @Override - public void cloneFields(Cloner cloner, Object original) { - // Probably could clone this now but it will get regenerated anyway. - this.collisionTree = DEFAULT_COLLISION_TREE; - - this.meshBound = cloner.clone(meshBound); - this.buffersList = cloner.clone(buffersList); - this.buffers = cloner.clone(buffers); - this.lodLevels = cloner.clone(lodLevels); - this.elementLengths = cloner.clone(elementLengths); - this.modeStart = cloner.clone(modeStart); - } - - /** - * @param forSoftwareAnim ignored - * @deprecated use generateBindPose(); - */ - @Deprecated - public void generateBindPose(boolean forSoftwareAnim) { - generateBindPose(); - } - - /** - * Generates the {@link Type#BindPosePosition}, {@link Type#BindPoseNormal}, - * and {@link Type#BindPoseTangent} - * buffers for this mesh by duplicating them based on the position and normal - * buffers already set on the mesh. - * This method does nothing if the mesh has no bone weight or index - * buffers. - */ - public void generateBindPose() { - VertexBuffer pos = getBuffer(Type.Position); - if (pos == null || getBuffer(Type.BoneIndex) == null) { - // ignore, this mesh doesn't have positional data - // or it doesn't have bone-vertex assignments, so it's not animated - return; - } - - VertexBuffer bindPos = new VertexBuffer(Type.BindPosePosition); - bindPos.setupData(Usage.CpuOnly, - pos.getNumComponents(), - pos.getFormat(), - BufferUtils.clone(pos.getData())); - setBuffer(bindPos); - - // XXX: note that this method also sets stream mode - // so that animation is faster. this is not needed for hardware skinning - pos.setUsage(Usage.Stream); - - VertexBuffer norm = getBuffer(Type.Normal); - if (norm != null) { - VertexBuffer bindNorm = new VertexBuffer(Type.BindPoseNormal); - bindNorm.setupData(Usage.CpuOnly, - norm.getNumComponents(), - norm.getFormat(), - BufferUtils.clone(norm.getData())); - setBuffer(bindNorm); - norm.setUsage(Usage.Stream); - } - - VertexBuffer tangents = getBuffer(Type.Tangent); - if (tangents != null) { - VertexBuffer bindTangents = new VertexBuffer(Type.BindPoseTangent); - bindTangents.setupData(Usage.CpuOnly, - tangents.getNumComponents(), - tangents.getFormat(), - BufferUtils.clone(tangents.getData())); - setBuffer(bindTangents); - tangents.setUsage(Usage.Stream); - }// else hardware setup does nothing, mesh already in bind pose - - } - - /** - * Prepares the mesh for software skinning by converting the bone index - * and weight buffers to heap buffers. - * - * @param forSoftwareAnim Should be true to enable the conversion. - */ - public void prepareForAnim(boolean forSoftwareAnim) { - if (forSoftwareAnim) { - // convert indices to ubytes on the heap - VertexBuffer indices = getBuffer(Type.BoneIndex); - if (!indices.getData().hasArray()) { - if (indices.getFormat() == Format.UnsignedByte) { - ByteBuffer originalIndex = (ByteBuffer) indices.getData(); - ByteBuffer arrayIndex = ByteBuffer.allocate(originalIndex.capacity()); - originalIndex.clear(); - arrayIndex.put(originalIndex); - indices.updateData(arrayIndex); - } else { - //bone indices can be stored in an UnsignedShort buffer - ShortBuffer originalIndex = (ShortBuffer) indices.getData(); - ShortBuffer arrayIndex = ShortBuffer.allocate(originalIndex.capacity()); - originalIndex.clear(); - arrayIndex.put(originalIndex); - indices.updateData(arrayIndex); - } - } - indices.setUsage(Usage.CpuOnly); - - // convert weights on the heap - VertexBuffer weights = getBuffer(Type.BoneWeight); - if (!weights.getData().hasArray()) { - FloatBuffer originalWeight = (FloatBuffer) weights.getData(); - FloatBuffer arrayWeight = FloatBuffer.allocate(originalWeight.capacity()); - originalWeight.clear(); - arrayWeight.put(originalWeight); - weights.updateData(arrayWeight); - } - weights.setUsage(Usage.CpuOnly); - // position, normal, and tangent buffers to be in "Stream" mode - VertexBuffer positions = getBuffer(Type.Position); - VertexBuffer normals = getBuffer(Type.Normal); - VertexBuffer tangents = getBuffer(Type.Tangent); - positions.setUsage(Usage.Stream); - if (normals != null) { - normals.setUsage(Usage.Stream); - } - if (tangents != null) { - tangents.setUsage(Usage.Stream); - } - } else { - //if HWBoneIndex and HWBoneWeight are empty, we setup them as direct - //buffers with software anim buffers data - VertexBuffer indicesHW = getBuffer(Type.HWBoneIndex); - Buffer result; - if (indicesHW.getData() == null) { - VertexBuffer indices = getBuffer(Type.BoneIndex); - if (indices.getFormat() == Format.UnsignedByte) { - ByteBuffer originalIndex = (ByteBuffer) indices.getData(); - ByteBuffer directIndex - = BufferUtils.createByteBuffer(originalIndex.capacity()); - originalIndex.clear(); - directIndex.put(originalIndex); - result = directIndex; - } else { - //bone indices can be stored in an UnsignedShort buffer - ShortBuffer originalIndex = (ShortBuffer) indices.getData(); - ShortBuffer directIndex - = BufferUtils.createShortBuffer(originalIndex.capacity()); - originalIndex.clear(); - directIndex.put(originalIndex); - result = directIndex; - } - indicesHW.setupData(Usage.Static, indices.getNumComponents(), - indices.getFormat(), result); - } - - VertexBuffer weightsHW = getBuffer(Type.HWBoneWeight); - if (weightsHW.getData() == null) { - VertexBuffer weights = getBuffer(Type.BoneWeight); - FloatBuffer originalWeight = (FloatBuffer) weights.getData(); - FloatBuffer directWeight - = BufferUtils.createFloatBuffer(originalWeight.capacity()); - originalWeight.clear(); - directWeight.put(originalWeight); - weightsHW.setupData(Usage.Static, weights.getNumComponents(), - weights.getFormat(), directWeight); - } - - // position, normal, and tangent buffers to be in "Static" mode - VertexBuffer positions = getBuffer(Type.Position); - VertexBuffer normals = getBuffer(Type.Normal); - VertexBuffer tangents = getBuffer(Type.Tangent); - - VertexBuffer positionsBP = getBuffer(Type.BindPosePosition); - VertexBuffer normalsBP = getBuffer(Type.BindPoseNormal); - VertexBuffer tangentsBP = getBuffer(Type.BindPoseTangent); + int getVertexCount(); - positions.setUsage(Usage.Static); - positionsBP.copyElements(0, positions, 0, positionsBP.getNumElements()); - positions.setUpdateNeeded(); + int getTriangleCount(); - if (normals != null) { - normals.setUsage(Usage.Static); - normalsBP.copyElements(0, normals, 0, normalsBP.getNumElements()); - normals.setUpdateNeeded(); - } + int collideWith(Collidable other, Geometry geometry, CollisionResults results); - if (tangents != null) { - tangents.setUsage(Usage.Static); - tangentsBP.copyElements(0, tangents, 0, tangentsBP.getNumElements()); - tangents.setUpdateNeeded(); - } - } - } - - /** - * Set the LOD (level of detail) index buffers on this mesh. - * - * @param lodLevels The LOD levels to set - */ - public void setLodLevels(VertexBuffer[] lodLevels) { - this.lodLevels = lodLevels; - } - - /** - * @return The number of LOD levels set on this mesh, including the main - * index buffer, returns zero if there are no lod levels. - */ - public int getNumLodLevels() { - return lodLevels != null ? lodLevels.length : 0; - } - - /** - * Returns the lod level at the given index. - * - * @param lod The lod level index, this does not include - * the main index buffer. - * @return The LOD index buffer at the index - * - * @throws IndexOutOfBoundsException If the index is outside of the - * range [0, {@link #getNumLodLevels()}]. - * - * @see #setLodLevels(com.jme3.scene.VertexBuffer[]) - */ - public VertexBuffer getLodLevel(int lod) { - return lodLevels[lod]; - } + void updateBound(); - /** - * Get the element lengths for {@link Mode#Hybrid} mesh mode. - * - * @return element lengths - */ - public int[] getElementLengths() { - return elementLengths; - } + void setBound(BoundingVolume volume); - /** - * Set the element lengths for {@link Mode#Hybrid} mesh mode. - * - * @param elementLengths The element lengths to set - */ - public void setElementLengths(int[] elementLengths) { - this.elementLengths = elementLengths; - } - - /** - * Set the mode start indices for {@link Mode#Hybrid} mesh mode. - * - * @return mode start indices - */ - public int[] getModeStart() { - return modeStart; - } - - /** - * Get the mode start indices for {@link Mode#Hybrid} mesh mode. - * - * @param modeStart the pre-existing array - */ - public void setModeStart(int[] modeStart) { - this.modeStart = modeStart; - } - - /** - * Returns the mesh mode - * - * @return the mesh mode - * - * @see #setMode(com.jme3.scene.Mesh.Mode) - */ - public Mode getMode() { - return mode; - } + BoundingVolume getBound(); - /** - * Change the Mesh's mode. By default the mode is {@link Mode#Triangles}. - * - * @param mode The new mode to set - * - * @see Mode - */ - public void setMode(Mode mode) { - this.mode = mode; - updateCounts(); - } - - /** - * Returns the maximum number of weights per vertex on this mesh. - * - * @return maximum number of weights per vertex - * - * @see #setMaxNumWeights(int) - */ - public int getMaxNumWeights() { - return maxNumWeights; - } - - /** - * Set the maximum number of weights per vertex on this mesh. - * Only relevant if this mesh has bone index/weight buffers. - * This value should be between 0 and 4. - * - * @param maxNumWeights the desired number (between 0 and 4, inclusive) - */ - public void setMaxNumWeights(int maxNumWeights) { - this.maxNumWeights = maxNumWeights; - } - - /** - * @deprecated Always returns 1.0 since point size is - * determined in the vertex shader. - * - * @return 1.0 - */ - @Deprecated - public float getPointSize() { - return DEFAULT_POINT_SIZE; - } - - /** - * Returns the line width for line meshes. - * - * @return the line width - * @deprecated use {@link Material#getAdditionalRenderState()} - * and {@link RenderState#getLineWidth()} - */ - @Deprecated - public float getLineWidth() { - return lineWidth; - } - - /** - * Specify the line width for meshes of the line modes, such - * as {@link Mode#Lines}. The line width is specified as on-screen pixels, - * the default value is 1.0. - * - * @param lineWidth The line width - * @deprecated use {@link Material#getAdditionalRenderState()} - * and {@link RenderState#setLineWidth(float)} - */ - @Deprecated - public void setLineWidth(float lineWidth) { - if (lineWidth < 1f) { - throw new IllegalArgumentException("lineWidth must be greater than or equal to 1.0"); - } - this.lineWidth = lineWidth; - } - - /** - * Indicates to the GPU that this mesh will not be modified (a hint). - * Sets the usage mode to {@link Usage#Static} - * for all {@link VertexBuffer vertex buffers} on this Mesh. - */ - public void setStatic() { - for (VertexBuffer vb : buffersList.getArray()) { - vb.setUsage(Usage.Static); - } - } - - /** - * Indicates to the GPU that this mesh will be modified occasionally (a hint). - * Sets the usage mode to {@link Usage#Dynamic} - * for all {@link VertexBuffer vertex buffers} on this Mesh. - */ - public void setDynamic() { - for (VertexBuffer vb : buffersList.getArray()) { - vb.setUsage(Usage.Dynamic); - } - } - - /** - * Indicates to the GPU that this mesh will be modified every frame (a hint). - * Sets the usage mode to {@link Usage#Stream} - * for all {@link VertexBuffer vertex buffers} on this Mesh. - */ - public void setStreamed() { - for (VertexBuffer vb : buffersList.getArray()) { - vb.setUsage(Usage.Stream); - } - } - - /** - * Interleaves the data in this mesh. This operation cannot be reversed. - * Some GPUs may prefer the data in this format, however it is a good idea - * to avoid using this method as it disables some engine features. - */ - @Deprecated - public void setInterleaved() { - ArrayList vbs = new ArrayList<>(); - vbs.addAll(buffersList); - -// ArrayList vbs = new ArrayList(buffers.values()); - // index buffer not included when interleaving - vbs.remove(getBuffer(Type.Index)); - - int stride = 0; // aka bytes per vertex - for (int i = 0; i < vbs.size(); i++) { - VertexBuffer vb = vbs.get(i); -// if (vb.getFormat() != Format.Float){ -// throw new UnsupportedOperationException("Cannot interleave vertex buffer.\n" + -// "Contains not-float data."); -// } - stride += vb.componentsLength; - vb.getData().clear(); // reset position & limit (used later) - } - - VertexBuffer allData = new VertexBuffer(Type.InterleavedData); - ByteBuffer dataBuf = BufferUtils.createByteBuffer(stride * getVertexCount()); - allData.setupData(Usage.Static, 1, Format.UnsignedByte, dataBuf); - - // adding buffer directly so that no update counts is forced - buffers.put(Type.InterleavedData.ordinal(), allData); - buffersList.add(allData); - - for (int vert = 0; vert < getVertexCount(); vert++) { - for (int i = 0; i < vbs.size(); i++) { - VertexBuffer vb = vbs.get(i); - switch (vb.getFormat()) { - case Float: - FloatBuffer fb = (FloatBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++) { - dataBuf.putFloat(fb.get()); - } - break; - case Byte: - case UnsignedByte: - ByteBuffer bb = (ByteBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++) { - dataBuf.put(bb.get()); - } - break; - case Half: - case Short: - case UnsignedShort: - ShortBuffer sb = (ShortBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++) { - dataBuf.putShort(sb.get()); - } - break; - case Int: - case UnsignedInt: - IntBuffer ib = (IntBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++) { - dataBuf.putInt(ib.get()); - } - break; - case Double: - DoubleBuffer db = (DoubleBuffer) vb.getData(); - for (int comp = 0; comp < vb.components; comp++) { - dataBuf.putDouble(db.get()); - } - break; - } - } - } - - int offset = 0; - for (VertexBuffer vb : vbs) { - vb.setOffset(offset); - vb.setStride(stride); - - vb.updateData(null); - //vb.setupData(vb.usage, vb.components, vb.format, null); - offset += vb.componentsLength; - } - } - - private int computeNumElements(int bufSize) { - switch (mode) { - case Triangles: - return bufSize / 3; - case TriangleFan: - case TriangleStrip: - return bufSize - 2; - case Points: - return bufSize; - case Lines: - return bufSize / 2; - case LineLoop: - return bufSize; - case LineStrip: - return bufSize - 1; - case Patch: - return bufSize / patchVertexCount; - default: - throw new UnsupportedOperationException(); - } - } - - private int computeInstanceCount() { - // Whatever the max of the base instance counts - int max = 0; - for (VertexBuffer vb : buffersList) { - if (vb.getBaseInstanceCount() > max) { - max = vb.getBaseInstanceCount(); - } - } - return max; - } - - /** - * Update the {@link #getVertexCount() vertex} and - * {@link #getTriangleCount() triangle} counts for this mesh - * based on the current data. This method should be called - * after the {@link Buffer#capacity() capacities} of the mesh's - * {@link VertexBuffer vertex buffers} has been altered. - * - * @throws IllegalStateException If this mesh is in - * {@link #setInterleaved() interleaved} format. - */ - public void updateCounts() { - if (getBuffer(Type.InterleavedData) != null) { - throw new IllegalStateException("Should update counts before interleave"); - } - - VertexBuffer pb = getBuffer(Type.Position); - VertexBuffer ib = getBuffer(Type.Index); - if (pb != null) { - vertCount = pb.getData().limit() / pb.getNumComponents(); - } - if (ib != null) { - elementCount = computeNumElements(ib.getData().limit()); - } else { - elementCount = computeNumElements(vertCount); - } - instanceCount = computeInstanceCount(); - } - - /** - * Returns the triangle count for the given LOD level. - * - * @param lod The lod level to look up - * @return The triangle count for that LOD level - */ - public int getTriangleCount(int lod) { - if (lodLevels != null) { - if (lod < 0) { - throw new IllegalArgumentException("LOD level cannot be < 0"); - } - - if (lod >= lodLevels.length) { - throw new IllegalArgumentException("LOD level " + lod + " does not exist!"); - } - - return computeNumElements(lodLevels[lod].getData().limit()); - } else if (lod == 0) { - return elementCount; - } else { - throw new IllegalArgumentException("There are no LOD levels on the mesh!"); - } - } - - /** - * Returns how many triangles or elements are on this Mesh. - * This value is only updated when {@link #updateCounts() } is called. - * If the mesh mode is not a triangle mode, then this returns the - * number of elements/primitives, e.g. how many lines or how many points, - * instead of how many triangles. - * - * @return how many triangles/elements are on this Mesh. - */ - public int getTriangleCount() { - return elementCount; - } - - /** - * Returns the number of vertices on this mesh. - * The value is computed based on the position buffer, which - * must be set on all meshes. - * - * @return Number of vertices on the mesh - */ - public int getVertexCount() { - return vertCount; - } - - /** - * Returns the number of instances this mesh contains. The instance - * count is based on any VertexBuffers with instancing set. - * - * @return the number of instances - */ - public int getInstanceCount() { - return instanceCount; - } - - /** - * Gets the triangle vertex positions at the given triangle index - * and stores them into the v1, v2, v3 arguments. - * - * @param index The index of the triangle. - * Should be between 0 and {@link #getTriangleCount()}. - * - * @param v1 Vector to contain first vertex position - * @param v2 Vector to contain second vertex position - * @param v3 Vector to contain third vertex position - */ - public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3) { - VertexBuffer pb = getBuffer(Type.Position); - IndexBuffer ib = getIndicesAsList(); - if (pb != null && pb.getFormat() == Format.Float && pb.getNumComponents() == 3) { - FloatBuffer fpb = (FloatBuffer) pb.getData(); - - // acquire triangle's vertex indices - int vertIndex = index * 3; - int vert1 = ib.get(vertIndex); - int vert2 = ib.get(vertIndex + 1); - int vert3 = ib.get(vertIndex + 2); - - BufferUtils.populateFromBuffer(v1, fpb, vert1); - BufferUtils.populateFromBuffer(v2, fpb, vert2); - BufferUtils.populateFromBuffer(v3, fpb, vert3); - } else { - throw new UnsupportedOperationException("Position buffer not set or " - + " has incompatible format"); - } - } - - /** - * Gets the triangle vertex positions at the given triangle index - * and stores them into the {@link Triangle} argument. - * Also sets the triangle index to the index argument. - * - * @param index The index of the triangle. - * Should be between 0 and {@link #getTriangleCount()}. - * - * @param tri The triangle to store the positions in - */ - public void getTriangle(int index, Triangle tri) { - getTriangle(index, tri.get1(), tri.get2(), tri.get3()); - tri.setIndex(index); - tri.setCenter(null); // invalidate previously cached centroid, if any - tri.setNormal(null); - } - - /** - * Gets the triangle vertex indices at the given triangle index - * and stores them into the given int array. - * - * @param index The index of the triangle. - * Should be between 0 and {@link #getTriangleCount()}. - * - * @param indices Indices of the triangle's vertices - */ - public void getTriangle(int index, int[] indices) { - IndexBuffer ib = getIndicesAsList(); - - // acquire triangle's vertex indices - int vertIndex = index * 3; - indices[0] = ib.get(vertIndex); - indices[1] = ib.get(vertIndex + 1); - indices[2] = ib.get(vertIndex + 2); - } - - /** - * Returns the mesh's VAO ID. Internal use only. - * - * @return the array ID - */ - public int getId() { - return vertexArrayID; - } - - /** - * Sets the mesh's VAO ID. Internal use only. - * - * @param id the array ID - */ - public void setId(int id) { - if (vertexArrayID != DEFAULT_VERTEX_ARRAY_ID) { - throw new IllegalStateException("ID has already been set."); - } - - vertexArrayID = id; - } - - /** - * Generates a collision tree for the mesh. - * Called automatically by {@link #collideWith(com.jme3.collision.Collidable, - * com.jme3.math.Matrix4f, - * com.jme3.bounding.BoundingVolume, - * com.jme3.collision.CollisionResults) }. - */ - public void createCollisionData() { - BIHTree tree = new BIHTree(this); - tree.construct(); - collisionTree = tree; - } + int getNumLodLevels(); - /** - * Clears any previously generated collision data. Use this if - * the mesh has changed in some way that invalidates any previously - * generated BIHTree. - */ - public void clearCollisionData() { - collisionTree = DEFAULT_COLLISION_TREE; + default AttributeModifier modifyAttribute(BuiltInAttribute name) { + return modifyAttribute(name.getName()); } - /** - * Handles collision detection, internal use only. - * User code should only use collideWith() on scene - * graph elements such as {@link Spatial}s. - * - * @param other the other Collidable - * @param worldMatrix the world matrix - * @param worldBound the world bound - * @param results storage for the results - * @return the number of collisions detected (≥0) - */ - public int collideWith(Collidable other, - Matrix4f worldMatrix, - BoundingVolume worldBound, - CollisionResults results) { - - switch (mode) { - case Points: - case Lines: - case LineStrip: - case LineLoop: - /* - * Collisions can be detected only with triangles, - * and there are no triangles in this mesh. - */ - return 0; - } - - if (getVertexCount() == 0) { - return 0; - } - - if (collisionTree == null) { - createCollisionData(); - } - - return collisionTree.collideWith(other, worldMatrix, worldBound, results); - } - - /** - * Sets the {@link VertexBuffer} on the mesh. - * This will update the vertex/triangle counts if needed. - * - * @param vb The buffer to set - * @throws IllegalArgumentException If the buffer type is already set - */ - public void setBuffer(VertexBuffer vb) { - if (buffers.containsKey(vb.getBufferType().ordinal())) { - throw new IllegalArgumentException("Buffer type already set: " + vb.getBufferType()); - } - - buffers.put(vb.getBufferType().ordinal(), vb); - buffersList.add(vb); - updateCounts(); - } - - /** - * Unsets the {@link VertexBuffer} set on this mesh - * with the given type. Does nothing if the vertex buffer type is not set - * initially. - * - * @param type The buffer type to remove - */ - public void clearBuffer(VertexBuffer.Type type) { - VertexBuffer vb = buffers.remove(type.ordinal()); - if (vb != null) { - buffersList.remove(vb); - updateCounts(); - } - } - - /** - * Creates a {@link VertexBuffer} for the mesh or modifies - * the existing one per the parameters given. - * - * @param type The type of the buffer - * @param components Number of components - * @param format Data format - * @param buf The buffer data - * - * @throws UnsupportedOperationException If the buffer already set is - * incompatible with the parameters given. - */ - public void setBuffer(Type type, int components, Format format, Buffer buf) { - VertexBuffer vb = buffers.get(type.ordinal()); - if (vb == null) { - vb = new VertexBuffer(type); - vb.setupData(Usage.Dynamic, components, format, buf); - setBuffer(vb); - } else { - if (vb.getNumComponents() != components || vb.getFormat() != format) { - throw new UnsupportedOperationException("The buffer already set " - + "is incompatible with the given parameters"); - } - vb.updateData(buf); - updateCounts(); - } - } - - /** - * Set a floating point {@link VertexBuffer} on the mesh. - * - * @param type The type of {@link VertexBuffer}, - * e.g. {@link Type#Position}, {@link Type#Normal}, etc. - * - * @param components Number of components on the vertex buffer, should - * be between 1 and 4. - * - * @param buf The floating point data to contain - */ - public void setBuffer(Type type, int components, FloatBuffer buf) { - setBuffer(type, components, Format.Float, buf); - } - - public void setBuffer(Type type, int components, float[] buf) { - setBuffer(type, components, BufferUtils.createFloatBuffer(buf)); - } - - public void setBuffer(Type type, int components, IntBuffer buf) { - setBuffer(type, components, Format.UnsignedInt, buf); - } - - public void setBuffer(Type type, int components, int[] buf) { - setBuffer(type, components, BufferUtils.createIntBuffer(buf)); - } - - public void setBuffer(Type type, int components, ShortBuffer buf) { - setBuffer(type, components, Format.UnsignedShort, buf); - } - - public void setBuffer(Type type, int components, byte[] buf) { - setBuffer(type, components, BufferUtils.createByteBuffer(buf)); - } - - public void setBuffer(Type type, int components, ByteBuffer buf) { - setBuffer(type, components, Format.UnsignedByte, buf); - } - - public void setBuffer(Type type, int components, short[] buf) { - setBuffer(type, components, BufferUtils.createShortBuffer(buf)); - } - - /** - * Get the {@link VertexBuffer} stored on this mesh with the given - * type. - * - * @param type The type of VertexBuffer - * @return the VertexBuffer data, or null if not set - */ - public VertexBuffer getBuffer(Type type) { - return buffers.get(type.ordinal()); - } - - /** - * Get the {@link VertexBuffer} data stored on this mesh in float - * format. - * - * @param type The type of VertexBuffer - * @return the VertexBuffer data, or null if not set - */ - public FloatBuffer getFloatBuffer(Type type) { - VertexBuffer vb = getBuffer(type); - if (vb == null) { - return null; - } - - return (FloatBuffer) vb.getData(); - } - - /** - * Get the {@link VertexBuffer} data stored on this mesh in short - * format. - * - * @param type The type of VertexBuffer - * @return the VertexBuffer data, or null if not set - */ - public ShortBuffer getShortBuffer(Type type) { - VertexBuffer vb = getBuffer(type); - if (vb == null) { - return null; - } - - return (ShortBuffer) vb.getData(); - } - - /** - * Acquires an index buffer that will read the vertices on the mesh - * as a list. - * - * @return A virtual or wrapped index buffer to read the data as a list - */ - public IndexBuffer getIndicesAsList() { - if (mode == Mode.Hybrid) { - throw new UnsupportedOperationException("Hybrid mode not supported"); - } - - IndexBuffer ib = getIndexBuffer(); - if (ib != null) { - if (mode.isListMode()) { - // already in list mode - return ib; - } else { - // not in list mode but it does have an index buffer - // wrap it so the data is converted to list format - return new WrappedIndexBuffer(this); - } - } else { - // return a virtual index buffer that will supply - // "fake" indices in list format - return new VirtualIndexBuffer(vertCount, mode); - } - } - - /** - * Get the index buffer for this mesh. - * Will return null if no index buffer is set. - * - * @return The index buffer of this mesh. - * - * @see Type#Index - */ - public IndexBuffer getIndexBuffer() { - VertexBuffer vb = getBuffer(Type.Index); - if (vb == null) { - return null; - } - - return IndexBuffer.wrapIndexBuffer(vb.getData()); - } - - /** - * Extracts the vertex attributes from the given mesh into - * this mesh, by using this mesh's {@link #getIndexBuffer() index buffer} - * to index into the attributes of the other mesh. - * Note that this will also change this mesh's index buffer so that - * the references to the vertex data match the new indices. - * - * @param other The mesh to extract the vertex data from - */ - public void extractVertexData(Mesh other) { - // Determine the number of unique vertices need to - // be created. Also determine the mappings - // between old indices to new indices (since we avoid duplicating - // vertices, this is a map and not an array). - VertexBuffer oldIdxBuf = getBuffer(Type.Index); - IndexBuffer indexBuf = getIndexBuffer(); - int numIndices = indexBuf.size(); - - IntMap oldIndicesToNewIndices = new IntMap<>(numIndices); - ArrayList newIndicesToOldIndices = new ArrayList<>(); - int newIndex = 0; - - for (int i = 0; i < numIndices; i++) { - int oldIndex = indexBuf.get(i); - - if (!oldIndicesToNewIndices.containsKey(oldIndex)) { - // this vertex has not been added, so allocate a - // new index for it and add it to the map - oldIndicesToNewIndices.put(oldIndex, newIndex); - newIndicesToOldIndices.add(oldIndex); - - // increment to have the next index - newIndex++; - } - } - - // Number of unique verts to be created now available - int newNumVerts = newIndicesToOldIndices.size(); - - if (newIndex != newNumVerts) { - throw new AssertionError(); - } - - // Create the new index buffer. - // Do not overwrite the old one because we might be able to - // convert from int index buffer to short index buffer - IndexBuffer newIndexBuf; - if (newNumVerts >= 65536) { - newIndexBuf = new IndexIntBuffer(BufferUtils.createIntBuffer(numIndices)); - } else { - newIndexBuf = new IndexShortBuffer(BufferUtils.createShortBuffer(numIndices)); - } - - for (int i = 0; i < numIndices; i++) { - // Map the old indices to the new indices - int oldIndex = indexBuf.get(i); - newIndex = oldIndicesToNewIndices.get(oldIndex); - - newIndexBuf.put(i, newIndex); - } - - VertexBuffer newIdxBuf = new VertexBuffer(Type.Index); - newIdxBuf.setupData(oldIdxBuf.getUsage(), - oldIdxBuf.getNumComponents(), - newIndexBuf instanceof IndexIntBuffer ? Format.UnsignedInt : Format.UnsignedShort, - newIndexBuf.getBuffer()); - clearBuffer(Type.Index); - setBuffer(newIdxBuf); - - // Now, create the vertex buffers - SafeArrayList oldVertexData = other.getBufferList(); - for (VertexBuffer oldVb : oldVertexData) { - if (oldVb.getBufferType() == VertexBuffer.Type.Index) { - // ignore the index buffer - continue; - } - - VertexBuffer newVb = new VertexBuffer(oldVb.getBufferType()); - newVb.setNormalized(oldVb.isNormalized()); - //check for data before copying, some buffers are just empty shells - //for caching purpose (HW skinning buffers), and will be filled when - //needed - if (oldVb.getData() != null) { - // Create a new vertex buffer with similar configuration, but - // with the capacity of number of unique vertices - Buffer buffer = VertexBuffer.createBuffer(oldVb.getFormat(), - oldVb.getNumComponents(), newNumVerts); - newVb.setupData(oldVb.getUsage(), oldVb.getNumComponents(), - oldVb.getFormat(), buffer); - - // Copy the vertex data from the old buffer into the new buffer - for (int i = 0; i < newNumVerts; i++) { - int oldIndex = newIndicesToOldIndices.get(i); - - // Copy the vertex attribute from the old index - // to the new index - oldVb.copyElement(oldIndex, newVb, i); - } - } - - // Set the buffer on the mesh - clearBuffer(newVb.getBufferType()); - setBuffer(newVb); - } - - // Copy max weights per vertex as well - setMaxNumWeights(other.getMaxNumWeights()); - - // The data has been copied over, update information - updateCounts(); - updateBound(); - } - - /** - * Scales the texture coordinate buffer on this mesh by the given scale - * factor. - *

- * Note that values above 1 will cause the - * texture to tile, while values below 1 will cause the texture - * to stretch. - *

- * - * @param scaleFactor The scale factor to scale by. Every texture - * coordinate is multiplied by this vector to get the result. - * - * @throws IllegalStateException If there's no texture coordinate - * buffer on the mesh - * @throws UnsupportedOperationException If the texture coordinate - * buffer is not in 2D float format. - */ - public void scaleTextureCoordinates(Vector2f scaleFactor) { - VertexBuffer tc = getBuffer(Type.TexCoord); - if (tc == null) { - throw new IllegalStateException("The mesh has no texture coordinates"); - } - - if (tc.getFormat() != VertexBuffer.Format.Float) { - throw new UnsupportedOperationException("Only float texture coord format is supported"); - } - - if (tc.getNumComponents() != 2) { - throw new UnsupportedOperationException("Only 2D texture coords are supported"); - } - - FloatBuffer fb = (FloatBuffer) tc.getData(); - fb.clear(); - for (int i = 0; i < fb.limit() / 2; i++) { - float x = fb.get(); - float y = fb.get(); - fb.position(fb.position() - 2); - x *= scaleFactor.getX(); - y *= scaleFactor.getY(); - fb.put(x).put(y); - } - fb.clear(); - tc.updateData(fb); - } - - /** - * Updates the bounding volume of this mesh. - * The method does nothing if the mesh has no {@link Type#Position} buffer. - * It is expected that the position buffer is a float buffer with 3 components. - */ - public void updateBound() { - VertexBuffer posBuf = getBuffer(VertexBuffer.Type.Position); - if (meshBound != null && posBuf != null) { - meshBound.computeFromPoints((FloatBuffer) posBuf.getData()); - } - } - - /** - * Returns the {@link BoundingVolume} of this Mesh. - * By default the bounding volume is a {@link BoundingBox}. - * - * @return the bounding volume of this mesh - */ - public BoundingVolume getBound() { - return meshBound; - } - - /** - * Sets the {@link BoundingVolume} for this Mesh. - * The bounding volume is recomputed by calling {@link #updateBound() }. - * - * @param modelBound The model bound to set - */ - public void setBound(BoundingVolume modelBound) { - meshBound = modelBound; - } - - /** - * Returns a map of all {@link VertexBuffer vertex buffers} on this Mesh. - * The integer key for the map is the {@link Enum#ordinal() ordinal} - * of the vertex buffer's {@link Type}. - * Note that the returned map is a reference to the map used internally, - * modifying it will cause undefined results. - * - * @return map of vertex buffers on this mesh. - */ - public IntMap getBuffers() { - return buffers; - } - - /** - * Returns a list of all {@link VertexBuffer vertex buffers} on this Mesh. - * Using a list instead an IntMap via the {@link #getBuffers() } method is - * better for iteration as there's no need to create an iterator instance. - * Note that the returned list is a reference to the list used internally, - * modifying it will cause undefined results. - * - * @return list of vertex buffers on this mesh. - */ - public SafeArrayList getBufferList() { - return buffersList; - } - - /** - * Determines if the mesh uses bone animation. - * - * A mesh uses bone animation if it has bone index / weight buffers - * such as {@link Type#BoneIndex} or {@link Type#HWBoneIndex}. - * - * @return true if the mesh uses bone animation, false otherwise - */ - public boolean isAnimated() { - return getBuffer(Type.BoneIndex) != null - || getBuffer(Type.HWBoneIndex) != null; - } - - /** - * @deprecated use isAnimatedByJoint - * @param boneIndex the bone's index in its skeleton - * @return true if animated by that bone, otherwise false - */ - @Deprecated - public boolean isAnimatedByBone(int boneIndex) { - return isAnimatedByJoint(boneIndex); - } - - /** - * Test whether the specified bone animates this mesh. - * - * @param jointIndex the bone's index in its skeleton - * @return true if the specified bone animates this mesh, otherwise false - */ - public boolean isAnimatedByJoint(int jointIndex) { - VertexBuffer biBuf = getBuffer(VertexBuffer.Type.BoneIndex); - VertexBuffer wBuf = getBuffer(VertexBuffer.Type.BoneWeight); - if (biBuf == null || wBuf == null) { - return false; // no bone animation data - } - - IndexBuffer boneIndexBuffer = IndexBuffer.wrapIndexBuffer(biBuf.getData()); - boneIndexBuffer.rewind(); - int numBoneIndices = boneIndexBuffer.remaining(); - assert numBoneIndices % 4 == 0 : numBoneIndices; - int numVertices = boneIndexBuffer.remaining() / 4; - - FloatBuffer weightBuffer = (FloatBuffer) wBuf.getData(); - weightBuffer.rewind(); - int numWeights = weightBuffer.remaining(); - assert numWeights == numVertices * 4 : numWeights; - /* - * Test each vertex to determine whether the bone affects it. - */ - int biByte = jointIndex; - for (int vIndex = 0; vIndex < numVertices; vIndex++) { - for (int wIndex = 0; wIndex < 4; wIndex++) { - int bIndex = boneIndexBuffer.get(); - float weight = weightBuffer.get(); - if (wIndex < maxNumWeights && bIndex == biByte && weight != 0f) { - return true; - } - } - } - return false; - } - - /** - * Sets the count of vertices used for each tessellation patch - * - * @param patchVertexCount the desired count - */ - public void setPatchVertexCount(int patchVertexCount) { - this.patchVertexCount = patchVertexCount; - } - - /** - * Gets the amount of vertices used for each patch; - * - * @return the count (≥0) - */ - public int getPatchVertexCount() { - return patchVertexCount; - } - - public void addMorphTarget(MorphTarget target) { - if (morphTargets == null) { - morphTargets = new SafeArrayList<>(MorphTarget.class); - } - morphTargets.add(target); - } - - /** - * Remove the given MorphTarget from the Mesh - * @param target The MorphTarget to remove - * @return If the MorphTarget was removed - */ - public boolean removeMorphTarget(MorphTarget target) { - return morphTargets != null ? morphTargets.remove(target) : false; - } - - /** - * Remove the MorphTarget from the Mesh at the given index - * @throws IndexOutOfBoundsException if the index outside the number of morph targets - * @param index Index of the MorphTarget to remove - * @return The MorphTarget that was removed - */ - public MorphTarget removeMorphTarget(int index) { - if (morphTargets == null) { - throw new IndexOutOfBoundsException("Index:" + index + ", Size:0"); - } - return morphTargets.remove(index); - } - - /** - * Get the MorphTarget at the given index - * @throws IndexOutOfBoundsException if the index outside the number of morph targets - * @param index The index of the morph target to get - * @return The MorphTarget at the index - */ - public MorphTarget getMorphTarget(int index) { - if (morphTargets == null) { - throw new IndexOutOfBoundsException("Index:" + index + ", Size:0"); - } - return morphTargets.get(index); - } - - public MorphTarget[] getMorphTargets() { - if (morphTargets == null) { - return new MorphTarget[0]; - } else { - return morphTargets.getArray(); - } - } - - /** - * Get the name of all morphs in order. - * Morphs without names will be null - * @return an array - */ - public String[] getMorphTargetNames() { - MorphTarget[] nbMorphTargets = getMorphTargets(); - if (nbMorphTargets.length == 0) { - return new String[0]; - } - String[] targets = new String[nbMorphTargets.length]; - - for (int index = 0; index < nbMorphTargets.length; index++) { - targets[index] = nbMorphTargets[index].getName(); - } - return targets; - } - - public boolean hasMorphTargets() { - return morphTargets != null && !morphTargets.isEmpty(); - } - - /** - * Get the index of the morph that has the given name. - * - * @param morphName The name of the morph to search for - * @return The index of the morph, or -1 if not found. - */ - public int getMorphIndex(String morphName) { - int index = -1; - MorphTarget[] nbMorphTargets = getMorphTargets(); - for (int i = 0; i < nbMorphTargets.length; i++) { - if (nbMorphTargets[i].getName().equals(morphName)) { - index = i; - break; - } - } - return index; - } - - @Override - @SuppressWarnings("unchecked") - public void write(JmeExporter ex) throws IOException { - OutputCapsule out = ex.getCapsule(this); - - out.write(meshBound, "modelBound", null); - out.write(vertCount, "vertCount", DEFAULT_VERT_COUNT); - out.write(elementCount, "elementCount", DEFAULT_ELEMENT_COUNT); - out.write(instanceCount, "instanceCount", DEFAULT_INSTANCE_COUNT); - out.write(maxNumWeights, "max_num_weights", DEFAULT_MAX_NUM_WEIGHTS); - out.write(mode, "mode", Mode.Triangles); - out.write(collisionTree, "collisionTree", DEFAULT_COLLISION_TREE); - out.write(elementLengths, "elementLengths", null); - out.write(modeStart, "modeStart", null); - out.write(pointSize, "pointSize", DEFAULT_POINT_SIZE); - - //Removing HW skinning buffers to not save them - VertexBuffer hwBoneIndex = null; - VertexBuffer hwBoneWeight = null; - hwBoneIndex = getBuffer(Type.HWBoneIndex); - if (hwBoneIndex != null) { - buffers.remove(Type.HWBoneIndex.ordinal()); - } - hwBoneWeight = getBuffer(Type.HWBoneWeight); - if (hwBoneWeight != null) { - buffers.remove(Type.HWBoneWeight.ordinal()); - } - - out.writeIntSavableMap(buffers, "buffers", null); - - //restoring Hw skinning buffers. - if (hwBoneIndex != null) { - buffers.put(hwBoneIndex.getBufferType().ordinal(), hwBoneIndex); - } - if (hwBoneWeight != null) { - buffers.put(hwBoneWeight.getBufferType().ordinal(), hwBoneWeight); - } - - out.write(lodLevels, "lodLevels", null); - if (morphTargets != null) { - out.writeSavableArrayList(new ArrayList(morphTargets), "morphTargets", null); - } - } - - @Override - @SuppressWarnings("unchecked") - public void read(JmeImporter im) throws IOException { - InputCapsule in = im.getCapsule(this); - meshBound = (BoundingVolume) in.readSavable("modelBound", null); - vertCount = in.readInt("vertCount", DEFAULT_VERT_COUNT); - elementCount = in.readInt("elementCount", DEFAULT_ELEMENT_COUNT); - instanceCount = in.readInt("instanceCount", DEFAULT_INSTANCE_COUNT); - maxNumWeights = in.readInt("max_num_weights", DEFAULT_MAX_NUM_WEIGHTS); - mode = in.readEnum("mode", Mode.class, Mode.Triangles); - elementLengths = in.readIntArray("elementLengths", null); - modeStart = in.readIntArray("modeStart", null); - collisionTree = (BIHTree) in.readSavable("collisionTree", DEFAULT_COLLISION_TREE); - elementLengths = in.readIntArray("elementLengths", null); - modeStart = in.readIntArray("modeStart", null); - pointSize = in.readFloat("pointSize", DEFAULT_POINT_SIZE); - -// in.readStringSavableMap("buffers", null); - buffers = (IntMap) in.readIntSavableMap("buffers", null); - for (Entry entry : buffers) { - buffersList.add(entry.getValue()); - } - - //creating hw animation buffers empty so that they are put in the cache - if (isAnimated()) { - VertexBuffer hwBoneIndex = new VertexBuffer(Type.HWBoneIndex); - hwBoneIndex.setUsage(Usage.CpuOnly); - setBuffer(hwBoneIndex); - VertexBuffer hwBoneWeight = new VertexBuffer(Type.HWBoneWeight); - hwBoneWeight.setUsage(Usage.CpuOnly); - setBuffer(hwBoneWeight); - } - - Savable[] lodLevelsSavable = in.readSavableArray("lodLevels", null); - if (lodLevelsSavable != null) { - lodLevels = new VertexBuffer[lodLevelsSavable.length]; - System.arraycopy(lodLevelsSavable, 0, lodLevels, 0, lodLevels.length); - } - - ArrayList l = in.readSavableArrayList("morphTargets", null); - if (l != null) { - morphTargets = new SafeArrayList(MorphTarget.class, l); - } - } } diff --git a/jme3-core/src/main/java/com/jme3/scene/Node.java b/jme3-core/src/main/java/com/jme3/scene/Node.java index 0424cea053..12d79e80e2 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Node.java +++ b/jme3-core/src/main/java/com/jme3/scene/Node.java @@ -40,6 +40,8 @@ import com.jme3.material.Material; import com.jme3.util.SafeArrayList; import com.jme3.util.clone.Cloner; +import com.jme3.vulkan.material.NewMaterial; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -813,4 +815,15 @@ public void depthFirstTraversal(SceneGraphVisitor visitor, DFSMode mode) { protected void breadthFirstTraversal(SceneGraphVisitor visitor, Queue queue) { queue.addAll(children); } + + @Override + protected void findNextIteration(GraphIterator iterator) { + int i = iterator.advanceIndex(); + if (i >= children.size()) { + iterator.moveUp(); + } else { + iterator.moveDown(children.get(i)); + } + } + } diff --git a/jme3-core/src/main/java/com/jme3/scene/Spatial.java b/jme3-core/src/main/java/com/jme3/scene/Spatial.java index 2fe1775d3e..c8151e4f91 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java +++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java @@ -54,6 +54,8 @@ import com.jme3.util.clone.Cloner; import com.jme3.util.clone.IdentityCloneFunction; import com.jme3.util.clone.JmeCloneable; +import com.jme3.vulkan.material.NewMaterial; + import java.io.IOException; import java.util.*; import java.util.logging.Logger; @@ -68,7 +70,7 @@ * @author Joshua Slack * @version $Revision: 4075 $, $Data$ */ -public abstract class Spatial implements Savable, Cloneable, Collidable, +public abstract class Spatial implements Iterable, Savable, Cloneable, Collidable, CloneableSmartAsset, JmeCloneable, HasLocalTransform { private static final Logger logger = Logger.getLogger(Spatial.class.getName()); @@ -1874,4 +1876,88 @@ public void breadthFirstTraversal(SceneGraphVisitor visitor) { } protected abstract void breadthFirstTraversal(SceneGraphVisitor visitor, Queue queue); + + protected abstract void findNextIteration(GraphIterator iterator); + + @Override + public GraphIterator iterator() { + return new GraphIterator(this); + } + + public static class GraphIterator implements Iterator { + + private final Stack childIndices = new Stack<>(); + private Spatial current; + private int currentIndex = 0; + private int iteration = -1; + + public GraphIterator(Spatial start) { + current = Objects.requireNonNull(start); + } + + @Override + public boolean hasNext() { + return current != null; + } + + @Override + public Spatial next() { + if (++iteration > 0) { + current.findNextIteration(this); + } + return current; + } + + @Override + public void remove() { + if (current.getParent() != null) { + current.removeFromParent(); + moveUp(); + currentIndex--; + } + } + + protected void moveUp() { + if (!childIndices.isEmpty()) { + current = current.getParent(); + currentIndex = childIndices.pop(); + if (current != null) { + current.findNextIteration(this); + } + } else { + current = null; + } + } + + protected void moveDown(Spatial node) { + if (node.getParent() != current) { + throw new IllegalArgumentException("Next node must be a child of the current node."); + } + current = node; + childIndices.push(currentIndex); + currentIndex = 0; + } + + protected int advanceIndex() { + return currentIndex++; + } + + protected int getCurrentIndex() { + return currentIndex; + } + + public void skipChildren() { + moveUp(); + } + + public int getDepth() { + return childIndices.size(); + } + + public int getIteration() { + return iteration; + } + + } + } diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/Arrow.java b/jme3-core/src/main/java/com/jme3/scene/debug/Arrow.java index 8f46298693..30e8180683 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/Arrow.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/Arrow.java @@ -33,7 +33,7 @@ import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; import java.nio.FloatBuffer; @@ -45,7 +45,7 @@ * * @author Kirill Vainer */ -public class Arrow extends Mesh { +public class Arrow extends GlMesh { private final Quaternion tempQuat = new Quaternion(); private final Vector3f tempVec = new Vector3f(); diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/Grid.java b/jme3-core/src/main/java/com/jme3/scene/debug/Grid.java index d2947e52a9..1135274364 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/Grid.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/Grid.java @@ -31,7 +31,7 @@ */ package com.jme3.scene.debug; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import com.jme3.util.BufferUtils; @@ -43,7 +43,7 @@ * * @author Kirill Vainer */ -public class Grid extends Mesh { +public class Grid extends GlMesh { public Grid() { } diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonInterBoneWire.java b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonInterBoneWire.java index 6db686bed8..5d0635a4fc 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonInterBoneWire.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonInterBoneWire.java @@ -41,7 +41,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; @@ -55,7 +55,7 @@ * * @author Marcin Roguski (Kaelthas) */ -public class SkeletonInterBoneWire extends Mesh { +public class SkeletonInterBoneWire extends GlMesh { private static final int POINT_AMOUNT = 10; /** The amount of connections between bones. */ private int connectionsAmount; diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonPoints.java b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonPoints.java index 878b611673..50489df30e 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonPoints.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonPoints.java @@ -38,7 +38,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; @@ -53,7 +53,7 @@ /** * The class that displays either heads of the bones if no length data is supplied or both heads and tails otherwise. */ -public class SkeletonPoints extends Mesh { +public class SkeletonPoints extends GlMesh { /** The skeleton to be displayed. */ private Skeleton skeleton; /** The map between the bone index and its length. */ diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonWire.java b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonWire.java index afcecce778..caf30968ba 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonWire.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonWire.java @@ -42,7 +42,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; @@ -55,7 +55,7 @@ * The class that displays either wires between the bones' heads if no length data is supplied and * full bones' shapes otherwise. */ -public class SkeletonWire extends Mesh { +public class SkeletonWire extends GlMesh { /** The number of bones' connections. Used in non-length mode. */ private int numConnections; /** The skeleton to be displayed. */ diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java b/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java index 38593898c1..5810278bec 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/WireBox.java @@ -34,7 +34,7 @@ import com.jme3.bounding.BoundingBox; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; @@ -42,7 +42,7 @@ import com.jme3.util.BufferUtils; import java.nio.FloatBuffer; -public class WireBox extends Mesh { +public class WireBox extends GlMesh { public WireBox() { this(1,1,1); diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/WireFrustum.java b/jme3-core/src/main/java/com/jme3/scene/debug/WireFrustum.java index 9a2de74927..b2e8ee743c 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/WireFrustum.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/WireFrustum.java @@ -35,6 +35,7 @@ import com.jme3.renderer.Camera; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Usage; @@ -52,7 +53,7 @@ * and four for the far plane. These points are connected by lines * to form a wireframe cube-like structure. */ -public class WireFrustum extends Mesh { +public class WireFrustum extends GlMesh { /** * For Serialization only. Do not use. diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/WireSphere.java b/jme3-core/src/main/java/com/jme3/scene/debug/WireSphere.java index 72ee624bb0..3aeeceb567 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/WireSphere.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/WireSphere.java @@ -35,7 +35,7 @@ import com.jme3.math.FastMath; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; @@ -45,7 +45,7 @@ import java.nio.FloatBuffer; import java.nio.ShortBuffer; -public class WireSphere extends Mesh { +public class WireSphere extends GlMesh { private static final int samples = 30; private static final int zSamples = 10; diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java index d7973eabc1..0ec2768050 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureDebugger.java @@ -43,7 +43,7 @@ import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.util.List; @@ -126,7 +126,7 @@ public void initialize(AssetManager assetManager, Camera camera) { armatureNode.setCamera(camera); Material matJoints = new Material(assetManager, "Common/MatDefs/Misc/Billboard.j3md"); - Texture t = assetManager.loadTexture("Common/Textures/dot.png"); + GlTexture t = assetManager.loadTexture("Common/Textures/dot.png"); matJoints.setTexture("Texture", t); matJoints.getAdditionalRenderState().setDepthTest(false); matJoints.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureInterJointsWire.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureInterJointsWire.java index 1fe8bdcdc6..c786f9e2a9 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureInterJointsWire.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/ArmatureInterJointsWire.java @@ -34,7 +34,7 @@ import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; @@ -45,7 +45,7 @@ * * @author Marcin Roguski (Kaelthas) */ -public class ArmatureInterJointsWire extends Mesh { +public class ArmatureInterJointsWire extends GlMesh { private final Vector3f tmp = new Vector3f(); diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java b/jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java index 989667eb23..4246e348fe 100644 --- a/jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java +++ b/jme3-core/src/main/java/com/jme3/scene/debug/custom/JointShape.java @@ -32,10 +32,10 @@ package com.jme3.scene.debug.custom; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; -public class JointShape extends Mesh { +public class JointShape extends GlMesh { /** * Serialization only. Do not use. diff --git a/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedGeometry.java b/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedGeometry.java index e0a673838f..c6f6c53827 100644 --- a/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedGeometry.java +++ b/jme3-core/src/main/java/com/jme3/scene/instancing/InstancedGeometry.java @@ -45,6 +45,7 @@ import com.jme3.math.Quaternion; import com.jme3.renderer.Camera; import com.jme3.renderer.Camera.FrustumIntersect; +import com.jme3.renderer.Renderer; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; import com.jme3.scene.VertexBuffer; @@ -54,6 +55,9 @@ import com.jme3.util.BufferUtils; import com.jme3.util.TempVars; import com.jme3.util.clone.Cloner; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.pipelines.Pipeline; + import java.io.IOException; import java.nio.FloatBuffer; import java.util.ArrayList; @@ -114,6 +118,20 @@ public static BiFunction getInstanceCullingFunction() return instanceCullingFunction; } + @Override + public void draw(CommandBuffer cmd, Pipeline pipeline) { + super.draw(cmd, pipeline); + // todo: implement correctly + } + + @Override + public void draw(Renderer renderer) { + int instances = getNumVisibleInstances(); + if (instances > 0) { + mesh.draw(renderer, this, instances, getAllInstanceData()); + } + } + /** * Global user specified per-instance data. * diff --git a/jme3-core/src/main/java/com/jme3/scene/mesh/IndexBuffer.java b/jme3-core/src/main/java/com/jme3/scene/mesh/IndexBuffer.java index 29ff8050c7..6e5d401fd6 100644 --- a/jme3-core/src/main/java/com/jme3/scene/mesh/IndexBuffer.java +++ b/jme3-core/src/main/java/com/jme3/scene/mesh/IndexBuffer.java @@ -36,6 +36,7 @@ import java.nio.IntBuffer; import java.nio.ShortBuffer; +import com.jme3.scene.Mesh; import com.jme3.scene.VertexBuffer.Format; import com.jme3.util.BufferUtils; @@ -170,7 +171,7 @@ public int remaining() { * Returns the format of the data stored in this buffer. * *

This method can be used to set an {@link IndexBuffer} to a - * {@link com.jme3.scene.Mesh Mesh}:

+ * {@link Mesh Mesh}:

*
      * mesh.setBuffer(Type.Index, 3, 
      *     indexBuffer.getFormat(), indexBuffer);
diff --git a/jme3-core/src/main/java/com/jme3/scene/mesh/VirtualIndexBuffer.java b/jme3-core/src/main/java/com/jme3/scene/mesh/VirtualIndexBuffer.java
index c3144e6b97..4c483247eb 100644
--- a/jme3-core/src/main/java/com/jme3/scene/mesh/VirtualIndexBuffer.java
+++ b/jme3-core/src/main/java/com/jme3/scene/mesh/VirtualIndexBuffer.java
@@ -31,23 +31,23 @@
  */
 package com.jme3.scene.mesh;
 
-import com.jme3.scene.Mesh.Mode;
+import com.jme3.scene.GlMesh;
 import com.jme3.scene.VertexBuffer.Format;
 
 import java.nio.Buffer;
 
 /**
  * IndexBuffer implementation that generates vertex indices sequentially
- * based on a specific Mesh {@link Mode}.
+ * based on a specific Mesh {@link GlMesh.Mode}.
  * The generated indices are as if the mesh is in the given mode
  * but contains no index buffer, thus this implementation will
  * return the indices if the index buffer was there and contained sequential
  * triangles.
  * Example:
  * 
    - *
  • {@link Mode#Triangles}: 0, 1, 2 | 3, 4, 5 | 6, 7, 8 | ...
  • - *
  • {@link Mode#TriangleStrip}: 0, 1, 2 | 2, 1, 3 | 2, 3, 4 | ...
  • - *
  • {@link Mode#TriangleFan}: 0, 1, 2 | 0, 2, 3 | 0, 3, 4 | ...
  • + *
  • {@link GlMesh.Mode#Triangles}: 0, 1, 2 | 3, 4, 5 | 6, 7, 8 | ...
  • + *
  • {@link GlMesh.Mode#TriangleStrip}: 0, 1, 2 | 2, 1, 3 | 2, 3, 4 | ...
  • + *
  • {@link GlMesh.Mode#TriangleFan}: 0, 1, 2 | 0, 2, 3 | 0, 3, 4 | ...
  • *
* * @author Kirill Vainer @@ -56,10 +56,10 @@ public class VirtualIndexBuffer extends IndexBuffer { protected int numVerts = 0; protected int numIndices = 0; - protected Mode meshMode; + protected GlMesh.Mode meshMode; protected int position = 0; - public VirtualIndexBuffer(int numVerts, Mode meshMode) { + public VirtualIndexBuffer(int numVerts, GlMesh.Mode meshMode) { this.numVerts = numVerts; this.meshMode = meshMode; switch (meshMode) { @@ -108,13 +108,13 @@ public int remaining() { @Override public int get(int i) { - if (meshMode == Mode.Triangles || meshMode == Mode.Lines || meshMode == Mode.Points) { + if (meshMode == GlMesh.Mode.Triangles || meshMode == GlMesh.Mode.Lines || meshMode == GlMesh.Mode.Points) { return i; - } else if (meshMode == Mode.LineStrip) { + } else if (meshMode == GlMesh.Mode.LineStrip) { return (i + 1) / 2; - } else if (meshMode == Mode.LineLoop) { + } else if (meshMode == GlMesh.Mode.LineLoop) { return (i == (numIndices - 1)) ? 0 : ((i + 1) / 2); - } else if (meshMode == Mode.TriangleStrip) { + } else if (meshMode == GlMesh.Mode.TriangleStrip) { int triIndex = i / 3; int vertIndex = i % 3; boolean isBack = (i / 3) % 2 == 1; @@ -132,7 +132,7 @@ public int get(int i) { throw new AssertionError(); } } - } else if (meshMode == Mode.TriangleFan) { + } else if (meshMode == GlMesh.Mode.TriangleFan) { int vertIndex = i % 3; if (vertIndex == 0) { return 0; diff --git a/jme3-core/src/main/java/com/jme3/scene/mesh/WrappedIndexBuffer.java b/jme3-core/src/main/java/com/jme3/scene/mesh/WrappedIndexBuffer.java index f6c9d4bfea..ac1ee222d3 100644 --- a/jme3-core/src/main/java/com/jme3/scene/mesh/WrappedIndexBuffer.java +++ b/jme3-core/src/main/java/com/jme3/scene/mesh/WrappedIndexBuffer.java @@ -32,7 +32,7 @@ package com.jme3.scene.mesh; import com.jme3.scene.Mesh; -import com.jme3.scene.Mesh.Mode; +import com.jme3.scene.GlMesh.Mode; import com.jme3.scene.VertexBuffer.Type; import java.nio.Buffer; diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/AbstractBox.java b/jme3-core/src/main/java/com/jme3/scene/shape/AbstractBox.java index e096a91a4c..1092512b67 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/AbstractBox.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/AbstractBox.java @@ -33,7 +33,7 @@ import com.jme3.export.*; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import java.io.IOException; @@ -50,7 +50,7 @@ * @author Ian Phillips * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ */ -public abstract class AbstractBox extends Mesh { +public abstract class AbstractBox extends GlMesh { public final Vector3f center = new Vector3f(0f, 0f, 0f); diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/CenterQuad.java b/jme3-core/src/main/java/com/jme3/scene/shape/CenterQuad.java index cfe51dbaff..af5634df22 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/CenterQuad.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/CenterQuad.java @@ -35,7 +35,7 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import java.io.IOException; @@ -51,7 +51,7 @@ * * @author Kirill Vainer */ -public class CenterQuad extends Mesh { +public class CenterQuad extends GlMesh { private float width; private float height; diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Curve.java b/jme3-core/src/main/java/com/jme3/scene/shape/Curve.java index e1b7dd994f..150a1a91e2 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Curve.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Curve.java @@ -34,6 +34,7 @@ import com.jme3.math.Spline; import com.jme3.math.Vector3f; import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import java.util.Iterator; import java.util.List; @@ -47,7 +48,7 @@ * * @author Nehon */ -public class Curve extends Mesh { +public class Curve extends GlMesh { private Spline spline; private Vector3f temp = new Vector3f(); diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java b/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java index 36df9d9892..6b8908ae20 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java @@ -38,7 +38,7 @@ import com.jme3.export.OutputCapsule; import com.jme3.math.FastMath; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import com.jme3.util.BufferUtils; import java.io.IOException; @@ -50,7 +50,7 @@ * @author Mark Powell * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ */ -public class Cylinder extends Mesh { +public class Cylinder extends GlMesh { private int axisSamples; diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java b/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java index 5cfd312f82..3e2c3bd1c5 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Dome.java @@ -38,7 +38,7 @@ import com.jme3.export.OutputCapsule; import com.jme3.math.FastMath; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import com.jme3.util.BufferUtils; import com.jme3.util.TempVars; @@ -53,7 +53,7 @@ * @author Joshua Slack (Original sphere code that was adapted) * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ */ -public class Dome extends Mesh { +public class Dome extends GlMesh { private int planes; private int radialSamples; diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Line.java b/jme3-core/src/main/java/com/jme3/scene/shape/Line.java index c9c5f3c197..465a9a9666 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Line.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Line.java @@ -36,7 +36,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; import java.io.IOException; @@ -47,7 +47,7 @@ * * @author Brent Owens */ -public class Line extends Mesh { +public class Line extends GlMesh { private Vector3f start = new Vector3f(); private Vector3f end = new Vector3f(); diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/PQTorus.java b/jme3-core/src/main/java/com/jme3/scene/shape/PQTorus.java index d301a98675..39243e05b3 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/PQTorus.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/PQTorus.java @@ -38,7 +38,7 @@ import com.jme3.export.OutputCapsule; import com.jme3.math.FastMath; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import static com.jme3.util.BufferUtils.*; import java.io.IOException; @@ -51,7 +51,7 @@ * @author Joshua Slack, Eric Woroshow * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ */ -public class PQTorus extends Mesh { +public class PQTorus extends GlMesh { private float p, q; diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Quad.java b/jme3-core/src/main/java/com/jme3/scene/shape/Quad.java index 07c161c301..be6defcb81 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Quad.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Quad.java @@ -36,7 +36,7 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import java.io.IOException; @@ -48,7 +48,7 @@ * * @author Kirill Vainer */ -public class Quad extends Mesh { +public class Quad extends GlMesh { private float width; private float height; diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/RectangleMesh.java b/jme3-core/src/main/java/com/jme3/scene/shape/RectangleMesh.java index 6f16847390..778b6c6143 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/RectangleMesh.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/RectangleMesh.java @@ -40,7 +40,7 @@ import com.jme3.math.Rectangle; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import com.jme3.util.BufferUtils; import com.jme3.util.clone.Cloner; @@ -71,7 +71,7 @@ * * @author Francivan Bezerra */ -public class RectangleMesh extends Mesh { +public class RectangleMesh extends GlMesh { /** * Used to locate the vertices and calculate a default normal. diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Sphere.java b/jme3-core/src/main/java/com/jme3/scene/shape/Sphere.java index f4b2ba34c6..3356820095 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Sphere.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Sphere.java @@ -38,7 +38,7 @@ import com.jme3.export.OutputCapsule; import com.jme3.math.FastMath; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import com.jme3.util.BufferUtils; import com.jme3.util.TempVars; @@ -53,7 +53,7 @@ * @author Joshua Slack * @version $Revision: 4163 $, $Date: 2009-03-24 21:14:55 -0400 (Tue, 24 Mar 2009) $ */ -public class Sphere extends Mesh { +public class Sphere extends GlMesh { public enum TextureMode { diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Surface.java b/jme3-core/src/main/java/com/jme3/scene/shape/Surface.java index 9beef259e4..f7e64c533d 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Surface.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Surface.java @@ -40,7 +40,7 @@ import com.jme3.math.Spline.SplineType; import com.jme3.math.Vector3f; import com.jme3.math.Vector4f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.util.BufferUtils; import java.io.IOException; @@ -56,7 +56,7 @@ * a) NURBS * @author Marcin Roguski (Kealthas) */ -public class Surface extends Mesh { +public class Surface extends GlMesh { private SplineType type; // the type of the surface private List> controlPoints; // space control points and their weights private List[] knots; // knots of the surface diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Torus.java b/jme3-core/src/main/java/com/jme3/scene/shape/Torus.java index d3e75d6faf..2b445feb4d 100644 --- a/jme3-core/src/main/java/com/jme3/scene/shape/Torus.java +++ b/jme3-core/src/main/java/com/jme3/scene/shape/Torus.java @@ -37,7 +37,7 @@ import com.jme3.export.OutputCapsule; import com.jme3.math.FastMath; import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer.Type; import com.jme3.util.BufferUtils; import java.io.IOException; @@ -52,7 +52,7 @@ * @author Mark Powell * @version $Revision: 4131 $, $Date: 2009-03-19 16:15:28 -0400 (Thu, 19 Mar 2009) $ */ -public class Torus extends Mesh { +public class Torus extends GlMesh { private int circleSamples; diff --git a/jme3-core/src/main/java/com/jme3/shader/Uniform.java b/jme3-core/src/main/java/com/jme3/shader/Uniform.java index ebd42f9605..ff9ef0351c 100644 --- a/jme3-core/src/main/java/com/jme3/shader/Uniform.java +++ b/jme3-core/src/main/java/com/jme3/shader/Uniform.java @@ -31,7 +31,7 @@ */ package com.jme3.shader; -import com.jme3.material.Material.BindUnits; +import com.jme3.material.GlMaterial.BindUnits; import com.jme3.math.*; import com.jme3.util.BufferUtils; import com.jme3.util.TempVars; diff --git a/jme3-core/src/main/java/com/jme3/shader/VarType.java b/jme3-core/src/main/java/com/jme3/shader/VarType.java index ebf7edc64c..4d847358ab 100644 --- a/jme3-core/src/main/java/com/jme3/shader/VarType.java +++ b/jme3-core/src/main/java/com/jme3/shader/VarType.java @@ -38,7 +38,7 @@ import com.jme3.math.Vector3f; import com.jme3.math.Vector4f; import com.jme3.shader.bufferobject.BufferObject; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.Texture3D; import com.jme3.texture.TextureArray; @@ -68,10 +68,10 @@ public enum VarType { Matrix4Array(true, false, "mat4", Matrix4f[].class), TextureBuffer(false, true, "sampler1D|sampler1DShadow"), - Texture2D(false, true, "sampler2D|sampler2DShadow", Texture2D.class, Texture.class), - Texture3D(false, true, "sampler3D", Texture3D.class, Texture.class), - TextureArray(false, true, "sampler2DArray|sampler2DArrayShadow", TextureArray.class, Texture.class), - TextureCubeMap(false, true, "samplerCube", TextureCubeMap.class, Texture.class), + Texture2D(false, true, "sampler2D|sampler2DShadow", Texture2D.class, GlTexture.class), + Texture3D(false, true, "sampler3D", Texture3D.class, GlTexture.class), + TextureArray(false, true, "sampler2DArray|sampler2DArrayShadow", TextureArray.class, GlTexture.class), + TextureCubeMap(false, true, "samplerCube", TextureCubeMap.class, GlTexture.class), Image2D(false, false, true, "image2D", TextureImage.class), Image3D(false, false, true, "image3D", TextureImage.class), diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index 50db5a5a64..88a9fdea42 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -37,7 +37,6 @@ import com.jme3.light.NullLightFilter; import com.jme3.material.Material; import com.jme3.material.RenderState; -import com.jme3.math.ColorRGBA; import com.jme3.math.Matrix4f; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; @@ -55,10 +54,10 @@ import com.jme3.scene.Spatial; import com.jme3.scene.debug.WireFrustum; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; -import com.jme3.texture.Texture.ShadowCompareMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; +import com.jme3.texture.GlTexture.ShadowCompareMode; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.ui.Picture; @@ -301,29 +300,31 @@ public CompareMode getShadowCompareMode() { */ protected Geometry createFrustum(Vector3f[] pts, int i) { WireFrustum frustum = new WireFrustum(pts); - Geometry frustumMdl = new Geometry("f", frustum); + // fixme + Geometry frustumMdl = new Geometry("f"/*, frustum*/); frustumMdl.setCullHint(Spatial.CullHint.Never); frustumMdl.setShadowMode(ShadowMode.Off); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.getAdditionalRenderState().setWireframe(true); - frustumMdl.setMaterial(mat); - switch (i) { - case 0: - frustumMdl.getMaterial().setColor("Color", ColorRGBA.Pink); - break; - case 1: - frustumMdl.getMaterial().setColor("Color", ColorRGBA.Red); - break; - case 2: - frustumMdl.getMaterial().setColor("Color", ColorRGBA.Green); - break; - case 3: - frustumMdl.getMaterial().setColor("Color", ColorRGBA.Blue); - break; - default: - frustumMdl.getMaterial().setColor("Color", ColorRGBA.White); - break; - } + // fixme + //frustumMdl.setMaterial(mat); +// switch (i) { +// case 0: +// frustumMdl.getMaterial().setColor("Color", ColorRGBA.Pink); +// break; +// case 1: +// frustumMdl.getMaterial().setColor("Color", ColorRGBA.Red); +// break; +// case 2: +// frustumMdl.getMaterial().setColor("Color", ColorRGBA.Green); +// break; +// case 3: +// frustumMdl.getMaterial().setColor("Color", ColorRGBA.Blue); +// break; +// default: +// frustumMdl.getMaterial().setColor("Color", ColorRGBA.White); +// break; +// } frustumMdl.updateGeometricState(); return frustumMdl; diff --git a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java index 3f41721b3c..a8d68052f3 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java @@ -48,7 +48,7 @@ import com.jme3.renderer.queue.RenderQueue.ShadowMode; import com.jme3.scene.Spatial; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; diff --git a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java index a0d405000b..95e388c7c0 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java @@ -54,10 +54,10 @@ import com.jme3.scene.Spatial; import com.jme3.scene.debug.WireFrustum; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; -import com.jme3.texture.Texture.ShadowCompareMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; +import com.jme3.texture.GlTexture.ShadowCompareMode; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; import java.util.ArrayList; diff --git a/jme3-core/src/main/java/com/jme3/system/JmeContext.java b/jme3-core/src/main/java/com/jme3/system/JmeContext.java index c2ffe912ef..e162fc399a 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeContext.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeContext.java @@ -44,7 +44,7 @@ public interface JmeContext { /** * The type of context. */ - public enum Type { + enum Type { /** * A display can represent a windowed or a fullscreen-exclusive display. * If windowed, the graphics are rendered to a new on-screen surface @@ -79,6 +79,23 @@ public enum Type { Headless, } + /** + * Enum specifying the backend to use. + */ + enum Backend { + + /** + * Specifies the OpenGL backend. + */ + OpenGL, + + /** + * Specifies the Vulkan backend. + */ + Vulkan; + + } + /** * @return The type of the context. */ diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java index 4a832916c8..e257e9d091 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java @@ -34,6 +34,7 @@ import com.jme3.asset.AssetManager; import com.jme3.audio.AudioRenderer; import com.jme3.input.SoftTextDialogInput; +import com.jme3.texture.GlImage; import java.io.File; import java.io.IOException; @@ -137,7 +138,7 @@ public static SoftTextDialogInput getSoftTextDialogInput() { * * @param outStream The stream where to write the image data. * @param format The format to use, either "png" or "jpg". - * @param imageData The image data in {@link com.jme3.texture.Image.Format#RGBA8} format. + * @param imageData The image data in {@link GlImage.Format#RGBA8} format. * @param width The width of the image. * @param height The height of the image. * @throws IOException If outStream throws an exception while writing. diff --git a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java index 28eb6b5231..38bf8b2982 100644 --- a/jme3-core/src/main/java/com/jme3/system/NullRenderer.java +++ b/jme3-core/src/main/java/com/jme3/system/NullRenderer.java @@ -40,14 +40,14 @@ import com.jme3.renderer.Renderer; import com.jme3.renderer.Statistics; import com.jme3.renderer.TextureUnitException; -import com.jme3.scene.Mesh; +import com.jme3.scene.GlMesh; import com.jme3.scene.VertexBuffer; import com.jme3.shader.Shader; import com.jme3.shader.Shader.ShaderSource; import com.jme3.shader.bufferobject.BufferObject; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.TextureImage; import java.nio.ByteBuffer; @@ -168,7 +168,7 @@ public void deleteFrameBuffer(FrameBuffer fb) { } @Override - public void setTexture(int unit, Texture tex) throws TextureUnitException { + public void setTexture(int unit, GlTexture tex) throws TextureUnitException { // do nothing } @@ -178,7 +178,7 @@ public void setTextureImage(int unit, TextureImage tex) throws TextureUnitExcept } @Override - public void modifyTexture(Texture tex, Image pixels, int x, int y) { + public void modifyTexture(GlTexture tex, GlImage pixels, int x, int y) { } @Override @@ -195,7 +195,7 @@ public void deleteBuffer(BufferObject bo) { } @Override - public void renderMesh(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { + public void renderMesh(GlMesh mesh, int lod, int count, VertexBuffer[] instanceData) { } @Override @@ -207,7 +207,7 @@ public void cleanup() { } @Override - public void deleteImage(Image image) { + public void deleteImage(GlImage image) { } @Override @@ -248,7 +248,7 @@ public boolean isTaskResultAvailable(int taskId) { } @Override - public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { + public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, GlImage.Format format) { } @Override @@ -302,6 +302,7 @@ public FrameBuffer getCurrentFrameBuffer() { return null; } + @Override public void updateShaderStorageBufferObjectData(BufferObject bo) { } diff --git a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java index f3cc721df9..e41d228b70 100644 --- a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java +++ b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java @@ -33,7 +33,7 @@ import com.jme3.renderer.Caps; import com.jme3.renderer.Renderer; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.util.NativeObject; import java.util.ArrayList; @@ -45,7 +45,7 @@ * FrameBuffer, the result can be either a texture or a buffer. *

* A FrameBuffer supports two methods of rendering, - * using a {@link Texture} or using a buffer. + * using a {@link GlTexture} or using a buffer. * When using a texture, the result of the rendering will be rendered * onto the texture, after which the texture can be placed on an object * and rendered as if the texture was uploaded from disk. @@ -94,8 +94,8 @@ public class FrameBuffer extends NativeObject { */ public static class RenderBuffer { - Texture tex; - Image.Format format; + GlTexture tex; + GlImage.Format format; int id = -1; int slot = SLOT_UNDEF; int face = -1; @@ -118,7 +118,7 @@ public Format getFormat() { * @return The texture to render to for this RenderBuffer * or null if content should be rendered into a buffer. */ - public Texture getTexture() { + public GlTexture getTexture() { return tex; } @@ -182,9 +182,9 @@ public int getLayer() { public static class FrameBufferTextureTarget extends RenderBuffer { private FrameBufferTextureTarget(){} - void setTexture(Texture tx){ + void setTexture(GlTexture tx){ this.tex=tx; - this.format=tx.getImage().getFormat(); + this.format=tx.getImage().getGlFormat(); } void setFormat(Format f){ @@ -221,7 +221,7 @@ void setFormat(Format f){ public static class FrameBufferTarget { private FrameBufferTarget(){} - public static FrameBufferTextureTarget newTarget(Texture tx){ + public static FrameBufferTextureTarget newTarget(GlTexture tx){ FrameBufferTextureTarget t=new FrameBufferTextureTarget(); t.setTexture(tx); return t; @@ -241,7 +241,7 @@ public static FrameBufferBufferTarget newTarget(Format format){ * @param face face to add to the color buffer to * @return FrameBufferTexture Target */ - public static FrameBufferTextureTarget newTarget(Texture tx, TextureCubeMap.Face face) { + public static FrameBufferTextureTarget newTarget(GlTexture tx, TextureCubeMap.Face face) { FrameBufferTextureTarget t = new FrameBufferTextureTarget(); t.face = face.ordinal(); t.setTexture(tx); @@ -322,7 +322,7 @@ public void setDepthTarget(FrameBufferBufferTarget depthBuf){ public void setDepthTarget(FrameBufferTextureTarget depthBuf){ checkSetTexture(depthBuf.getTexture(), true); this.depthBuf = depthBuf; - this.depthBuf.slot = depthBuf.getTexture().getImage().getFormat().isDepthStencilFormat() ? SLOT_DEPTH_STENCIL : SLOT_DEPTH; + this.depthBuf.slot = depthBuf.getTexture().getImage().getGlFormat().isDepthStencilFormat() ? SLOT_DEPTH_STENCIL : SLOT_DEPTH; } public int getNumColorTargets(){ @@ -398,7 +398,7 @@ protected FrameBuffer(FrameBuffer src) { * {@link #setDepthTarget(com.jme3.texture.FrameBuffer.FrameBufferBufferTarget)} */ @Deprecated - public void setDepthBuffer(Image.Format format) { + public void setDepthBuffer(GlImage.Format format) { if (id != -1) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } @@ -420,7 +420,7 @@ public void setDepthBuffer(Image.Format format) { * @deprecated Use addColorTarget */ @Deprecated - public void setColorBuffer(Image.Format format) { + public void setColorBuffer(GlImage.Format format) { if (id != -1) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } @@ -437,15 +437,15 @@ public void setColorBuffer(Image.Format format) { colorBufs.add(colorBuf); } - private void checkSetTexture(Texture tex, boolean depth) { - Image img = tex.getImage(); + private void checkSetTexture(GlTexture tex, boolean depth) { + GlImage img = tex.getImage(); if (img == null) { throw new IllegalArgumentException("Texture not initialized with RTT."); } - if (depth && !img.getFormat().isDepthFormat()) { + if (depth && !img.getGlFormat().isDepthFormat()) { throw new IllegalArgumentException("Texture image format must be depth."); - } else if (!depth && img.getFormat().isDepthFormat()) { + } else if (!depth && img.getGlFormat().isDepthFormat()) { throw new IllegalArgumentException("Texture image format must be color/luminance."); } @@ -582,7 +582,7 @@ public void clearColorTargets() { * @deprecated Use addColorTarget */ @Deprecated - public void addColorBuffer(Image.Format format) { + public void addColorBuffer(GlImage.Format format) { if (id != -1) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } @@ -606,7 +606,7 @@ public void addColorBuffer(Image.Format format) { * is rendered to by the shader. * * @param tex The texture to add. - * @see #addColorBuffer(com.jme3.texture.Image.Format) + * @see #addColorBuffer(GlImage.Format) * @deprecated Use addColorTarget */ @Deprecated @@ -615,13 +615,13 @@ public void addColorTexture(Texture2D tex) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } - Image img = tex.getImage(); + GlImage img = tex.getImage(); checkSetTexture(tex, false); RenderBuffer colorBuf = new RenderBuffer(); colorBuf.slot = colorBufs.size(); colorBuf.tex = tex; - colorBuf.format = img.getFormat(); + colorBuf.format = img.getGlFormat(); colorBufs.add(colorBuf); } @@ -643,13 +643,13 @@ public void addColorTexture(TextureArray tex, int layer) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } - Image img = tex.getImage(); + GlImage img = tex.getImage(); checkSetTexture(tex, false); RenderBuffer colorBuf = new RenderBuffer(); colorBuf.slot = colorBufs.size(); colorBuf.tex = tex; - colorBuf.format = img.getFormat(); + colorBuf.format = img.getGlFormat(); colorBuf.layer = layer; colorBufs.add(colorBuf); @@ -672,13 +672,13 @@ public void addColorTexture(TextureCubeMap tex, TextureCubeMap.Face face) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } - Image img = tex.getImage(); + GlImage img = tex.getImage(); checkSetTexture(tex, false); RenderBuffer colorBuf = new RenderBuffer(); colorBuf.slot = colorBufs.size(); colorBuf.tex = tex; - colorBuf.format = img.getFormat(); + colorBuf.format = img.getGlFormat(); colorBuf.face = face.ordinal(); colorBufs.add(colorBuf); @@ -697,13 +697,13 @@ public void setDepthTexture(Texture2D tex) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } - Image img = tex.getImage(); + GlImage img = tex.getImage(); checkSetTexture(tex, true); depthBuf = new RenderBuffer(); - depthBuf.slot = img.getFormat().isDepthStencilFormat() ? SLOT_DEPTH_STENCIL : SLOT_DEPTH; + depthBuf.slot = img.getGlFormat().isDepthStencilFormat() ? SLOT_DEPTH_STENCIL : SLOT_DEPTH; depthBuf.tex = tex; - depthBuf.format = img.getFormat(); + depthBuf.format = img.getGlFormat(); } /** @@ -719,13 +719,13 @@ public void setDepthTexture(TextureArray tex, int layer) { throw new UnsupportedOperationException("FrameBuffer already initialized."); } - Image img = tex.getImage(); + GlImage img = tex.getImage(); checkSetTexture(tex, true); depthBuf = new RenderBuffer(); - depthBuf.slot = img.getFormat().isDepthStencilFormat() ? SLOT_DEPTH_STENCIL : SLOT_DEPTH; + depthBuf.slot = img.getGlFormat().isDepthStencilFormat() ? SLOT_DEPTH_STENCIL : SLOT_DEPTH; depthBuf.tex = tex; - depthBuf.format = img.getFormat(); + depthBuf.format = img.getGlFormat(); depthBuf.layer = layer; } diff --git a/jme3-core/src/main/java/com/jme3/texture/Image.java b/jme3-core/src/main/java/com/jme3/texture/GlImage.java similarity index 88% rename from jme3-core/src/main/java/com/jme3/texture/Image.java rename to jme3-core/src/main/java/com/jme3/texture/GlImage.java index 3159f0856a..3a1d2a11ea 100644 --- a/jme3-core/src/main/java/com/jme3/texture/Image.java +++ b/jme3-core/src/main/java/com/jme3/texture/GlImage.java @@ -1,1308 +1,1311 @@ -/* - * Copyright (c) 2009-2024 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.texture; - -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.FastMath; -import com.jme3.renderer.Caps; -import com.jme3.renderer.Renderer; -import com.jme3.texture.image.ColorSpace; -import com.jme3.texture.image.LastTextureState; -import com.jme3.util.BufferUtils; -import com.jme3.util.NativeObject; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Image defines a data format for a graphical image. The image - * is defined by a format, a height and width, and the image data. The width and - * height must be greater than 0. The data is contained in a byte buffer, and - * should be packed before creation of the image object. - * - * @author Mark Powell - * @author Joshua Slack - * @version $Id: Image.java 4131 2009-03-19 20:15:28Z blaine.dev $ - */ -public class Image extends NativeObject implements Savable /*, Cloneable*/ { - - public enum Format { - /** - * 8-bit alpha - */ - Alpha8(8), - - @Deprecated - Reserved1(0), - - /** - * 8-bit grayscale/luminance. - */ - Luminance8(8), - - @Deprecated - Reserved2(0), - - /** - * half-precision floating-point grayscale/luminance. - * - * Requires {@link Caps#FloatTexture}. - */ - Luminance16F(16,true), - - /** - * single-precision floating-point grayscale/luminance. - * - * Requires {@link Caps#FloatTexture}. - */ - Luminance32F(32,true), - - /** - * 8-bit luminance/grayscale and 8-bit alpha. - */ - Luminance8Alpha8(16), - - @Deprecated - Reserved3(0), - - /** - * half-precision floating-point grayscale/luminance and alpha. - * - * Requires {@link Caps#FloatTexture}. - */ - Luminance16FAlpha16F(32,true), - - @Deprecated - Reserved4(0), - - @Deprecated - Reserved5(0), - - /** - * 8-bit blue, green, and red. - */ - BGR8(24), // BGR and ABGR formats are often used on Windows systems - - /** - * 8-bit red, green, and blue. - */ - RGB8(24), - - @Deprecated - Reserved6(0), - - @Deprecated - Reserved7(0), - - /** - * 5-bit red, 6-bit green, and 5-bit blue. - */ - RGB565(16), - - @Deprecated - Reserved8(0), - - /** - * 5-bit red, green, and blue with 1-bit alpha. - */ - RGB5A1(16), - - /** - * 8-bit red, green, blue, and alpha. - */ - RGBA8(32), - - /** - * 8-bit alpha, blue, green, and red. - */ - ABGR8(32), - - /** - * 8-bit alpha, red, blue and green - */ - ARGB8(32), - - /** - * 8-bit blue, green, red and alpha. - */ - BGRA8(32), - - @Deprecated - Reserved9(0), - - /** - * S3TC compression DXT1. - */ - DXT1(4,false,true, false), - - /** - * S3TC compression DXT1 with 1-bit alpha. - */ - DXT1A(4,false,true, false), - - /** - * S3TC compression DXT3 with 4-bit alpha. - */ - DXT3(8,false,true, false), - - /** - * S3TC compression DXT5 with interpolated 8-bit alpha. - * - */ - DXT5(8,false,true, false), - - RGTC2(8,false,true, false), - - SIGNED_RGTC2(8,false,true, false), - - RGTC1(4,false,true, false), - - SIGNED_RGTC1(4,false,true, false), - - /** - * BPTC compression BC6 signed float RGB - */ - BC6H_SF16(8, false, true, true), - - /** - * BPTC compression BC6 unsigned float RGB - */ - BC6H_UF16(8, false, true, true), - - /** - * BPTC compression BC7 RGBA - */ - BC7_UNORM(8, false, true, false), - - /** - * BPTC compression BC7 SRGB Alpha - */ - BC7_UNORM_SRGB(8, false, true, false), - - /** - * Luminance-Alpha Texture Compression. - * - * @deprecated Not supported by OpenGL 3.0. - */ - @Deprecated - Reserved10(0), - - /** - * Arbitrary depth format. The precision is chosen by the video - * hardware. - */ - Depth(0,true,false,false), - - /** - * 16-bit depth. - */ - Depth16(16,true,false,false), - - /** - * 24-bit depth. - */ - Depth24(24,true,false,false), - - /** - * 32-bit depth. - */ - Depth32(32,true,false,false), - - /** - * single-precision floating point depth. - * - * Requires {@link Caps#FloatDepthBuffer}. - */ - Depth32F(32,true,false,true), - - /** - * Texture data is stored as {@link Format#RGB16F} in system memory, - * but will be converted to {@link Format#RGB111110F} when sent - * to the video hardware. - * - * Requires {@link Caps#FloatTexture} and {@link Caps#PackedFloatTexture}. - */ - RGB16F_to_RGB111110F(48,true), - - /** - * unsigned floating-point red, green and blue that uses 32 bits. - * - * Requires {@link Caps#PackedFloatTexture}. - */ - RGB111110F(32,true), - - /** - * Texture data is stored as {@link Format#RGB16F} in system memory, - * but will be converted to {@link Format#RGB9E5} when sent - * to the video hardware. - * - * Requires {@link Caps#FloatTexture} and {@link Caps#SharedExponentTexture}. - */ - RGB16F_to_RGB9E5(48,true), - - /** - * 9-bit red, green and blue with 5-bit exponent. - * - * Requires {@link Caps#SharedExponentTexture}. - */ - RGB9E5(32,true), - - /** - * half-precision floating point red, green, and blue. - * - * Requires {@link Caps#FloatTexture}. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB16F(48,true), - - /** - * half-precision floating point red, green, blue, and alpha. - * - * Requires {@link Caps#FloatTexture}. - */ - RGBA16F(64,true), - - /** - * single-precision floating point red, green, and blue. - * - * Requires {@link Caps#FloatTexture}. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB32F(96,true), - - /** - * single-precision floating point red, green, blue and alpha. - * - * Requires {@link Caps#FloatTexture}. - */ - RGBA32F(128,true), - - @Deprecated - Reserved11(0), - - /** - * 24-bit depth with 8-bit stencil. - * Check the cap {@link Caps#PackedDepthStencilBuffer}. - */ - Depth24Stencil8(32, true, false, false), - - @Deprecated - Reserved12(0), - - /** - * Ericsson Texture Compression. Typically used on Android. - * - * Requires {@link Caps#TextureCompressionETC1}. - */ - ETC1(4, false, true, false), - - /** - * Ericsson Texture Compression 2. Typically used on Android. - * Same as {@link #ETC1} but with alpha. - * - * Requires {@link Caps#TextureCompressionETC2}. - */ - ETC2(8, false, true, false), - - /** - * Ericsson Texture Compression 2. Typically used on Android. - * Same as {@link #ETC2} but alpha can be either 1 or 0. - * - * Requires {@link Caps#TextureCompressionETC2}. - */ - ETC2_ALPHA1(4, false, true, false), - - - /** - * 8-bit signed int red. - * - * Requires {@link Caps#IntegerTexture}. - */ - R8I(8), - /** - * 8-bit unsigned int red. - * - * Requires {@link Caps#IntegerTexture}. - */ - R8UI(8), - /** - * 16-bit signed int red. - * - * Requires {@link Caps#IntegerTexture}. - */ - R16I(16), - /** - * 16-bit unsigned int red. - * - * Requires {@link Caps#IntegerTexture}. - */ - R16UI(16), - /** - * 32-bit signed int red. - * - * Requires {@link Caps#IntegerTexture}. - */ - R32I(32), - /** - * 32-bit unsigned int red. - * - * Requires {@link Caps#IntegerTexture}. - */ - R32UI(32), - - - /** - * 8-bit signed int red and green. - * - * Requires {@link Caps#IntegerTexture}. - */ - RG8I(16), - /** - * 8-bit unsigned int red and green. - * - * Requires {@link Caps#IntegerTexture}. - */ - RG8UI(16), - /** - * 16-bit signed int red and green. - * - * Requires {@link Caps#IntegerTexture}. - */ - RG16I(32), - /** - * 16-bit unsigned int red and green. - * - * Requires {@link Caps#IntegerTexture}. - */ - RG16UI(32), - /** - * 32-bit signed int red and green. - * - * Requires {@link Caps#IntegerTexture}. - */ - RG32I(64), - /** - * 32-bit unsigned int red and green. - * - * Requires {@link Caps#IntegerTexture}. - */ - RG32UI(64), - - /** - * 8-bit signed int red, green and blue. - * - * Requires {@link Caps#IntegerTexture} to be supported for textures. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB8I(24), - /** - * 8 bit unsigned int red, green and blue. - * - * Requires {@link Caps#IntegerTexture} to be supported for textures. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB8UI(24), - /** - * 16-bit signed int red, green and blue. - * - * Requires {@link Caps#IntegerTexture} to be supported for textures. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB16I(48), - /** - * 16-bit unsigned int red, green and blue. - * - * Requires {@link Caps#IntegerTexture} to be supported for textures. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB16UI(48), - /** - * 32-bit signed int red, green and blue. - * - * Requires {@link Caps#IntegerTexture} to be supported for textures. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB32I(96), - /** - * 32-bit unsigned int red, green and blue. - * - * Requires {@link Caps#IntegerTexture} to be supported for textures. - * May be supported for renderbuffers, but the OpenGL specification does not require it. - */ - RGB32UI(96), - - - /** - * 8-bit signed int red, green, blue and alpha. - * - * Requires {@link Caps#IntegerTexture}. - */ - RGBA8I(32), - /** - * 8-bit unsigned int red, green, blue and alpha. - * - * Requires {@link Caps#IntegerTexture}. - */ - RGBA8UI(32), - /** - * 16-bit signed int red, green, blue and alpha. - * - * Requires {@link Caps#IntegerTexture}. - */ - RGBA16I(64), - /** - * 16-bit unsigned int red, green, blue and alpha. - * - * Requires {@link Caps#IntegerTexture}. - */ - RGBA16UI(64), - /** - * 32-bit signed int red, green, blue and alpha. - * - * Requires {@link Caps#IntegerTexture}. - */ - RGBA32I(128), - /** - * 32-bit unsigned int red, green, blue and alpha. - * - * Requires {@link Caps#IntegerTexture}. - */ - RGBA32UI(128), - - /** - * half-precision floating point red. - * - * Requires {@link Caps#FloatTexture}. - */ - R16F(16,true), - - /** - * single-precision floating point red. - * - * Requires {@link Caps#FloatTexture}. - */ - R32F(32,true), - - /** - * half-precision floating point red and green. - * - * Requires {@link Caps#FloatTexture}. - */ - RG16F(32,true), - - /** - * single-precision floating point red and green. - * - * Requires {@link Caps#FloatTexture}. - */ - RG32F(64,true), - - /** - * 10-bit red, green, and blue with 2-bit alpha. - */ - RGB10A2(32), - ; - - private int bpp; - private boolean isDepth; - private boolean isCompressed; - private boolean isFloatingPoint; - - private Format(int bpp){ - this.bpp = bpp; - } - - private Format(int bpp, boolean isFP){ - this(bpp); - this.isFloatingPoint = isFP; - } - - private Format(int bpp, boolean isDepth, boolean isCompressed, boolean isFP){ - this(bpp, isFP); - this.isDepth = isDepth; - this.isCompressed = isCompressed; - } - - /** - * @return bits per pixel. - */ - public int getBitsPerPixel(){ - return bpp; - } - - /** - * @return True if this format is a depth format, false otherwise. - */ - public boolean isDepthFormat(){ - return isDepth; - } - - /** - * @return True if this format is a depth + stencil (packed) format, false otherwise. - */ - boolean isDepthStencilFormat() { - return this == Depth24Stencil8; - } - - /** - * @return True if this is a compressed image format, false if - * uncompressed. - */ - public boolean isCompressed() { - return isCompressed; - } - - /** - * @return True if this image format is in floating point, - * false if it is an integer format. - */ - public boolean isFloatingPont(){ - return isFloatingPoint; - } - - - - } - - // image attributes - protected Format format; - protected int width, height, depth; - protected int[] mipMapSizes; - protected ArrayList data; - protected int multiSamples = 1; - protected ColorSpace colorSpace = null; -// protected int mipOffset = 0; - - // attributes relating to GL object - protected boolean mipsWereGenerated = false; - protected boolean needGeneratedMips = false; - protected LastTextureState lastTextureState = new LastTextureState(); - - /** - * Internal use only. - * The renderer stores the texture state set from the last texture, - * so it doesn't have to change it unless necessary. - * - * @return The image parameter state. - */ - public LastTextureState getLastTextureState() { - return lastTextureState; - } - - /** - * Internal use only. - * The renderer marks which images have generated mipmaps in VRAM - * and which do not, so it can generate them as needed. - * - * @param generated If mipmaps were generated or not. - */ - public void setMipmapsGenerated(boolean generated) { - this.mipsWereGenerated = generated; - } - - /** - * Internal use only. - * Check if the renderer has generated mipmaps for this image in VRAM - * or not. - * - * @return If mipmaps were generated already. - */ - public boolean isMipmapsGenerated() { - return mipsWereGenerated; - } - - /** - * (Package private) Called by {@link Texture} when - * {@link #isMipmapsGenerated() } is false in order to generate - * mipmaps for this image. - */ - void setNeedGeneratedMipmaps() { - needGeneratedMips = true; - } - - /** - * @return True if the image needs to have mipmaps generated - * for it (as requested by the texture). This stays true even - * after mipmaps have been generated. - */ - public boolean isGeneratedMipmapsRequired() { - return needGeneratedMips; - } - - /** - * Sets the update needed flag, while also checking if mipmaps - * need to be regenerated. - */ - @Override - public void setUpdateNeeded() { - super.setUpdateNeeded(); - if (isGeneratedMipmapsRequired() && !hasMipmaps()) { - // Mipmaps are no longer valid, since the image was changed. - setMipmapsGenerated(false); - } - } - - /** - * Determine if the image is NPOT. - * - * @return if the image is a non-power-of-2 image, e.g. having dimensions - * that are not powers of 2. - */ - public boolean isNPOT() { - return width != 0 && height != 0 - && (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)); - } - - @Override - public void resetObject() { - this.id = -1; - this.mipsWereGenerated = false; - this.lastTextureState.reset(); - setUpdateNeeded(); - } - - @Override - protected void deleteNativeBuffers() { - for (ByteBuffer buf : data) { - BufferUtils.destroyDirectBuffer(buf); - } - } - - @Override - public void deleteObject(Object rendererObject) { - ((Renderer)rendererObject).deleteImage(this); - } - - @Override - public NativeObject createDestructableClone() { - return new Image(id); - } - - @Override - public long getUniqueId() { - return ((long)OBJTYPE_TEXTURE << 32) | (0xffffffffL & (long)id); - } - - /** - * @return A shallow clone of this image. The data is not cloned. - */ - @Override - public Image clone(){ - Image clone = (Image) super.clone(); - clone.mipMapSizes = mipMapSizes != null ? mipMapSizes.clone() : null; - clone.data = data != null ? new ArrayList(data) : null; - clone.lastTextureState = new LastTextureState(); - clone.setUpdateNeeded(); - return clone; - } - - /** - * Constructor instantiates a new Image object. All values - * are undefined. - */ - public Image() { - super(); - data = new ArrayList(1); - } - - protected Image(int id){ - super(id); - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param depth - * the desired image depth - * @param data - * the image data. - * @param mipMapSizes - * the array of mipmap sizes, or null for no mipmaps. - * @param colorSpace - * the colorSpace of the image - */ - public Image(Format format, int width, int height, int depth, ArrayList data, - int[] mipMapSizes, ColorSpace colorSpace) { - - this(); - - if (mipMapSizes != null) { - if (mipMapSizes.length <= 1) { - mipMapSizes = null; - } else { - needGeneratedMips = false; - mipsWereGenerated = true; - } - } - - setFormat(format); - this.width = width; - this.height = height; - this.data = data; - this.depth = depth; - this.mipMapSizes = mipMapSizes; - this.colorSpace = colorSpace; - } - - /** - * @see #Image(com.jme3.texture.Image.Format, int, int, int, java.util.ArrayList, int[], com.jme3.texture.image.ColorSpace) - * @param format the desired data format - * @param width the desired width (in pixels) - * @param height the desired height (in pixels) - * @param depth the desired image depth - * @param data the image data to use - * @param mipMapSizes the desired mipmap sizes, or null for no mipmaps - * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, int, java.util.ArrayList, int[], com.jme3.texture.image.ColorSpace)} - */ - @Deprecated - public Image(Format format, int width, int height, int depth, ArrayList data, - int[] mipMapSizes) { - this(format, width, height, depth, data, mipMapSizes, ColorSpace.Linear); - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param data - * the image data. - * @param mipMapSizes - * the array of mipmap sizes, or null for no mipmaps. - * @param colorSpace - * the colorSpace of the image - */ - public Image(Format format, int width, int height, ByteBuffer data, - int[] mipMapSizes, ColorSpace colorSpace) { - - this(); - - if (mipMapSizes != null) { - if (mipMapSizes.length <= 1) { - mipMapSizes = null; - } else { - needGeneratedMips = false; - mipsWereGenerated = true; - } - } - - setFormat(format); - this.width = width; - this.height = height; - if (data != null){ - this.data = new ArrayList(1); - this.data.add(data); - } - this.mipMapSizes = mipMapSizes; - this.colorSpace = colorSpace; - } - - /** - * @see #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, int[], com.jme3.texture.image.ColorSpace) - * @param format the desired data format - * @param width the desired width (in pixels) - * @param height the desired height (in pixels) - * @param data the image data to use - * @param mipMapSizes the desired mipmap sizes, or null for no mipmaps - * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, int[], com.jme3.texture.image.ColorSpace)} - */ - @Deprecated - public Image(Format format, int width, int height, ByteBuffer data, - int[] mipMapSizes) { - this(format, width, height, data, mipMapSizes, ColorSpace.Linear); - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param depth - * the desired image depth - * @param data - * the image data. - * @param colorSpace - * the colorSpace of the image - */ - public Image(Format format, int width, int height, int depth, ArrayList data, ColorSpace colorSpace) { - this(format, width, height, depth, data, null, colorSpace); - } - - /** - * @see #Image(com.jme3.texture.Image.Format, int, int, int, java.util.ArrayList, com.jme3.texture.image.ColorSpace) - * @param format the desired data format - * @param width the desired width (in pixels) - * @param height the desired height (in pixels) - * @param depth the desired image depth - * @param data the image data to use - * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, int, java.util.ArrayList, com.jme3.texture.image.ColorSpace)} - */ - @Deprecated - public Image(Format format, int width, int height, int depth, ArrayList data) { - this(format, width, height, depth, data, ColorSpace.Linear); - } - - /** - * Constructor instantiates a new Image object. The - * attributes of the image are defined during construction. - * - * @param format - * the data format of the image. - * @param width - * the width of the image. - * @param height - * the height of the image. - * @param data - * the image data. - * @param colorSpace - * the colorSpace of the image - */ - public Image(Format format, int width, int height, ByteBuffer data, ColorSpace colorSpace) { - this(format, width, height, data, null, colorSpace); - } - - - /** - * @see #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, com.jme3.texture.image.ColorSpace) - * @param format the desired data format - * @param width the desired width (in pixels) - * @param height the desired height (in pixels) - * @param data the image data - * @deprecated use {@link #Image(com.jme3.texture.Image.Format, int, int, java.nio.ByteBuffer, com.jme3.texture.image.ColorSpace)} - */ - @Deprecated - public Image(Format format, int width, int height, ByteBuffer data) { - this(format, width, height, data, null, ColorSpace.Linear); - } - - - /** - * @return The number of samples (for multisampled textures). - * @see Image#setMultiSamples(int) - */ - public int getMultiSamples() { - return multiSamples; - } - - /** - * @param multiSamples Set the number of samples to use for this image, - * setting this to a value higher than 1 turns this image/texture - * into a multisample texture (on OpenGL3.1 and higher). - */ - public void setMultiSamples(int multiSamples) { - if (multiSamples <= 0) { - throw new IllegalArgumentException("multiSamples must be > 0"); - } - - if (multiSamples > 1) { - if (getData(0) != null) { - throw new IllegalArgumentException("Cannot upload data as multisample texture"); - } - - if (hasMipmaps()) { - throw new IllegalArgumentException("Multisample textures do not support mipmaps"); - } - } - - this.multiSamples = multiSamples; - } - - /** - * setData sets the data that makes up the image. This data - * is packed into an array of ByteBuffer objects. - * - * @param data - * the data that contains the image information. - */ - public void setData(ArrayList data) { - this.data = data; - setUpdateNeeded(); - } - - /** - * setData sets the data that makes up the image. This data - * is packed into a single ByteBuffer. - * - * @param data - * the data that contains the image information. - */ - public void setData(ByteBuffer data) { - this.data = new ArrayList(1); - this.data.add(data); - setUpdateNeeded(); - } - - public void addData(ByteBuffer data) { - if (this.data == null) - this.data = new ArrayList(1); - this.data.add(data); - setUpdateNeeded(); - } - - public void setData(int index, ByteBuffer data) { - if (index >= 0) { - while (this.data.size() <= index) { - this.data.add(null); - } - this.data.set(index, data); - setUpdateNeeded(); - } else { - throw new IllegalArgumentException("index must be greater than or equal to 0."); - } - } - - /** - * @return null - * @deprecated This feature is no longer used by the engine - */ - @Deprecated - public Object getEfficentData(){ - return null; - } - - /** - * Sets the mipmap sizes stored in this image's data buffer. Mipmaps are - * stored sequentially, and the first mipmap is the main image data. To - * specify no mipmaps, pass null and this will automatically be expanded - * into a single mipmap of the full - * - * @param mipMapSizes - * the mipmap sizes array, or null for a single image map. - */ - public void setMipMapSizes(int[] mipMapSizes) { - if (mipMapSizes != null && mipMapSizes.length <= 1) - mipMapSizes = null; - - this.mipMapSizes = mipMapSizes; - - if (mipMapSizes != null) { - needGeneratedMips = false; - mipsWereGenerated = false; - } else { - needGeneratedMips = true; - mipsWereGenerated = false; - } - - setUpdateNeeded(); - } - - /** - * setHeight sets the height value of the image. It is - * typically a good idea to try to keep this as a multiple of 2. - * - * @param height - * the height of the image. - */ - public void setHeight(int height) { - this.height = height; - setUpdateNeeded(); - } - - /** - * setDepth sets the depth value of the image. It is - * typically a good idea to try to keep this as a multiple of 2. This is - * used for 3d images. - * - * @param depth - * the depth of the image. - */ - public void setDepth(int depth) { - this.depth = depth; - setUpdateNeeded(); - } - - /** - * setWidth sets the width value of the image. It is - * typically a good idea to try to keep this as a multiple of 2. - * - * @param width - * the width of the image. - */ - public void setWidth(int width) { - this.width = width; - setUpdateNeeded(); - } - - /** - * setFormat sets the image format for this image. - * - * @param format - * the image format (not null) - * @throws IllegalArgumentException - * if format is null - * @see Format - */ - public void setFormat(Format format) { - if (format == null) { - throw new IllegalArgumentException("format may not be null."); - } - - this.format = format; - setUpdateNeeded(); - } - - /** - * getFormat returns the image format for this image. - * - * @return the image format. - * @see Format - */ - public Format getFormat() { - return format; - } - - /** - * getWidth returns the width of this image. - * - * @return the width of this image. - */ - public int getWidth() { - return width; - } - - /** - * getHeight returns the height of this image. - * - * @return the height of this image. - */ - public int getHeight() { - return height; - } - - /** - * getDepth returns the depth of this image (for 3d images). - * - * @return the depth of this image. - */ - public int getDepth() { - return depth; - } - - /** - * getData returns the data for this image. If the data is - * undefined, null will be returned. - * - * @return the data for this image. - */ - public List getData() { - return data; - } - - /** - * getData returns the data for this image. If the data is - * undefined, null will be returned. - * - * @param index index of the data buffer to access - * @return the data for this image. - */ - public ByteBuffer getData(int index) { - if (data.size() > index) - return data.get(index); - else - return null; - } - - /** - * Returns whether the image data contains mipmaps. - * - * @return true if the image data contains mipmaps, false if not. - */ - public boolean hasMipmaps() { - return mipMapSizes != null; - } - - /** - * Returns the mipmap sizes for this image. - * - * @return the mipmap sizes for this image. - */ - public int[] getMipMapSizes() { - return mipMapSizes; - } - - /** - * image loader is responsible for setting this attribute based on the color - * space in which the image has been encoded with. In the majority of cases, - * this flag will be set to sRGB by default since many image formats do not - * contain any color space information and the most frequently used colors - * space is sRGB - * - * The material loader may override this attribute to Linear if it determines that - * such conversion must not be performed, for example, when loading normal - * maps. - * - * @param colorSpace Set to sRGB to enable srgb -> linear - * conversion, Linear otherwise. - * - * @see Renderer#setLinearizeSrgbImages(boolean) - * - */ - public void setColorSpace(ColorSpace colorSpace) { - this.colorSpace = colorSpace; - } - - /** - * Specifies that this image is an SRGB image and therefore must undergo an - * sRGB -> linear RGB color conversion prior to being read by a shader and - * with the {@link Renderer#setLinearizeSrgbImages(boolean)} option is - * enabled. - * - * This option is only supported for the 8-bit color and grayscale image - * formats. Determines if the image is in SRGB color space or not. - * - * @return True, if the image is an SRGB image, false if it is linear RGB. - * - * @see Renderer#setLinearizeSrgbImages(boolean) - */ - public ColorSpace getColorSpace() { - return colorSpace; - } - - @Override - public String toString(){ - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName()); - sb.append("[size=").append(width).append("x").append(height); - - if (depth > 1) - sb.append("x").append(depth); - - sb.append(", format=").append(format.name()); - - if (hasMipmaps()) - sb.append(", mips"); - - if (getId() >= 0) - sb.append(", id=").append(id); - - sb.append("]"); - - return sb.toString(); - } - - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - if (!(other instanceof Image)) { - return false; - } - Image that = (Image) other; - if (this.getFormat() != that.getFormat()) - return false; - if (this.getWidth() != that.getWidth()) - return false; - if (this.getHeight() != that.getHeight()) - return false; - if (this.getData() != null && !this.getData().equals(that.getData())) - return false; - if (this.getData() == null && that.getData() != null) - return false; - if (this.getMipMapSizes() != null - && !Arrays.equals(this.getMipMapSizes(), that.getMipMapSizes())) - return false; - if (this.getMipMapSizes() == null && that.getMipMapSizes() != null) - return false; - if (this.getMultiSamples() != that.getMultiSamples()) - return false; - - return true; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 97 * hash + (this.format != null ? this.format.hashCode() : 0); - hash = 97 * hash + this.width; - hash = 97 * hash + this.height; - hash = 97 * hash + this.depth; - hash = 97 * hash + Arrays.hashCode(this.mipMapSizes); - hash = 97 * hash + (this.data != null ? this.data.hashCode() : 0); - hash = 97 * hash + this.multiSamples; - return hash; - } - - @Override - public void write(JmeExporter e) throws IOException { - OutputCapsule capsule = e.getCapsule(this); - capsule.write(format, "format", Format.RGBA8); - capsule.write(width, "width", 0); - capsule.write(height, "height", 0); - capsule.write(depth, "depth", 0); - capsule.write(mipMapSizes, "mipMapSizes", null); - capsule.write(multiSamples, "multiSamples", 1); - capsule.writeByteBufferArrayList(data, "data", null); - capsule.write(colorSpace, "colorSpace", null); - } - - @Override - public void read(JmeImporter importer) throws IOException { - InputCapsule capsule = importer.getCapsule(this); - format = capsule.readEnum("format", Format.class, Format.RGBA8); - width = capsule.readInt("width", 0); - height = capsule.readInt("height", 0); - depth = capsule.readInt("depth", 0); - mipMapSizes = capsule.readIntArray("mipMapSizes", null); - multiSamples = capsule.readInt("multiSamples", 1); - data = capsule.readByteBufferArrayList("data", null); - colorSpace = capsule.readEnum("colorSpace", ColorSpace.class, null); - if (mipMapSizes != null) { - needGeneratedMips = false; - mipsWereGenerated = true; - } - } - -} +/* + * Copyright (c) 2009-2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.texture; + +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.FastMath; +import com.jme3.renderer.Caps; +import com.jme3.renderer.Renderer; +import com.jme3.texture.image.ColorSpace; +import com.jme3.texture.image.LastTextureState; +import com.jme3.util.natives.GlNative; +import com.jme3.vulkan.images.GpuImage; +import com.jme3.vulkan.util.IntEnum; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Image defines a data format for a graphical image. The image + * is defined by a format, a height and width, and the image data. The width and + * height must be greater than 0. The data is contained in a byte buffer, and + * should be packed before creation of the image object. + * + * @author Mark Powell + * @author Joshua Slack + * @version $Id: Image.java 4131 2009-03-19 20:15:28Z blaine.dev $ + */ +public class GlImage extends GlNative implements GpuImage, Savable /*, Cloneable*/ { + + @Override + public IntEnum getType() { + return Type.TwoDemensional; + } + + public enum Format { + /** + * 8-bit alpha + */ + Alpha8(8), + + @Deprecated + Reserved1(0), + + /** + * 8-bit grayscale/luminance. + */ + Luminance8(8), + + @Deprecated + Reserved2(0), + + /** + * half-precision floating-point grayscale/luminance. + * + * Requires {@link Caps#FloatTexture}. + */ + Luminance16F(16,true), + + /** + * single-precision floating-point grayscale/luminance. + * + * Requires {@link Caps#FloatTexture}. + */ + Luminance32F(32,true), + + /** + * 8-bit luminance/grayscale and 8-bit alpha. + */ + Luminance8Alpha8(16), + + @Deprecated + Reserved3(0), + + /** + * half-precision floating-point grayscale/luminance and alpha. + * + * Requires {@link Caps#FloatTexture}. + */ + Luminance16FAlpha16F(32,true), + + @Deprecated + Reserved4(0), + + @Deprecated + Reserved5(0), + + /** + * 8-bit blue, green, and red. + */ + BGR8(24), // BGR and ABGR formats are often used on Windows systems + + /** + * 8-bit red, green, and blue. + */ + RGB8(24), + + @Deprecated + Reserved6(0), + + @Deprecated + Reserved7(0), + + /** + * 5-bit red, 6-bit green, and 5-bit blue. + */ + RGB565(16), + + @Deprecated + Reserved8(0), + + /** + * 5-bit red, green, and blue with 1-bit alpha. + */ + RGB5A1(16), + + /** + * 8-bit red, green, blue, and alpha. + */ + RGBA8(32), + + /** + * 8-bit alpha, blue, green, and red. + */ + ABGR8(32), + + /** + * 8-bit alpha, red, blue and green + */ + ARGB8(32), + + /** + * 8-bit blue, green, red and alpha. + */ + BGRA8(32), + + @Deprecated + Reserved9(0), + + /** + * S3TC compression DXT1. + */ + DXT1(4,false,true, false), + + /** + * S3TC compression DXT1 with 1-bit alpha. + */ + DXT1A(4,false,true, false), + + /** + * S3TC compression DXT3 with 4-bit alpha. + */ + DXT3(8,false,true, false), + + /** + * S3TC compression DXT5 with interpolated 8-bit alpha. + * + */ + DXT5(8,false,true, false), + + RGTC2(8,false,true, false), + + SIGNED_RGTC2(8,false,true, false), + + RGTC1(4,false,true, false), + + SIGNED_RGTC1(4,false,true, false), + + /** + * BPTC compression BC6 signed float RGB + */ + BC6H_SF16(8, false, true, true), + + /** + * BPTC compression BC6 unsigned float RGB + */ + BC6H_UF16(8, false, true, true), + + /** + * BPTC compression BC7 RGBA + */ + BC7_UNORM(8, false, true, false), + + /** + * BPTC compression BC7 SRGB Alpha + */ + BC7_UNORM_SRGB(8, false, true, false), + + /** + * Luminance-Alpha Texture Compression. + * + * @deprecated Not supported by OpenGL 3.0. + */ + @Deprecated + Reserved10(0), + + /** + * Arbitrary depth format. The precision is chosen by the video + * hardware. + */ + Depth(0,true,false,false), + + /** + * 16-bit depth. + */ + Depth16(16,true,false,false), + + /** + * 24-bit depth. + */ + Depth24(24,true,false,false), + + /** + * 32-bit depth. + */ + Depth32(32,true,false,false), + + /** + * single-precision floating point depth. + * + * Requires {@link Caps#FloatDepthBuffer}. + */ + Depth32F(32,true,false,true), + + /** + * Texture data is stored as {@link Format#RGB16F} in system memory, + * but will be converted to {@link Format#RGB111110F} when sent + * to the video hardware. + * + * Requires {@link Caps#FloatTexture} and {@link Caps#PackedFloatTexture}. + */ + RGB16F_to_RGB111110F(48,true), + + /** + * unsigned floating-point red, green and blue that uses 32 bits. + * + * Requires {@link Caps#PackedFloatTexture}. + */ + RGB111110F(32,true), + + /** + * Texture data is stored as {@link Format#RGB16F} in system memory, + * but will be converted to {@link Format#RGB9E5} when sent + * to the video hardware. + * + * Requires {@link Caps#FloatTexture} and {@link Caps#SharedExponentTexture}. + */ + RGB16F_to_RGB9E5(48,true), + + /** + * 9-bit red, green and blue with 5-bit exponent. + * + * Requires {@link Caps#SharedExponentTexture}. + */ + RGB9E5(32,true), + + /** + * half-precision floating point red, green, and blue. + * + * Requires {@link Caps#FloatTexture}. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB16F(48,true), + + /** + * half-precision floating point red, green, blue, and alpha. + * + * Requires {@link Caps#FloatTexture}. + */ + RGBA16F(64,true), + + /** + * single-precision floating point red, green, and blue. + * + * Requires {@link Caps#FloatTexture}. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB32F(96,true), + + /** + * single-precision floating point red, green, blue and alpha. + * + * Requires {@link Caps#FloatTexture}. + */ + RGBA32F(128,true), + + @Deprecated + Reserved11(0), + + /** + * 24-bit depth with 8-bit stencil. + * Check the cap {@link Caps#PackedDepthStencilBuffer}. + */ + Depth24Stencil8(32, true, false, false), + + @Deprecated + Reserved12(0), + + /** + * Ericsson Texture Compression. Typically used on Android. + * + * Requires {@link Caps#TextureCompressionETC1}. + */ + ETC1(4, false, true, false), + + /** + * Ericsson Texture Compression 2. Typically used on Android. + * Same as {@link #ETC1} but with alpha. + * + * Requires {@link Caps#TextureCompressionETC2}. + */ + ETC2(8, false, true, false), + + /** + * Ericsson Texture Compression 2. Typically used on Android. + * Same as {@link #ETC2} but alpha can be either 1 or 0. + * + * Requires {@link Caps#TextureCompressionETC2}. + */ + ETC2_ALPHA1(4, false, true, false), + + + /** + * 8-bit signed int red. + * + * Requires {@link Caps#IntegerTexture}. + */ + R8I(8), + /** + * 8-bit unsigned int red. + * + * Requires {@link Caps#IntegerTexture}. + */ + R8UI(8), + /** + * 16-bit signed int red. + * + * Requires {@link Caps#IntegerTexture}. + */ + R16I(16), + /** + * 16-bit unsigned int red. + * + * Requires {@link Caps#IntegerTexture}. + */ + R16UI(16), + /** + * 32-bit signed int red. + * + * Requires {@link Caps#IntegerTexture}. + */ + R32I(32), + /** + * 32-bit unsigned int red. + * + * Requires {@link Caps#IntegerTexture}. + */ + R32UI(32), + + + /** + * 8-bit signed int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ + RG8I(16), + /** + * 8-bit unsigned int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ + RG8UI(16), + /** + * 16-bit signed int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ + RG16I(32), + /** + * 16-bit unsigned int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ + RG16UI(32), + /** + * 32-bit signed int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ + RG32I(64), + /** + * 32-bit unsigned int red and green. + * + * Requires {@link Caps#IntegerTexture}. + */ + RG32UI(64), + + /** + * 8-bit signed int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB8I(24), + /** + * 8 bit unsigned int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB8UI(24), + /** + * 16-bit signed int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB16I(48), + /** + * 16-bit unsigned int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB16UI(48), + /** + * 32-bit signed int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB32I(96), + /** + * 32-bit unsigned int red, green and blue. + * + * Requires {@link Caps#IntegerTexture} to be supported for textures. + * May be supported for renderbuffers, but the OpenGL specification does not require it. + */ + RGB32UI(96), + + + /** + * 8-bit signed int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ + RGBA8I(32), + /** + * 8-bit unsigned int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ + RGBA8UI(32), + /** + * 16-bit signed int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ + RGBA16I(64), + /** + * 16-bit unsigned int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ + RGBA16UI(64), + /** + * 32-bit signed int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ + RGBA32I(128), + /** + * 32-bit unsigned int red, green, blue and alpha. + * + * Requires {@link Caps#IntegerTexture}. + */ + RGBA32UI(128), + + /** + * half-precision floating point red. + * + * Requires {@link Caps#FloatTexture}. + */ + R16F(16,true), + + /** + * single-precision floating point red. + * + * Requires {@link Caps#FloatTexture}. + */ + R32F(32,true), + + /** + * half-precision floating point red and green. + * + * Requires {@link Caps#FloatTexture}. + */ + RG16F(32,true), + + /** + * single-precision floating point red and green. + * + * Requires {@link Caps#FloatTexture}. + */ + RG32F(64,true), + + /** + * 10-bit red, green, and blue with 2-bit alpha. + */ + RGB10A2(32), + ; + + private int bpp; + private boolean isDepth; + private boolean isCompressed; + private boolean isFloatingPoint; + + private Format(int bpp){ + this.bpp = bpp; + } + + private Format(int bpp, boolean isFP){ + this(bpp); + this.isFloatingPoint = isFP; + } + + private Format(int bpp, boolean isDepth, boolean isCompressed, boolean isFP){ + this(bpp, isFP); + this.isDepth = isDepth; + this.isCompressed = isCompressed; + } + + /** + * @return bits per pixel. + */ + public int getBitsPerPixel(){ + return bpp; + } + + /** + * @return True if this format is a depth format, false otherwise. + */ + public boolean isDepthFormat(){ + return isDepth; + } + + /** + * @return True if this format is a depth + stencil (packed) format, false otherwise. + */ + boolean isDepthStencilFormat() { + return this == Depth24Stencil8; + } + + /** + * @return True if this is a compressed image format, false if + * uncompressed. + */ + public boolean isCompressed() { + return isCompressed; + } + + /** + * @return True if this image format is in floating point, + * false if it is an integer format. + */ + public boolean isFloatingPont(){ + return isFloatingPoint; + } + + + + } + + // image attributes + protected Format format; + protected int width, height, depth; + protected int[] mipMapSizes; + protected ArrayList data; + protected int multiSamples = 1; + protected ColorSpace colorSpace = null; +// protected int mipOffset = 0; + + // attributes relating to GL object + protected boolean mipsWereGenerated = false; + protected boolean needGeneratedMips = false; + protected LastTextureState lastTextureState = new LastTextureState(); + + /** + * Internal use only. + * The renderer stores the texture state set from the last texture, + * so it doesn't have to change it unless necessary. + * + * @return The image parameter state. + */ + public LastTextureState getLastTextureState() { + return lastTextureState; + } + + /** + * Internal use only. + * The renderer marks which images have generated mipmaps in VRAM + * and which do not, so it can generate them as needed. + * + * @param generated If mipmaps were generated or not. + */ + public void setMipmapsGenerated(boolean generated) { + this.mipsWereGenerated = generated; + } + + /** + * Internal use only. + * Check if the renderer has generated mipmaps for this image in VRAM + * or not. + * + * @return If mipmaps were generated already. + */ + public boolean isMipmapsGenerated() { + return mipsWereGenerated; + } + + /** + * (Package private) Called by {@link GlTexture} when + * {@link #isMipmapsGenerated() } is false in order to generate + * mipmaps for this image. + */ + void setNeedGeneratedMipmaps() { + needGeneratedMips = true; + } + + /** + * @return True if the image needs to have mipmaps generated + * for it (as requested by the texture). This stays true even + * after mipmaps have been generated. + */ + public boolean isGeneratedMipmapsRequired() { + return needGeneratedMips; + } + + /** + * Determine if the image is NPOT. + * + * @return if the image is a non-power-of-2 image, e.g. having dimensions + * that are not powers of 2. + */ + public boolean isNPOT() { + return width != 0 && height != 0 + && (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)); + } + + @Override + public void resetObject() { + this.object = -1; + this.mipsWereGenerated = false; + this.lastTextureState.reset(); + setUpdateNeeded(); + } + + @Override + public Runnable createNativeDestroyer() { + return () -> renderer.deleteImage(new GlImage(object)); + } + + /** + * @return A shallow clone of this image. The data is not cloned. + */ + @Override + public GlImage clone(){ + GlImage clone = (GlImage) super.clone(); + clone.mipMapSizes = mipMapSizes != null ? mipMapSizes.clone() : null; + clone.data = data != null ? new ArrayList<>(data) : null; + clone.lastTextureState = new LastTextureState(); + clone.setUpdateNeeded(); + return clone; + } + + /** + * Constructor instantiates a new Image object. All values + * are undefined. + */ + public GlImage() { + super(); + data = new ArrayList(1); + } + + protected GlImage(int id) { + super(id); + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param depth + * the desired image depth + * @param data + * the image data. + * @param mipMapSizes + * the array of mipmap sizes, or null for no mipmaps. + * @param colorSpace + * the colorSpace of the image + */ + public GlImage(Format format, int width, int height, int depth, ArrayList data, + int[] mipMapSizes, ColorSpace colorSpace) { + + this(); + + if (mipMapSizes != null) { + if (mipMapSizes.length <= 1) { + mipMapSizes = null; + } else { + needGeneratedMips = false; + mipsWereGenerated = true; + } + } + + setFormat(format); + this.width = width; + this.height = height; + this.data = data; + this.depth = depth; + this.mipMapSizes = mipMapSizes; + this.colorSpace = colorSpace; + } + + /** + * @see #GlImage(GlImage.Format, int, int, int, java.util.ArrayList, int[], com.jme3.texture.image.ColorSpace) + * @param format the desired data format + * @param width the desired width (in pixels) + * @param height the desired height (in pixels) + * @param depth the desired image depth + * @param data the image data to use + * @param mipMapSizes the desired mipmap sizes, or null for no mipmaps + * @deprecated use {@link #GlImage(GlImage.Format, int, int, int, java.util.ArrayList, int[], com.jme3.texture.image.ColorSpace)} + */ + @Deprecated + public GlImage(Format format, int width, int height, int depth, ArrayList data, + int[] mipMapSizes) { + this(format, width, height, depth, data, mipMapSizes, ColorSpace.Linear); + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param data + * the image data. + * @param mipMapSizes + * the array of mipmap sizes, or null for no mipmaps. + * @param colorSpace + * the colorSpace of the image + */ + public GlImage(Format format, int width, int height, ByteBuffer data, + int[] mipMapSizes, ColorSpace colorSpace) { + + this(); + + if (mipMapSizes != null) { + if (mipMapSizes.length <= 1) { + mipMapSizes = null; + } else { + needGeneratedMips = false; + mipsWereGenerated = true; + } + } + + setFormat(format); + this.width = width; + this.height = height; + if (data != null){ + this.data = new ArrayList(1); + this.data.add(data); + } + this.mipMapSizes = mipMapSizes; + this.colorSpace = colorSpace; + } + + /** + * @see #GlImage(GlImage.Format, int, int, java.nio.ByteBuffer, int[], com.jme3.texture.image.ColorSpace) + * @param format the desired data format + * @param width the desired width (in pixels) + * @param height the desired height (in pixels) + * @param data the image data to use + * @param mipMapSizes the desired mipmap sizes, or null for no mipmaps + * @deprecated use {@link #GlImage(GlImage.Format, int, int, java.nio.ByteBuffer, int[], com.jme3.texture.image.ColorSpace)} + */ + @Deprecated + public GlImage(Format format, int width, int height, ByteBuffer data, + int[] mipMapSizes) { + this(format, width, height, data, mipMapSizes, ColorSpace.Linear); + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param depth + * the desired image depth + * @param data + * the image data. + * @param colorSpace + * the colorSpace of the image + */ + public GlImage(Format format, int width, int height, int depth, ArrayList data, ColorSpace colorSpace) { + this(format, width, height, depth, data, null, colorSpace); + } + + /** + * @see #GlImage(GlImage.Format, int, int, int, java.util.ArrayList, com.jme3.texture.image.ColorSpace) + * @param format the desired data format + * @param width the desired width (in pixels) + * @param height the desired height (in pixels) + * @param depth the desired image depth + * @param data the image data to use + * @deprecated use {@link #GlImage(GlImage.Format, int, int, int, java.util.ArrayList, com.jme3.texture.image.ColorSpace)} + */ + @Deprecated + public GlImage(Format format, int width, int height, int depth, ArrayList data) { + this(format, width, height, depth, data, ColorSpace.Linear); + } + + /** + * Constructor instantiates a new Image object. The + * attributes of the image are defined during construction. + * + * @param format + * the data format of the image. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param data + * the image data. + * @param colorSpace + * the colorSpace of the image + */ + public GlImage(Format format, int width, int height, ByteBuffer data, ColorSpace colorSpace) { + this(format, width, height, data, null, colorSpace); + } + + + /** + * @see #GlImage(GlImage.Format, int, int, java.nio.ByteBuffer, com.jme3.texture.image.ColorSpace) + * @param format the desired data format + * @param width the desired width (in pixels) + * @param height the desired height (in pixels) + * @param data the image data + * @deprecated use {@link #GlImage(GlImage.Format, int, int, java.nio.ByteBuffer, com.jme3.texture.image.ColorSpace)} + */ + @Deprecated + public GlImage(Format format, int width, int height, ByteBuffer data) { + this(format, width, height, data, null, ColorSpace.Linear); + } + + + /** + * @return The number of samples (for multisampled textures). + * @see GlImage#setMultiSamples(int) + */ + public int getMultiSamples() { + return multiSamples; + } + + /** + * @param multiSamples Set the number of samples to use for this image, + * setting this to a value higher than 1 turns this image/texture + * into a multisample texture (on OpenGL3.1 and higher). + */ + public void setMultiSamples(int multiSamples) { + if (multiSamples <= 0) { + throw new IllegalArgumentException("multiSamples must be > 0"); + } + + if (multiSamples > 1) { + if (getData(0) != null) { + throw new IllegalArgumentException("Cannot upload data as multisample texture"); + } + + if (hasMipmaps()) { + throw new IllegalArgumentException("Multisample textures do not support mipmaps"); + } + } + + this.multiSamples = multiSamples; + } + + /** + * setData sets the data that makes up the image. This data + * is packed into an array of ByteBuffer objects. + * + * @param data + * the data that contains the image information. + */ + public void setData(ArrayList data) { + this.data = data; + setUpdateNeeded(); + } + + /** + * setData sets the data that makes up the image. This data + * is packed into a single ByteBuffer. + * + * @param data + * the data that contains the image information. + */ + public void setData(ByteBuffer data) { + this.data = new ArrayList(1); + this.data.add(data); + setUpdateNeeded(); + } + + public void addData(ByteBuffer data) { + if (this.data == null) + this.data = new ArrayList(1); + this.data.add(data); + setUpdateNeeded(); + } + + public void setData(int index, ByteBuffer data) { + if (index >= 0) { + while (this.data.size() <= index) { + this.data.add(null); + } + this.data.set(index, data); + setUpdateNeeded(); + } else { + throw new IllegalArgumentException("index must be greater than or equal to 0."); + } + } + + /** + * @return null + * @deprecated This feature is no longer used by the engine + */ + @Deprecated + public Object getEfficentData(){ + return null; + } + + /** + * Sets the mipmap sizes stored in this image's data buffer. Mipmaps are + * stored sequentially, and the first mipmap is the main image data. To + * specify no mipmaps, pass null and this will automatically be expanded + * into a single mipmap of the full + * + * @param mipMapSizes + * the mipmap sizes array, or null for a single image map. + */ + public void setMipMapSizes(int[] mipMapSizes) { + if (mipMapSizes != null && mipMapSizes.length <= 1) + mipMapSizes = null; + + this.mipMapSizes = mipMapSizes; + + if (mipMapSizes != null) { + needGeneratedMips = false; + mipsWereGenerated = false; + } else { + needGeneratedMips = true; + mipsWereGenerated = false; + } + + setUpdateNeeded(); + } + + /** + * setHeight sets the height value of the image. It is + * typically a good idea to try to keep this as a multiple of 2. + * + * @param height + * the height of the image. + */ + public void setHeight(int height) { + this.height = height; + setUpdateNeeded(); + } + + /** + * setDepth sets the depth value of the image. It is + * typically a good idea to try to keep this as a multiple of 2. This is + * used for 3d images. + * + * @param depth + * the depth of the image. + */ + public void setDepth(int depth) { + this.depth = depth; + setUpdateNeeded(); + } + + /** + * setWidth sets the width value of the image. It is + * typically a good idea to try to keep this as a multiple of 2. + * + * @param width + * the width of the image. + */ + public void setWidth(int width) { + this.width = width; + setUpdateNeeded(); + } + + /** + * setFormat sets the image format for this image. + * + * @param format + * the image format (not null) + * @throws IllegalArgumentException + * if format is null + * @see Format + */ + public void setFormat(Format format) { + if (format == null) { + throw new IllegalArgumentException("format may not be null."); + } + + this.format = format; + setUpdateNeeded(); + } + + /** + * getFormat returns the image format for this image. + * + * @return the image format. + * @see Format + */ + public Format getGlFormat() { + return format; + } + + @Override + public com.jme3.vulkan.Format getFormat() { + // todo: merge com.jme3.vulkan.Format and GlImage.Format + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getId() { + return object; + } + + /** + * getWidth returns the width of this image. + * + * @return the width of this image. + */ + @Override + public int getWidth() { + return width; + } + + /** + * getHeight returns the height of this image. + * + * @return the height of this image. + */ + @Override + public int getHeight() { + return height; + } + + /** + * getDepth returns the depth of this image (for 3d images). + * + * @return the depth of this image. + */ + @Override + public int getDepth() { + return depth; + } + + @Override + public int getMipmaps() { + // todo: check for accuracy (maybe refactor gl mipmaps?) + return mipMapSizes.length; + } + + @Override + public int getLayers() { + // todo: implement properly + return 1; + } + + /** + * getData returns the data for this image. If the data is + * undefined, null will be returned. + * + * @return the data for this image. + */ + public List getData() { + return data; + } + + /** + * getData returns the data for this image. If the data is + * undefined, null will be returned. + * + * @param index index of the data buffer to access + * @return the data for this image. + */ + public ByteBuffer getData(int index) { + if (data.size() > index) + return data.get(index); + else + return null; + } + + /** + * Returns whether the image data contains mipmaps. + * + * @return true if the image data contains mipmaps, false if not. + */ + public boolean hasMipmaps() { + return mipMapSizes != null; + } + + /** + * Returns the mipmap sizes for this image. + * + * @return the mipmap sizes for this image. + */ + public int[] getMipMapSizes() { + return mipMapSizes; + } + + /** + * image loader is responsible for setting this attribute based on the color + * space in which the image has been encoded with. In the majority of cases, + * this flag will be set to sRGB by default since many image formats do not + * contain any color space information and the most frequently used colors + * space is sRGB + * + * The material loader may override this attribute to Linear if it determines that + * such conversion must not be performed, for example, when loading normal + * maps. + * + * @param colorSpace Set to sRGB to enable srgb -> linear + * conversion, Linear otherwise. + * + * @see Renderer#setLinearizeSrgbImages(boolean) + * + */ + public void setColorSpace(ColorSpace colorSpace) { + this.colorSpace = colorSpace; + } + + /** + * Specifies that this image is an SRGB image and therefore must undergo an + * sRGB -> linear RGB color conversion prior to being read by a shader and + * with the {@link Renderer#setLinearizeSrgbImages(boolean)} option is + * enabled. + * + * This option is only supported for the 8-bit color and grayscale image + * formats. Determines if the image is in SRGB color space or not. + * + * @return True, if the image is an SRGB image, false if it is linear RGB. + * + * @see Renderer#setLinearizeSrgbImages(boolean) + */ + public ColorSpace getColorSpace() { + return colorSpace; + } + + @Override + public String toString(){ + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append("[size=").append(width).append("x").append(height); + + if (depth > 1) + sb.append("x").append(depth); + + sb.append(", format=").append(format.name()); + + if (hasMipmaps()) + sb.append(", mips"); + + if (getNativeObject() >= 0) + sb.append(", id=").append(object); + + sb.append("]"); + + return sb.toString(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof GlImage)) { + return false; + } + GlImage that = (GlImage) other; + if (this.getGlFormat() != that.getGlFormat()) + return false; + if (this.getWidth() != that.getWidth()) + return false; + if (this.getHeight() != that.getHeight()) + return false; + if (this.getData() != null && !this.getData().equals(that.getData())) + return false; + if (this.getData() == null && that.getData() != null) + return false; + if (this.getMipMapSizes() != null + && !Arrays.equals(this.getMipMapSizes(), that.getMipMapSizes())) + return false; + if (this.getMipMapSizes() == null && that.getMipMapSizes() != null) + return false; + if (this.getMultiSamples() != that.getMultiSamples()) + return false; + + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (this.format != null ? this.format.hashCode() : 0); + hash = 97 * hash + this.width; + hash = 97 * hash + this.height; + hash = 97 * hash + this.depth; + hash = 97 * hash + Arrays.hashCode(this.mipMapSizes); + hash = 97 * hash + (this.data != null ? this.data.hashCode() : 0); + hash = 97 * hash + this.multiSamples; + return hash; + } + + @Override + public void write(JmeExporter e) throws IOException { + OutputCapsule capsule = e.getCapsule(this); + capsule.write(format, "format", Format.RGBA8); + capsule.write(width, "width", 0); + capsule.write(height, "height", 0); + capsule.write(depth, "depth", 0); + capsule.write(mipMapSizes, "mipMapSizes", null); + capsule.write(multiSamples, "multiSamples", 1); + capsule.writeByteBufferArrayList(data, "data", null); + capsule.write(colorSpace, "colorSpace", null); + } + + @Override + public void read(JmeImporter importer) throws IOException { + InputCapsule capsule = importer.getCapsule(this); + format = capsule.readEnum("format", Format.class, Format.RGBA8); + width = capsule.readInt("width", 0); + height = capsule.readInt("height", 0); + depth = capsule.readInt("depth", 0); + mipMapSizes = capsule.readIntArray("mipMapSizes", null); + multiSamples = capsule.readInt("multiSamples", 1); + data = capsule.readByteBufferArrayList("data", null); + colorSpace = capsule.readEnum("colorSpace", ColorSpace.class, null); + if (mipMapSizes != null) { + needGeneratedMips = false; + mipsWereGenerated = true; + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/texture/GlTexture.java b/jme3-core/src/main/java/com/jme3/texture/GlTexture.java new file mode 100644 index 0000000000..f637e4fb2f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/texture/GlTexture.java @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2009-2021 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.texture; + +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetNotFoundException; +import com.jme3.asset.CloneableSmartAsset; +import com.jme3.asset.TextureKey; +import com.jme3.export.*; +import com.jme3.util.PlaceholderAssets; +import com.jme3.vulkan.images.AddressMode; +import com.jme3.vulkan.images.Filter; +import com.jme3.vulkan.images.GpuImage; +import com.jme3.vulkan.images.MipmapMode; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.vulkan.VK10; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Texture defines a texture object to be used to display an + * image on a piece of geometry. The image to be displayed is defined by the + * Image class. All attributes required for texture mapping are + * contained within this class. This includes mipmapping if desired, + * magnificationFilter options, apply options and correction options. Default + * values are as follows: minificationFilter - NearestNeighborNoMipMaps, + * magnificationFilter - NearestNeighbor, wrap - EdgeClamp on S,T and R, apply - + * Modulate, environment - None. + * + * @see GlImage + * @author Mark Powell + * @author Joshua Slack + * @version $Id: Texture.java 4131 2009-03-19 20:15:28Z blaine.dev $ + */ +public abstract class GlTexture implements Texture, ImageView, CloneableSmartAsset, Savable, Cloneable { + + public enum Type { + + /** + * Two dimensional texture (default). A rectangle. + */ + TwoDimensional, + + /** + * An array of two-dimensional textures. + */ + TwoDimensionalArray, + + /** + * Three-dimensional texture. (A cube) + */ + ThreeDimensional, + + /** + * A set of 6 TwoDimensional textures arranged as faces of a cube facing + * inwards. + */ + CubeMap; + } + + public enum MinFilter { + + /** + * Nearest neighbor interpolation is the fastest and crudest filtering + * method - it simply uses the color of the texel closest to the pixel + * center for the pixel color. While fast, this results in aliasing and + * shimmering during minification. (GL equivalent: GL_NEAREST) + */ + NearestNoMipMaps(false), + + /** + * In this method the four nearest texels to the pixel center are + * sampled (at texture level 0), and their colors are combined by + * weighted averages. Though smoother, without mipmaps it suffers the + * same aliasing and shimmering problems as nearest + * NearestNeighborNoMipMaps. (GL equivalent: GL_LINEAR) + */ + BilinearNoMipMaps(false), + + /** + * Same as NearestNeighborNoMipMaps except that instead of using samples + * from texture level 0, the closest mipmap level is chosen based on + * distance. This reduces the aliasing and shimmering significantly, but + * does not help with blockiness. (GL equivalent: + * GL_NEAREST_MIPMAP_NEAREST) + */ + NearestNearestMipMap(true), + + /** + * Same as BilinearNoMipMaps except that instead of using samples from + * texture level 0, the closest mipmap level is chosen based on + * distance. By using mipmapping we avoid the aliasing and shimmering + * problems of BilinearNoMipMaps. (GL equivalent: + * GL_LINEAR_MIPMAP_NEAREST) + */ + BilinearNearestMipMap(true), + + /** + * Similar to NearestNeighborNoMipMaps except that instead of using + * samples from texture level 0, a sample is chosen from each of the + * closest (by distance) two mipmap levels. A weighted average of these + * two samples is returned. (GL equivalent: GL_NEAREST_MIPMAP_LINEAR) + */ + NearestLinearMipMap(true), + + /** + * Trilinear filtering is a remedy to a common artifact seen in + * mipmapped bilinearly filtered images: an abrupt and very noticeable + * change in quality at boundaries where the renderer switches from one + * mipmap level to the next. Trilinear filtering solves this by doing a + * texture lookup and bilinear filtering on the two closest mipmap + * levels (one higher and one lower quality), and then linearly + * interpolating the results. This results in a smooth degradation of + * texture quality as distance from the viewer increases, rather than a + * series of sudden drops. Of course, closer than Level 0 there is only + * one mipmap level available, and the algorithm reverts to bilinear + * filtering (GL equivalent: GL_LINEAR_MIPMAP_LINEAR) + */ + Trilinear(true); + + private final boolean usesMipMapLevels; + + MinFilter(boolean usesMipMapLevels) { + this.usesMipMapLevels = usesMipMapLevels; + } + + public boolean usesMipMapLevels() { + return usesMipMapLevels; + } + + public static MinFilter of(IntEnum filter, IntEnum mipmap) { + if (filter.is(Filter.Linear)) { + if (mipmap.is(MipmapMode.Linear)) return Trilinear; + else return BilinearNearestMipMap; + } else if (filter.is(Filter.Nearest)) { + if (mipmap.is(MipmapMode.Linear)) return Trilinear; + else return NearestNearestMipMap; + } else if (mipmap.is(MipmapMode.Linear)) return NearestLinearMipMap; + else return NearestNearestMipMap; + } + + } + + public enum MagFilter { + + /** + * Nearest neighbor interpolation is the fastest and crudest filtering + * mode - it simply uses the color of the texel closest to the pixel + * center for the pixel color. While fast, this results in texture + * 'blockiness' during magnification. (GL equivalent: GL_NEAREST) + */ + Nearest, + + /** + * In this mode the four nearest texels to the pixel center are sampled + * (at the closest mipmap level), and their colors are combined by + * weighted average according to distance. This removes the 'blockiness' + * seen during magnification, as there is now a smooth gradient of color + * change from one texel to the next, instead of an abrupt jump as the + * pixel center crosses the texel boundary. (GL equivalent: GL_LINEAR) + */ + Bilinear; + + public static MagFilter of(IntEnum filter) { + if (filter.is(Filter.Linear)) return Bilinear; + else return Nearest; + } + + } + + public enum WrapMode { + /** + * Only the fractional portion of the coordinate is considered. + */ + Repeat, + + /** + * Only the fractional portion of the coordinate is considered, but if + * the integer portion is odd, we'll use 1 - the fractional portion. + * (Introduced around OpenGL1.4) Falls back on Repeat if not supported. + */ + MirroredRepeat, + + /** + * coordinate will be clamped to [0,1] + * + * @deprecated Not supported by OpenGL 3 + */ + @Deprecated + Clamp, + /** + * mirrors and clamps the texture coordinate, where mirroring and + * clamping a value f computes: + * mirrorClamp(f) = min(1, max(1/(2*N), + * abs(f))) where N + * is the size of the one-, two-, or three-dimensional texture image in + * the direction of wrapping. (Introduced after OpenGL1.4) Falls back on + * Clamp if not supported. + * + * @deprecated Not supported by OpenGL 3 + */ + @Deprecated + MirrorClamp, + + /** + * coordinate will be clamped to the range [-1/(2N), 1 + 1/(2N)] where N + * is the size of the texture in the direction of clamping. Falls back + * on Clamp if not supported. + * + * @deprecated Not supported by OpenGL 3 or OpenGL ES 2 + */ + @Deprecated + BorderClamp, + /** + * Wrap mode MIRROR_CLAMP_TO_BORDER_EXT mirrors and clamps to border the + * texture coordinate, where mirroring and clamping to border a value f + * computes: + * mirrorClampToBorder(f) = min(1+1/(2*N), max(1/(2*N), abs(f))) + * where N is the size of the one-, two-, or three-dimensional texture + * image in the direction of wrapping. (Introduced after OpenGL1.4) + * Falls back on BorderClamp if not supported. + * + * @deprecated Not supported by OpenGL 3 + */ + @Deprecated + MirrorBorderClamp, + /** + * coordinate will be clamped to the range [1/(2N), 1 - 1/(2N)] where N + * is the size of the texture in the direction of clamping. Falls back + * on Clamp if not supported. + */ + EdgeClamp, + + /** + * mirrors and clamps to edge the texture coordinate, where mirroring + * and clamping to edge a value f computes: + * mirrorClampToEdge(f) = min(1-1/(2*N), max(1/(2*N), abs(f))) + * where N is the size of the one-, two-, or three-dimensional texture + * image in the direction of wrapping. (Introduced after OpenGL1.4) + * Falls back on EdgeClamp if not supported. + * + * @deprecated Not supported by OpenGL 3 + */ + @Deprecated + MirrorEdgeClamp; + + public static WrapMode of(IntEnum address) { + if (address.is(AddressMode.Repeat)) return Repeat; + else if (address.is(AddressMode.MirroredRepeat)) return MirroredRepeat; + else if (address.is(AddressMode.ClampToBorder)) return BorderClamp; + else return EdgeClamp; + } + + } + + public enum WrapAxis { + /** + * S wrapping (u or "horizontal" wrap) + */ + S, + /** + * T wrapping (v or "vertical" wrap) + */ + T, + /** + * R wrapping (w or "depth" wrap) + */ + R; + } + + /** + * If this texture is a depth texture (the format is Depth*) then + * this value may be used to compare the texture depth to the R texture + * coordinate. + */ + public enum ShadowCompareMode { + /** + * Shadow comparison mode is disabled. + * Texturing is done normally. + */ + Off, + + /** + * {@code + * Compares the 3rd texture coordinate R to the value + * in this depth texture. If R <= texture value then result is 1.0, + * otherwise, result is 0.0. If filtering is set to bilinear or trilinear + * the implementation may sample the texture multiple times to provide + * smoother results in the range [0, 1].} + */ + LessOrEqual, + + /** + * {@code + * Compares the 3rd texture coordinate R to the value + * in this depth texture. If R >= texture value then result is 1.0, + * otherwise, result is 0.0. If filtering is set to bilinear or trilinear + * the implementation may sample the texture multiple times to provide + * smoother results in the range [0, 1].} + */ + GreaterOrEqual + } + + /** + * The name of the texture (if loaded as a resource). + */ + private String name = null; + + /** + * The image stored in the texture + */ + private GlImage image = null; + + /** + * The texture key allows to reload a texture from a file + * if needed. + */ + private TextureKey key = null; + + private MinFilter minificationFilter = MinFilter.BilinearNoMipMaps; + private MagFilter magnificationFilter = MagFilter.Bilinear; + private ShadowCompareMode shadowCompareMode = ShadowCompareMode.Off; + private int anisotropicFilter; + + /** + * @return A cloned Texture object. + */ + @Override + public GlTexture clone(){ + try { + return (GlTexture) super.clone(); + } catch (CloneNotSupportedException ex) { + throw new AssertionError(); + } + } + + @Override + public long getId() { + return VK10.VK_NULL_HANDLE; + } + + /** + * Constructor instantiates a new Texture object with default + * attributes. + */ + public GlTexture() { + } + + /** + * @return the MinificationFilterMode of this texture. + */ + public MinFilter getMinFilter() { + return minificationFilter; + } + + /** + * @param minificationFilter + * the new MinificationFilterMode for this texture. + * @throws IllegalArgumentException + * if minificationFilter is null + */ + public void setMinFilter(MinFilter minificationFilter) { + if (minificationFilter == null) { + throw new IllegalArgumentException( + "minificationFilter can not be null."); + } + this.minificationFilter = minificationFilter; + if (minificationFilter.usesMipMapLevels() && image != null && !image.isGeneratedMipmapsRequired() && !image.hasMipmaps()) { + image.setNeedGeneratedMipmaps(); + } + } + + /** + * @return the MagnificationFilterMode of this texture. + */ + public MagFilter getMagFilter() { + return magnificationFilter; + } + + /** + * @param magnificationFilter + * the new MagnificationFilter for this texture. + * @throws IllegalArgumentException + * if magnificationFilter is null + */ + public void setMagFilter(MagFilter magnificationFilter) { + if (magnificationFilter == null) { + throw new IllegalArgumentException( + "magnificationFilter can not be null."); + } + this.magnificationFilter = magnificationFilter; + } + + /** + * @return The ShadowCompareMode of this texture. + * @see ShadowCompareMode + */ + public ShadowCompareMode getShadowCompareMode(){ + return shadowCompareMode; + } + + /** + * @param compareMode + * the new ShadowCompareMode for this texture. + * @throws IllegalArgumentException + * if compareMode is null + * @see ShadowCompareMode + */ + public void setShadowCompareMode(ShadowCompareMode compareMode){ + if (compareMode == null){ + throw new IllegalArgumentException( + "compareMode can not be null."); + } + this.shadowCompareMode = compareMode; + } + + /** + * setImage sets the image object that defines the texture. + * + * @param image + * the image that defines the texture. + */ + public void setImage(GlImage image) { + this.image = image; + + // Test if mipmap generation required. + setMinFilter(getMinFilter()); + } + + /** + * @param key The texture key that was used to load this texture + */ + @Override + public void setKey(AssetKey key){ + this.key = (TextureKey) key; + } + + @Override + public AssetKey getKey(){ + return this.key; + } + + @Override + public GlTexture getView() { + return this; + } + + @Override + public GlImage getImage() { + return image; + } + + /** + * setWrap sets the wrap mode of this texture for a + * particular axis. + * + * @param axis + * the texture axis to apply the wrap mode to. + * @param mode + * the wrap mode for the given axis of the texture. + * @throws IllegalArgumentException + * if axis or mode are null or invalid for this type of texture + */ + public abstract void setWrap(WrapAxis axis, WrapMode mode); + + /** + * setWrap sets the wrap mode of this texture for all axis. + * + * @param mode + * the wrap mode for the given axis of the texture. + * @throws IllegalArgumentException + * if mode is null or invalid for this type of texture + */ + public abstract void setWrap(WrapMode mode); + + /** + * getWrap returns the wrap mode for a given coordinate axis + * on this texture. + * + * @param axis + * the axis to return for + * @return the wrap mode of the texture. + * @throws IllegalArgumentException + * if axis is null or invalid for this type of texture + */ + public abstract WrapMode getWrap(WrapAxis axis); + + public abstract Type getType(); + + @Override + public IntEnum getViewType() { + return ImageView.Type.of(getType()); + } + + @Override + public int getBaseMipmap() { + return 0; + } + + @Override + public int getMipmapCount() { + return 0; + } + + @Override + public int getBaseLayer() { + return 0; + } + + @Override + public int getLayerCount() { + return 0; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * @return the anisotropic filtering level for this texture. Default value + * is 0 (use value from config), + * 1 means 1x (no anisotropy), 2 means x2, 4 is x4, etc. + */ + public int getAnisotropicFilter() { + return anisotropicFilter; + } + + /** + * @param level + * the anisotropic filtering level for this texture. + */ + public void setAnisotropicFilter(int level) { + anisotropicFilter = Math.max(0, level); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append("[name=").append(name); + if (image != null) { + sb.append(", image=").append(image.toString()); + } + + sb.append("]"); + return sb.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final GlTexture other = (GlTexture) obj; + + // NOTE: Since images are generally considered unique assets in jME3, + // using the image's equals() implementation is not necessary here + // (would be too slow) + if (this.image != other.image) { + return false; + } + if (this.minificationFilter != other.minificationFilter) { + return false; + } + if (this.magnificationFilter != other.magnificationFilter) { + return false; + } + if (this.shadowCompareMode != other.shadowCompareMode) { + return false; + } + if (this.anisotropicFilter != other.anisotropicFilter) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + // NOTE: Since images are generally considered unique assets in jME3, + // using the image's hashCode() implementation is not necessary here + // (would be too slow) + hash = 67 * hash + (this.image != null ? System.identityHashCode(this.image) : 0); + hash = 67 * hash + (this.minificationFilter != null ? this.minificationFilter.hashCode() : 0); + hash = 67 * hash + (this.magnificationFilter != null ? this.magnificationFilter.hashCode() : 0); + hash = 67 * hash + (this.shadowCompareMode != null ? this.shadowCompareMode.hashCode() : 0); + hash = 67 * hash + this.anisotropicFilter; + return hash; + } + + /** Retrieve a basic clone of this Texture (ie, clone everything but the + * image data, which is shared) + * + * @param rVal storage for the clone (not null, modified) + * @return Texture + * + * @deprecated Use {@link GlTexture#clone()} instead. + */ + @Deprecated + public GlTexture createSimpleClone(GlTexture rVal) { + rVal.setMinFilter(minificationFilter); + rVal.setMagFilter(magnificationFilter); + rVal.setShadowCompareMode(shadowCompareMode); + rVal.setAnisotropicFilter(anisotropicFilter); + rVal.setImage(image); // NOT CLONED. + rVal.setKey(key); + rVal.setName(name); + return rVal; + } + + /** + * @return a new Texture + * @deprecated Use {@link GlTexture#clone()} instead. + */ + @Deprecated + public abstract GlTexture createSimpleClone(); + + @Override + public void write(JmeExporter e) throws IOException { + OutputCapsule capsule = e.getCapsule(this); + capsule.write(name, "name", null); + + if (key == null){ + // no texture key is set, try to save image instead then + capsule.write(image, "image", null); + }else{ + capsule.write(key, "key", null); + } + + capsule.write(anisotropicFilter, "anisotropicFilter", 1); + capsule.write(minificationFilter, "minificationFilter", + MinFilter.BilinearNoMipMaps); + capsule.write(magnificationFilter, "magnificationFilter", + MagFilter.Bilinear); + } + + @Override + public void read(JmeImporter importer) throws IOException { + InputCapsule capsule = importer.getCapsule(this); + name = capsule.readString("name", null); + key = (TextureKey) capsule.readSavable("key", null); + + // load texture from key, if available + if (key != null) { + // key is available, so try the texture from there. + try { + GlTexture loadedTex = importer.getAssetManager().loadTexture(key); + image = loadedTex.getImage(); + } catch (AssetNotFoundException ex){ + Logger.getLogger(GlTexture.class.getName()).log(Level.SEVERE, "Cannot locate texture {0}", key); + image = PlaceholderAssets.getPlaceholderImage(importer.getAssetManager()); + } + }else{ + // no key is set on the texture. Attempt to load an embedded image + image = (GlImage) capsule.readSavable("image", null); + if (image == null){ + // TODO: what to print out here? the texture has no key or data, there's no useful information .. + // assume texture.name is set even though the key is null + Logger.getLogger(GlTexture.class.getName()) + .log(Level.SEVERE, "Cannot load embedded image {0}", toString()); + } + } + + setAnisotropicFilter(capsule.readInt("anisotropicFilter", 1)); + setMinFilter(capsule.readEnum("minificationFilter", + MinFilter.class, + MinFilter.BilinearNoMipMaps)); + setMagFilter(capsule.readEnum("magnificationFilter", + MagFilter.class, MagFilter.Bilinear)); + } +} diff --git a/jme3-core/src/main/java/com/jme3/texture/ImageView.java b/jme3-core/src/main/java/com/jme3/texture/ImageView.java new file mode 100644 index 0000000000..311db00d82 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/texture/ImageView.java @@ -0,0 +1,57 @@ +package com.jme3.texture; + +import com.jme3.vulkan.images.GpuImage; +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public interface ImageView { + + enum Type implements IntEnum { + + OneDemensional(VK_IMAGE_VIEW_TYPE_1D), + TwoDemensional(VK_IMAGE_VIEW_TYPE_2D), + ThreeDemensional(VK_IMAGE_VIEW_TYPE_3D), + OneDemensionalArray(VK_IMAGE_VIEW_TYPE_1D_ARRAY), + TwoDemensionalArray(VK_IMAGE_VIEW_TYPE_2D_ARRAY), + Cube(VK_IMAGE_VIEW_TYPE_CUBE), + CubeArray(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); + + private final int vkEnum; + + Type(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + public static Type of(GlTexture.Type type) { + switch (type) { + case TwoDimensional: return TwoDemensional; + case TwoDimensionalArray: return TwoDemensionalArray; + case ThreeDimensional: return ThreeDemensional; + case CubeMap: return Cube; + default: throw new UnsupportedOperationException("No conversion implemented for " + type); + } + } + + } + + long getId(); + + T getImage(); + + IntEnum getViewType(); + + int getBaseMipmap(); + + int getMipmapCount(); + + int getBaseLayer(); + + int getLayerCount(); + +} diff --git a/jme3-core/src/main/java/com/jme3/texture/Texture.java b/jme3-core/src/main/java/com/jme3/texture/Texture.java index 3ba9b78128..fabca33f88 100644 --- a/jme3-core/src/main/java/com/jme3/texture/Texture.java +++ b/jme3-core/src/main/java/com/jme3/texture/Texture.java @@ -1,647 +1,15 @@ -/* - * Copyright (c) 2009-2021 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ package com.jme3.texture; -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetNotFoundException; -import com.jme3.asset.CloneableSmartAsset; -import com.jme3.asset.TextureKey; -import com.jme3.export.*; -import com.jme3.util.PlaceholderAssets; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; +import com.jme3.vulkan.images.GpuImage; -/** - * Texture defines a texture object to be used to display an - * image on a piece of geometry. The image to be displayed is defined by the - * Image class. All attributes required for texture mapping are - * contained within this class. This includes mipmapping if desired, - * magnificationFilter options, apply options and correction options. Default - * values are as follows: minificationFilter - NearestNeighborNoMipMaps, - * magnificationFilter - NearestNeighbor, wrap - EdgeClamp on S,T and R, apply - - * Modulate, environment - None. - * - * @see com.jme3.texture.Image - * @author Mark Powell - * @author Joshua Slack - * @version $Id: Texture.java 4131 2009-03-19 20:15:28Z blaine.dev $ - */ -public abstract class Texture implements CloneableSmartAsset, Savable, Cloneable { +public interface Texture , I extends GpuImage> { - public enum Type { + long getId(); - /** - * Two dimensional texture (default). A rectangle. - */ - TwoDimensional, + V getView(); - /** - * An array of two-dimensional textures. - */ - TwoDimensionalArray, - - /** - * Three-dimensional texture. (A cube) - */ - ThreeDimensional, - - /** - * A set of 6 TwoDimensional textures arranged as faces of a cube facing - * inwards. - */ - CubeMap; + default I getImage() { + return getView().getImage(); } - public enum MinFilter { - - /** - * Nearest neighbor interpolation is the fastest and crudest filtering - * method - it simply uses the color of the texel closest to the pixel - * center for the pixel color. While fast, this results in aliasing and - * shimmering during minification. (GL equivalent: GL_NEAREST) - */ - NearestNoMipMaps(false), - - /** - * In this method the four nearest texels to the pixel center are - * sampled (at texture level 0), and their colors are combined by - * weighted averages. Though smoother, without mipmaps it suffers the - * same aliasing and shimmering problems as nearest - * NearestNeighborNoMipMaps. (GL equivalent: GL_LINEAR) - */ - BilinearNoMipMaps(false), - - /** - * Same as NearestNeighborNoMipMaps except that instead of using samples - * from texture level 0, the closest mipmap level is chosen based on - * distance. This reduces the aliasing and shimmering significantly, but - * does not help with blockiness. (GL equivalent: - * GL_NEAREST_MIPMAP_NEAREST) - */ - NearestNearestMipMap(true), - - /** - * Same as BilinearNoMipMaps except that instead of using samples from - * texture level 0, the closest mipmap level is chosen based on - * distance. By using mipmapping we avoid the aliasing and shimmering - * problems of BilinearNoMipMaps. (GL equivalent: - * GL_LINEAR_MIPMAP_NEAREST) - */ - BilinearNearestMipMap(true), - - /** - * Similar to NearestNeighborNoMipMaps except that instead of using - * samples from texture level 0, a sample is chosen from each of the - * closest (by distance) two mipmap levels. A weighted average of these - * two samples is returned. (GL equivalent: GL_NEAREST_MIPMAP_LINEAR) - */ - NearestLinearMipMap(true), - - /** - * Trilinear filtering is a remedy to a common artifact seen in - * mipmapped bilinearly filtered images: an abrupt and very noticeable - * change in quality at boundaries where the renderer switches from one - * mipmap level to the next. Trilinear filtering solves this by doing a - * texture lookup and bilinear filtering on the two closest mipmap - * levels (one higher and one lower quality), and then linearly - * interpolating the results. This results in a smooth degradation of - * texture quality as distance from the viewer increases, rather than a - * series of sudden drops. Of course, closer than Level 0 there is only - * one mipmap level available, and the algorithm reverts to bilinear - * filtering (GL equivalent: GL_LINEAR_MIPMAP_LINEAR) - */ - Trilinear(true); - - private final boolean usesMipMapLevels; - - private MinFilter(boolean usesMipMapLevels) { - this.usesMipMapLevels = usesMipMapLevels; - } - - public boolean usesMipMapLevels() { - return usesMipMapLevels; - } - } - - public enum MagFilter { - - /** - * Nearest neighbor interpolation is the fastest and crudest filtering - * mode - it simply uses the color of the texel closest to the pixel - * center for the pixel color. While fast, this results in texture - * 'blockiness' during magnification. (GL equivalent: GL_NEAREST) - */ - Nearest, - - /** - * In this mode the four nearest texels to the pixel center are sampled - * (at the closest mipmap level), and their colors are combined by - * weighted average according to distance. This removes the 'blockiness' - * seen during magnification, as there is now a smooth gradient of color - * change from one texel to the next, instead of an abrupt jump as the - * pixel center crosses the texel boundary. (GL equivalent: GL_LINEAR) - */ - Bilinear; - - } - - public enum WrapMode { - /** - * Only the fractional portion of the coordinate is considered. - */ - Repeat, - - /** - * Only the fractional portion of the coordinate is considered, but if - * the integer portion is odd, we'll use 1 - the fractional portion. - * (Introduced around OpenGL1.4) Falls back on Repeat if not supported. - */ - MirroredRepeat, - - /** - * coordinate will be clamped to [0,1] - * - * @deprecated Not supported by OpenGL 3 - */ - @Deprecated - Clamp, - /** - * mirrors and clamps the texture coordinate, where mirroring and - * clamping a value f computes: - * mirrorClamp(f) = min(1, max(1/(2*N), - * abs(f))) where N - * is the size of the one-, two-, or three-dimensional texture image in - * the direction of wrapping. (Introduced after OpenGL1.4) Falls back on - * Clamp if not supported. - * - * @deprecated Not supported by OpenGL 3 - */ - @Deprecated - MirrorClamp, - - /** - * coordinate will be clamped to the range [-1/(2N), 1 + 1/(2N)] where N - * is the size of the texture in the direction of clamping. Falls back - * on Clamp if not supported. - * - * @deprecated Not supported by OpenGL 3 or OpenGL ES 2 - */ - @Deprecated - BorderClamp, - /** - * Wrap mode MIRROR_CLAMP_TO_BORDER_EXT mirrors and clamps to border the - * texture coordinate, where mirroring and clamping to border a value f - * computes: - * mirrorClampToBorder(f) = min(1+1/(2*N), max(1/(2*N), abs(f))) - * where N is the size of the one-, two-, or three-dimensional texture - * image in the direction of wrapping. (Introduced after OpenGL1.4) - * Falls back on BorderClamp if not supported. - * - * @deprecated Not supported by OpenGL 3 - */ - @Deprecated - MirrorBorderClamp, - /** - * coordinate will be clamped to the range [1/(2N), 1 - 1/(2N)] where N - * is the size of the texture in the direction of clamping. Falls back - * on Clamp if not supported. - */ - EdgeClamp, - - /** - * mirrors and clamps to edge the texture coordinate, where mirroring - * and clamping to edge a value f computes: - * mirrorClampToEdge(f) = min(1-1/(2*N), max(1/(2*N), abs(f))) - * where N is the size of the one-, two-, or three-dimensional texture - * image in the direction of wrapping. (Introduced after OpenGL1.4) - * Falls back on EdgeClamp if not supported. - * - * @deprecated Not supported by OpenGL 3 - */ - @Deprecated - MirrorEdgeClamp; - } - - public enum WrapAxis { - /** - * S wrapping (u or "horizontal" wrap) - */ - S, - /** - * T wrapping (v or "vertical" wrap) - */ - T, - /** - * R wrapping (w or "depth" wrap) - */ - R; - } - - /** - * If this texture is a depth texture (the format is Depth*) then - * this value may be used to compare the texture depth to the R texture - * coordinate. - */ - public enum ShadowCompareMode { - /** - * Shadow comparison mode is disabled. - * Texturing is done normally. - */ - Off, - - /** - * {@code - * Compares the 3rd texture coordinate R to the value - * in this depth texture. If R <= texture value then result is 1.0, - * otherwise, result is 0.0. If filtering is set to bilinear or trilinear - * the implementation may sample the texture multiple times to provide - * smoother results in the range [0, 1].} - */ - LessOrEqual, - - /** - * {@code - * Compares the 3rd texture coordinate R to the value - * in this depth texture. If R >= texture value then result is 1.0, - * otherwise, result is 0.0. If filtering is set to bilinear or trilinear - * the implementation may sample the texture multiple times to provide - * smoother results in the range [0, 1].} - */ - GreaterOrEqual - } - - /** - * The name of the texture (if loaded as a resource). - */ - private String name = null; - - /** - * The image stored in the texture - */ - private Image image = null; - - /** - * The texture key allows to reload a texture from a file - * if needed. - */ - private TextureKey key = null; - - private MinFilter minificationFilter = MinFilter.BilinearNoMipMaps; - private MagFilter magnificationFilter = MagFilter.Bilinear; - private ShadowCompareMode shadowCompareMode = ShadowCompareMode.Off; - private int anisotropicFilter; - - /** - * @return A cloned Texture object. - */ - @Override - public Texture clone(){ - try { - return (Texture) super.clone(); - } catch (CloneNotSupportedException ex) { - throw new AssertionError(); - } - } - - /** - * Constructor instantiates a new Texture object with default - * attributes. - */ - public Texture() { - } - - /** - * @return the MinificationFilterMode of this texture. - */ - public MinFilter getMinFilter() { - return minificationFilter; - } - - /** - * @param minificationFilter - * the new MinificationFilterMode for this texture. - * @throws IllegalArgumentException - * if minificationFilter is null - */ - public void setMinFilter(MinFilter minificationFilter) { - if (minificationFilter == null) { - throw new IllegalArgumentException( - "minificationFilter can not be null."); - } - this.minificationFilter = minificationFilter; - if (minificationFilter.usesMipMapLevels() && image != null && !image.isGeneratedMipmapsRequired() && !image.hasMipmaps()) { - image.setNeedGeneratedMipmaps(); - } - } - - /** - * @return the MagnificationFilterMode of this texture. - */ - public MagFilter getMagFilter() { - return magnificationFilter; - } - - /** - * @param magnificationFilter - * the new MagnificationFilter for this texture. - * @throws IllegalArgumentException - * if magnificationFilter is null - */ - public void setMagFilter(MagFilter magnificationFilter) { - if (magnificationFilter == null) { - throw new IllegalArgumentException( - "magnificationFilter can not be null."); - } - this.magnificationFilter = magnificationFilter; - } - - /** - * @return The ShadowCompareMode of this texture. - * @see ShadowCompareMode - */ - public ShadowCompareMode getShadowCompareMode(){ - return shadowCompareMode; - } - - /** - * @param compareMode - * the new ShadowCompareMode for this texture. - * @throws IllegalArgumentException - * if compareMode is null - * @see ShadowCompareMode - */ - public void setShadowCompareMode(ShadowCompareMode compareMode){ - if (compareMode == null){ - throw new IllegalArgumentException( - "compareMode can not be null."); - } - this.shadowCompareMode = compareMode; - } - - /** - * setImage sets the image object that defines the texture. - * - * @param image - * the image that defines the texture. - */ - public void setImage(Image image) { - this.image = image; - - // Test if mipmap generation required. - setMinFilter(getMinFilter()); - } - - /** - * @param key The texture key that was used to load this texture - */ - @Override - public void setKey(AssetKey key){ - this.key = (TextureKey) key; - } - - @Override - public AssetKey getKey(){ - return this.key; - } - - /** - * getImage returns the image data that makes up this - * texture. If no image data has been set, this will return null. - * - * @return the image data that makes up the texture. - */ - public Image getImage() { - return image; - } - - /** - * setWrap sets the wrap mode of this texture for a - * particular axis. - * - * @param axis - * the texture axis to apply the wrap mode to. - * @param mode - * the wrap mode for the given axis of the texture. - * @throws IllegalArgumentException - * if axis or mode are null or invalid for this type of texture - */ - public abstract void setWrap(WrapAxis axis, WrapMode mode); - - /** - * setWrap sets the wrap mode of this texture for all axis. - * - * @param mode - * the wrap mode for the given axis of the texture. - * @throws IllegalArgumentException - * if mode is null or invalid for this type of texture - */ - public abstract void setWrap(WrapMode mode); - - /** - * getWrap returns the wrap mode for a given coordinate axis - * on this texture. - * - * @param axis - * the axis to return for - * @return the wrap mode of the texture. - * @throws IllegalArgumentException - * if axis is null or invalid for this type of texture - */ - public abstract WrapMode getWrap(WrapAxis axis); - - public abstract Type getType(); - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - /** - * @return the anisotropic filtering level for this texture. Default value - * is 0 (use value from config), - * 1 means 1x (no anisotropy), 2 means x2, 4 is x4, etc. - */ - public int getAnisotropicFilter() { - return anisotropicFilter; - } - - /** - * @param level - * the anisotropic filtering level for this texture. - */ - public void setAnisotropicFilter(int level) { - anisotropicFilter = Math.max(0, level); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName()); - sb.append("[name=").append(name); - if (image != null) { - sb.append(", image=").append(image.toString()); - } - - sb.append("]"); - return sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Texture other = (Texture) obj; - - // NOTE: Since images are generally considered unique assets in jME3, - // using the image's equals() implementation is not necessary here - // (would be too slow) - if (this.image != other.image) { - return false; - } - if (this.minificationFilter != other.minificationFilter) { - return false; - } - if (this.magnificationFilter != other.magnificationFilter) { - return false; - } - if (this.shadowCompareMode != other.shadowCompareMode) { - return false; - } - if (this.anisotropicFilter != other.anisotropicFilter) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 5; - // NOTE: Since images are generally considered unique assets in jME3, - // using the image's hashCode() implementation is not necessary here - // (would be too slow) - hash = 67 * hash + (this.image != null ? System.identityHashCode(this.image) : 0); - hash = 67 * hash + (this.minificationFilter != null ? this.minificationFilter.hashCode() : 0); - hash = 67 * hash + (this.magnificationFilter != null ? this.magnificationFilter.hashCode() : 0); - hash = 67 * hash + (this.shadowCompareMode != null ? this.shadowCompareMode.hashCode() : 0); - hash = 67 * hash + this.anisotropicFilter; - return hash; - } - - /** Retrieve a basic clone of this Texture (ie, clone everything but the - * image data, which is shared) - * - * @param rVal storage for the clone (not null, modified) - * @return Texture - * - * @deprecated Use {@link Texture#clone()} instead. - */ - @Deprecated - public Texture createSimpleClone(Texture rVal) { - rVal.setMinFilter(minificationFilter); - rVal.setMagFilter(magnificationFilter); - rVal.setShadowCompareMode(shadowCompareMode); - rVal.setAnisotropicFilter(anisotropicFilter); - rVal.setImage(image); // NOT CLONED. - rVal.setKey(key); - rVal.setName(name); - return rVal; - } - - /** - * @return a new Texture - * @deprecated Use {@link Texture#clone()} instead. - */ - @Deprecated - public abstract Texture createSimpleClone(); - - @Override - public void write(JmeExporter e) throws IOException { - OutputCapsule capsule = e.getCapsule(this); - capsule.write(name, "name", null); - - if (key == null){ - // no texture key is set, try to save image instead then - capsule.write(image, "image", null); - }else{ - capsule.write(key, "key", null); - } - - capsule.write(anisotropicFilter, "anisotropicFilter", 1); - capsule.write(minificationFilter, "minificationFilter", - MinFilter.BilinearNoMipMaps); - capsule.write(magnificationFilter, "magnificationFilter", - MagFilter.Bilinear); - } - - @Override - public void read(JmeImporter importer) throws IOException { - InputCapsule capsule = importer.getCapsule(this); - name = capsule.readString("name", null); - key = (TextureKey) capsule.readSavable("key", null); - - // load texture from key, if available - if (key != null) { - // key is available, so try the texture from there. - try { - Texture loadedTex = importer.getAssetManager().loadTexture(key); - image = loadedTex.getImage(); - } catch (AssetNotFoundException ex){ - Logger.getLogger(Texture.class.getName()).log(Level.SEVERE, "Cannot locate texture {0}", key); - image = PlaceholderAssets.getPlaceholderImage(importer.getAssetManager()); - } - }else{ - // no key is set on the texture. Attempt to load an embedded image - image = (Image) capsule.readSavable("image", null); - if (image == null){ - // TODO: what to print out here? the texture has no key or data, there's no useful information .. - // assume texture.name is set even though the key is null - Logger.getLogger(Texture.class.getName()) - .log(Level.SEVERE, "Cannot load embedded image {0}", toString()); - } - } - - setAnisotropicFilter(capsule.readInt("anisotropicFilter", 1)); - setMinFilter(capsule.readEnum("minificationFilter", - MinFilter.class, - MinFilter.BilinearNoMipMaps)); - setMagFilter(capsule.readEnum("magnificationFilter", - MagFilter.class, MagFilter.Bilinear)); - } } diff --git a/jme3-core/src/main/java/com/jme3/texture/Texture2D.java b/jme3-core/src/main/java/com/jme3/texture/Texture2D.java index ab633aed49..8094e3cb1f 100644 --- a/jme3-core/src/main/java/com/jme3/texture/Texture2D.java +++ b/jme3-core/src/main/java/com/jme3/texture/Texture2D.java @@ -36,12 +36,15 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.texture.image.ColorSpace; +import com.jme3.vulkan.images.GpuImage; +import com.jme3.vulkan.util.IntEnum; + import java.io.IOException; /** * @author Joshua Slack */ -public class Texture2D extends Texture { +public class Texture2D extends GlTexture { private WrapMode wrapS = WrapMode.EdgeClamp; private WrapMode wrapT = WrapMode.EdgeClamp; @@ -57,7 +60,7 @@ public Texture2D(){ * Creates a new two-dimensional texture using the given image. * @param img The image to use. */ - public Texture2D(Image img){ + public Texture2D(GlImage img){ super(); setImage(img); if (img.getData(0) == null) { @@ -76,8 +79,8 @@ public Texture2D(Image img){ * @param height the desired height (in pixels) * @param format the desired format */ - public Texture2D(int width, int height, Image.Format format){ - this(new Image(format, width, height, null, ColorSpace.Linear)); + public Texture2D(int width, int height, GlImage.Format format){ + this(new GlImage(format, width, height, null, ColorSpace.Linear)); } /** @@ -91,20 +94,20 @@ public Texture2D(int width, int height, Image.Format format){ * @param numSamples the desired degree of multi-sampling (≥1) * @param format the desired format */ - public Texture2D(int width, int height, int numSamples, Image.Format format){ - this(new Image(format, width, height, null, ColorSpace.Linear)); + public Texture2D(int width, int height, int numSamples, GlImage.Format format){ + this(new GlImage(format, width, height, null, ColorSpace.Linear)); getImage().setMultiSamples(numSamples); } @Override - public Texture createSimpleClone() { + public GlTexture createSimpleClone() { Texture2D clone = new Texture2D(); createSimpleClone(clone); return clone; } @Override - public Texture createSimpleClone(Texture rVal) { + public GlTexture createSimpleClone(GlTexture rVal) { rVal.setWrap(WrapAxis.S, wrapS); rVal.setWrap(WrapAxis.T, wrapT); return super.createSimpleClone(rVal); diff --git a/jme3-core/src/main/java/com/jme3/texture/Texture3D.java b/jme3-core/src/main/java/com/jme3/texture/Texture3D.java index bb12a858dd..22b44775a4 100644 --- a/jme3-core/src/main/java/com/jme3/texture/Texture3D.java +++ b/jme3-core/src/main/java/com/jme3/texture/Texture3D.java @@ -41,7 +41,7 @@ /** * @author Maarten Steur */ -public class Texture3D extends Texture { +public class Texture3D extends GlTexture { private WrapMode wrapS = WrapMode.EdgeClamp; private WrapMode wrapT = WrapMode.EdgeClamp; @@ -58,10 +58,10 @@ public Texture3D() { * Creates a new three-dimensional texture using the given image. * @param img The image to use. */ - public Texture3D(Image img) { + public Texture3D(GlImage img) { super(); setImage(img); - if (img.getFormat().isDepthFormat()) { + if (img.getGlFormat().isDepthFormat()) { setMagFilter(MagFilter.Nearest); setMinFilter(MinFilter.NearestNoMipMaps); } @@ -78,8 +78,8 @@ public Texture3D(Image img) { * @param depth the desired depth * @param format the desired format */ - public Texture3D(int width, int height, int depth, Image.Format format) { - this(new Image(format, width, height, depth, null, ColorSpace.Linear)); + public Texture3D(int width, int height, int depth, GlImage.Format format) { + this(new GlImage(format, width, height, depth, null, ColorSpace.Linear)); } /** @@ -94,20 +94,20 @@ public Texture3D(int width, int height, int depth, Image.Format format) { * @param numSamples the desired degree of multi-sampling (≥1) * @param format the desired format */ - public Texture3D(int width, int height, int depth, int numSamples, Image.Format format) { - this(new Image(format, width, height, depth, null, ColorSpace.Linear)); + public Texture3D(int width, int height, int depth, int numSamples, GlImage.Format format) { + this(new GlImage(format, width, height, depth, null, ColorSpace.Linear)); getImage().setMultiSamples(numSamples); } @Override - public Texture createSimpleClone() { + public GlTexture createSimpleClone() { Texture3D clone = new Texture3D(); createSimpleClone(clone); return clone; } @Override - public Texture createSimpleClone(Texture rVal) { + public GlTexture createSimpleClone(GlTexture rVal) { rVal.setWrap(WrapAxis.S, wrapS); rVal.setWrap(WrapAxis.T, wrapT); rVal.setWrap(WrapAxis.R, wrapR); diff --git a/jme3-core/src/main/java/com/jme3/texture/TextureArray.java b/jme3-core/src/main/java/com/jme3/texture/TextureArray.java index e839399c33..32416099ac 100644 --- a/jme3-core/src/main/java/com/jme3/texture/TextureArray.java +++ b/jme3-core/src/main/java/com/jme3/texture/TextureArray.java @@ -35,7 +35,7 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.image.ColorSpace; import java.io.IOException; import java.util.Arrays; @@ -48,7 +48,7 @@ * renderManager.getRenderer().getCaps().contains(Caps.TextureArray) * @author phate666 */ -public class TextureArray extends Texture { +public class TextureArray extends GlTexture { private WrapMode wrapS = WrapMode.EdgeClamp; private WrapMode wrapT = WrapMode.EdgeClamp; @@ -70,22 +70,22 @@ public TextureArray() { * * @param images the images to use (not null) */ - public TextureArray(List images) { + public TextureArray(List images) { super(); int width = images.get(0).getWidth(); int height = images.get(0).getHeight(); - Format format = images.get(0).getFormat(); + Format format = images.get(0).getGlFormat(); ColorSpace colorSpace = images.get(0).getColorSpace(); int[] mipMapSizes = images.get(0).getMipMapSizes(); - Image arrayImage = new Image(format, width, height, null, colorSpace); + GlImage arrayImage = new GlImage(format, width, height, null, colorSpace); arrayImage.setMipMapSizes(mipMapSizes); - for (Image img : images) { + for (GlImage img : images) { if (img.getHeight() != height || img.getWidth() != width) { throw new IllegalArgumentException("Images in texture array must have same dimensions"); } - if (img.getFormat() != format) { + if (img.getGlFormat() != format) { throw new IllegalArgumentException("Images in texture array must have same format"); } if (!Arrays.equals(mipMapSizes, img.getMipMapSizes())) { @@ -99,14 +99,14 @@ public TextureArray(List images) { } @Override - public Texture createSimpleClone() { + public GlTexture createSimpleClone() { TextureArray clone = new TextureArray(); createSimpleClone(clone); return clone; } @Override - public Texture createSimpleClone(Texture rVal) { + public GlTexture createSimpleClone(GlTexture rVal) { rVal.setWrap(WrapAxis.S, wrapS); rVal.setWrap(WrapAxis.T, wrapT); return super.createSimpleClone(rVal); diff --git a/jme3-core/src/main/java/com/jme3/texture/TextureCubeMap.java b/jme3-core/src/main/java/com/jme3/texture/TextureCubeMap.java index 40e6c037c3..01d3165d0c 100644 --- a/jme3-core/src/main/java/com/jme3/texture/TextureCubeMap.java +++ b/jme3-core/src/main/java/com/jme3/texture/TextureCubeMap.java @@ -55,7 +55,7 @@ * * @author Joshua Slack */ -public class TextureCubeMap extends Texture { +public class TextureCubeMap extends GlTexture { private WrapMode wrapS = WrapMode.EdgeClamp; private WrapMode wrapT = WrapMode.EdgeClamp; @@ -74,32 +74,32 @@ public TextureCubeMap() { super(); } - public TextureCubeMap(Image img) { + public TextureCubeMap(GlImage img) { super(); setImage(img); } - public TextureCubeMap(int width, int height, Image.Format format) { + public TextureCubeMap(int width, int height, GlImage.Format format) { this(createEmptyLayeredImage(width, height, 6, format)); } - private static Image createEmptyLayeredImage(int width, int height, - int layerCount, Image.Format format) { + private static GlImage createEmptyLayeredImage(int width, int height, + int layerCount, GlImage.Format format) { ArrayList layers = new ArrayList<>(); for (int i = 0; i < layerCount; i++) { layers.add(null); } - Image image = new Image(format, width, height, 0, layers, ColorSpace.Linear); + GlImage image = new GlImage(format, width, height, 0, layers, ColorSpace.Linear); return image; } @Override - public Texture createSimpleClone() { + public GlTexture createSimpleClone() { return createSimpleClone(new TextureCubeMap()); } @Override - public Texture createSimpleClone(Texture rVal) { + public GlTexture createSimpleClone(GlTexture rVal) { rVal.setWrap(WrapAxis.S, wrapS); rVal.setWrap(WrapAxis.T, wrapT); rVal.setWrap(WrapAxis.R, wrapR); diff --git a/jme3-core/src/main/java/com/jme3/texture/TextureImage.java b/jme3-core/src/main/java/com/jme3/texture/TextureImage.java index 31b705fa5d..9a86aae851 100644 --- a/jme3-core/src/main/java/com/jme3/texture/TextureImage.java +++ b/jme3-core/src/main/java/com/jme3/texture/TextureImage.java @@ -104,24 +104,24 @@ public int getGlEnum() { } - private Texture texture; + private GlTexture texture; private int level, layer; private Access access; private boolean updateFlag = true; - public TextureImage(Texture texture) { + public TextureImage(GlTexture texture) { this(texture, 0, -1, Access.ReadWrite); } - public TextureImage(Texture texture, Access access) { + public TextureImage(GlTexture texture, Access access) { this(texture, 0, -1, access); } - public TextureImage(Texture texture, int level, int layer) { + public TextureImage(GlTexture texture, int level, int layer) { this(texture, level, layer, Access.ReadWrite); } - public TextureImage(Texture texture, int level, int layer, Access access) { + public TextureImage(GlTexture texture, int level, int layer, Access access) { this.texture = Objects.requireNonNull(texture, "Underlying texture cannot be null"); this.level = level; this.layer = layer; @@ -143,9 +143,9 @@ public TextureImage(Texture texture, int level, int layer, Access access) { * @param unit texture unit to bind to */ public void bindImage(GL4 gl4, TextureUtil texUtil, int unit) { - Image img = texture.getImage(); - gl4.glBindImageTexture(unit, img.getId(), level, isLayered(), Math.max(layer, 0), - access.getGlEnum(), texUtil.getImageFormat(img.getFormat(), false).internalFormat); + GlImage img = texture.getImage(); + gl4.glBindImageTexture(unit, img.getNativeObject(), level, isLayered(), Math.max(layer, 0), + access.getGlEnum(), texUtil.getImageFormat(img.getGlFormat(), false).internalFormat); } /** @@ -172,7 +172,7 @@ public boolean clearUpdateNeeded() { * * @param texture wrapped texture (not null) */ - public void setTexture(Texture texture) { + public void setTexture(GlTexture texture) { Objects.requireNonNull(texture, "Wrapped texture cannot be null."); if (this.texture != texture) { this.texture = texture; @@ -235,7 +235,7 @@ public void setAccess(Access access) { * * @return underlying texture */ - public Texture getTexture() { + public GlTexture getTexture() { return texture; } @@ -244,7 +244,7 @@ public Texture getTexture() { * * @return */ - public Image getImage() { + public GlImage getImage() { return texture.getImage(); } @@ -253,8 +253,8 @@ public Image getImage() { * * @return */ - public Image.Format getFormat() { - return texture.getImage().getFormat(); + public GlImage.Format getFormat() { + return texture.getImage().getGlFormat(); } /** @@ -263,7 +263,7 @@ public Image.Format getFormat() { * @return */ public int getImageId() { - return texture.getImage().getId(); + return texture.getImage().getNativeObject(); } /** diff --git a/jme3-core/src/main/java/com/jme3/texture/TextureProcessor.java b/jme3-core/src/main/java/com/jme3/texture/TextureProcessor.java index c0dc0ad359..6d309d9cbc 100644 --- a/jme3-core/src/main/java/com/jme3/texture/TextureProcessor.java +++ b/jme3-core/src/main/java/com/jme3/texture/TextureProcessor.java @@ -41,13 +41,13 @@ public class TextureProcessor implements AssetProcessor { @Override public Object postProcess(AssetKey key, Object obj) { TextureKey texKey = (TextureKey) key; - Image img = (Image) obj; + GlImage img = (GlImage) obj; if (img == null) { return null; } - Texture tex; - if (texKey.getTextureTypeHint() == Texture.Type.CubeMap) { + GlTexture tex; + if (texKey.getTextureTypeHint() == GlTexture.Type.CubeMap) { if (texKey.isFlipY()) { // also flip -y and +y image in cubemap ByteBuffer pos_y = img.getData(2); @@ -55,7 +55,7 @@ public Object postProcess(AssetKey key, Object obj) { img.setData(3, pos_y); } tex = new TextureCubeMap(); - } else if (texKey.getTextureTypeHint() == Texture.Type.ThreeDimensional) { + } else if (texKey.getTextureTypeHint() == GlTexture.Type.ThreeDimensional) { tex = new Texture3D(); } else { tex = new Texture2D(); @@ -64,7 +64,7 @@ public Object postProcess(AssetKey key, Object obj) { // enable mipmaps if image has them // or generate them if requested by user if (img.hasMipmaps() || texKey.isGenerateMips()) { - tex.setMinFilter(Texture.MinFilter.Trilinear); + tex.setMinFilter(GlTexture.MinFilter.Trilinear); } tex.setAnisotropicFilter(texKey.getAnisotropy()); @@ -75,7 +75,7 @@ public Object postProcess(AssetKey key, Object obj) { @Override public Object createClone(Object obj) { - Texture tex = (Texture) obj; + GlTexture tex = (GlTexture) obj; return tex.clone(); } diff --git a/jme3-core/src/main/java/com/jme3/texture/image/DefaultImageRaster.java b/jme3-core/src/main/java/com/jme3/texture/image/DefaultImageRaster.java index 4de14566b4..f955739673 100644 --- a/jme3-core/src/main/java/com/jme3/texture/image/DefaultImageRaster.java +++ b/jme3-core/src/main/java/com/jme3/texture/image/DefaultImageRaster.java @@ -33,14 +33,14 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import java.nio.ByteBuffer; public class DefaultImageRaster extends ImageRaster { private final int[] components = new int[4]; private ByteBuffer buffer; - private final Image image; + private final GlImage image; private final ImageCodec codec; private final int width; private final int height; @@ -56,7 +56,7 @@ private void rangeCheck(int x, int y) { } } - public DefaultImageRaster(Image image, int slice, int mipMapLevel, boolean convertToLinear) { + public DefaultImageRaster(GlImage image, int slice, int mipMapLevel, boolean convertToLinear) { int[] mipMapSizes = image.getMipMapSizes(); int availableMips = mipMapSizes != null ? mipMapSizes.length : 1; @@ -88,7 +88,7 @@ public DefaultImageRaster(Image image, int slice, int mipMapLevel, boolean conve this.convertToLinear = convertToLinear && image.getColorSpace() == ColorSpace.sRGB; this.buffer = image.getData(slice); - this.codec = ImageCodec.lookup(image.getFormat()); + this.codec = ImageCodec.lookup(image.getGlFormat()); if (codec instanceof ByteAlignedImageCodec || codec instanceof ByteOffsetImageCodec) { this.temp = new byte[codec.bpp]; diff --git a/jme3-core/src/main/java/com/jme3/texture/image/ImageCodec.java b/jme3-core/src/main/java/com/jme3/texture/image/ImageCodec.java index 993ce508b4..5598b6fc83 100644 --- a/jme3-core/src/main/java/com/jme3/texture/image/ImageCodec.java +++ b/jme3-core/src/main/java/com/jme3/texture/image/ImageCodec.java @@ -31,15 +31,15 @@ */ package com.jme3.texture.image; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import java.nio.ByteBuffer; import java.util.EnumMap; abstract class ImageCodec { public static final int FLAG_F16 = 1, FLAG_F32 = 2, FLAG_GRAY = 4; //, FLAG_ALPHAONLY = 8, FLAG_SHAREDEXP = 16; - private static final EnumMap params = new EnumMap(Image.Format.class); + private static final EnumMap params = new EnumMap(GlImage.Format.class); protected final int bpp, type, maxAlpha, maxRed, maxGreen, maxBlue; protected final boolean isGray; diff --git a/jme3-core/src/main/java/com/jme3/texture/image/ImageRaster.java b/jme3-core/src/main/java/com/jme3/texture/image/ImageRaster.java index 1a75203225..758e77abcf 100644 --- a/jme3-core/src/main/java/com/jme3/texture/image/ImageRaster.java +++ b/jme3-core/src/main/java/com/jme3/texture/image/ImageRaster.java @@ -32,14 +32,14 @@ package com.jme3.texture.image; import com.jme3.math.ColorRGBA; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; /** - * Utility class for reading and writing from jME3 {@link Image images}. + * Utility class for reading and writing from jME3 {@link GlImage images}. *
* Allows directly manipulating pixels of the image by writing and * reading {@link ColorRGBA colors} at any coordinate, without - * regard to the underlying {@link com.jme3.texture.Image.Format format} of the image. + * regard to the underlying {@link GlImage.Format format} of the image. * NOTE: compressed and depth formats are not supported. * Special RGB formats like RGB111110F and RGB9E5 are not supported * at the moment, but may be added later on. For now @@ -72,14 +72,14 @@ public abstract class ImageRaster { * arrays or cubemaps. * @param mipMapLevel The mipmap level to read / write to. To access levels * other than 0, the image must have - * {@link Image#setMipMapSizes(int[]) mipmap sizes} set. + * {@link GlImage#setMipMapSizes(int[]) mipmap sizes} set. * @param convertToLinear If true, the application expects read or written * colors to be in linear color space (ImageRaster will * automatically perform a conversion as needed). If false, the application expects - * colors to be in the image's native {@link Image#getColorSpace() color space}. + * colors to be in the image's native {@link GlImage#getColorSpace() color space}. * @return An ImageRaster to read / write to the image. */ - public static ImageRaster create(Image image, int slice, int mipMapLevel, boolean convertToLinear) { + public static ImageRaster create(GlImage image, int slice, int mipMapLevel, boolean convertToLinear) { return new DefaultImageRaster(image, slice, mipMapLevel, convertToLinear); } @@ -91,7 +91,7 @@ public static ImageRaster create(Image image, int slice, int mipMapLevel, boolea * arrays or cubemaps. * @return An ImageRaster to read / write to the image. */ - public static ImageRaster create(Image image, int slice) { + public static ImageRaster create(GlImage image, int slice) { return create(image, slice, 0, false); } @@ -101,7 +101,7 @@ public static ImageRaster create(Image image, int slice) { * @param image The image to read / write to. * @return An ImageRaster to read / write to the image. */ - public static ImageRaster create(Image image) { + public static ImageRaster create(GlImage image) { if (image.getData().size() > 1) { throw new IllegalStateException("Use constructor that takes slices argument to read from multislice image"); } @@ -135,7 +135,7 @@ public ImageRaster() { * lower than 0.0 are still not allowed (as all formats are unsigned). *

* If the underlying format is grayscale (e.g. one of the luminance formats, - * such as {@link com.jme3.texture.Image.Format#Luminance8}) then a color to grayscale + * such as {@link GlImage.Format#Luminance8}) then a color to grayscale * conversion is done first, before writing the result into the image. *

* If the image lacks some components (such @@ -159,7 +159,7 @@ public ImageRaster() { *

* Any components that are not defined in the image format * will be set to 1.0 in the returned color. For example, - * reading from an {@link com.jme3.texture.Image.Format#Alpha8} format will + * reading from an {@link GlImage.Format#Alpha8} format will * return a ColorRGBA with the R, G, and B components set to 1.0, and * the A component set to the alpha in the image. *

@@ -169,7 +169,7 @@ public ImageRaster() { * Integer formats are converted to the range 0.0 - 1.0, based * on the maximum possible integer value that can be represented * by the number of bits the component has. - * For example, the {@link com.jme3.texture.Image.Format#RGB5A1} format can + * For example, the {@link GlImage.Format#RGB5A1} format can * contain the integer values 0 - 31, a conversion to floating point * is done by diving the integer value by 31 (done with floating point * precision). diff --git a/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java b/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java index 7a08e1cdde..63e7feab1c 100644 --- a/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java +++ b/jme3-core/src/main/java/com/jme3/texture/image/LastTextureState.java @@ -32,7 +32,7 @@ package com.jme3.texture.image; import com.jme3.renderer.Renderer; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * Stores/caches texture-state parameters so the {@link Renderer} doesn't have to @@ -42,11 +42,11 @@ */ public final class LastTextureState { - public Texture.WrapMode sWrap, tWrap, rWrap; - public Texture.MagFilter magFilter; - public Texture.MinFilter minFilter; + public GlTexture.WrapMode sWrap, tWrap, rWrap; + public GlTexture.MagFilter magFilter; + public GlTexture.MinFilter minFilter; public int anisoFilter; - public Texture.ShadowCompareMode shadowCompareMode; + public GlTexture.ShadowCompareMode shadowCompareMode; public LastTextureState() { reset(); @@ -62,6 +62,6 @@ public void reset() { // The default in OpenGL is OFF, so we avoid setting this per texture // if it's not used. - shadowCompareMode = Texture.ShadowCompareMode.Off; + shadowCompareMode = GlTexture.ShadowCompareMode.Off; } } diff --git a/jme3-core/src/main/java/com/jme3/texture/image/MipMapImageRaster.java b/jme3-core/src/main/java/com/jme3/texture/image/MipMapImageRaster.java index d37db00b67..d024b1c956 100644 --- a/jme3-core/src/main/java/com/jme3/texture/image/MipMapImageRaster.java +++ b/jme3-core/src/main/java/com/jme3/texture/image/MipMapImageRaster.java @@ -33,14 +33,14 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import java.nio.ByteBuffer; public class MipMapImageRaster extends ImageRaster { private final int[] components = new int[4]; private ByteBuffer buffer; - private final Image image; + private final GlImage image; private final ImageCodec codec; private int width[]; private int height[]; @@ -55,11 +55,11 @@ private void rangeCheck(int x, int y) { } } - public MipMapImageRaster(Image image, int slice) { + public MipMapImageRaster(GlImage image, int slice) { this.image = image; this.slice = slice; this.buffer = image.getData(slice); - this.codec = ImageCodec.lookup(image.getFormat()); + this.codec = ImageCodec.lookup(image.getGlFormat()); if (image.hasMipmaps()) { int nbMipMap = image.getMipMapSizes().length; this.width = new int[nbMipMap]; diff --git a/jme3-core/src/main/java/com/jme3/util/MipMapGenerator.java b/jme3-core/src/main/java/com/jme3/util/MipMapGenerator.java index 7073dfab52..23ccb420b6 100644 --- a/jme3-core/src/main/java/com/jme3/util/MipMapGenerator.java +++ b/jme3-core/src/main/java/com/jme3/util/MipMapGenerator.java @@ -33,7 +33,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.FastMath; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.image.ImageRaster; import java.nio.ByteBuffer; @@ -44,10 +44,10 @@ public class MipMapGenerator { private MipMapGenerator() { } - public static Image scaleImage(Image inputImage, int outputWidth, int outputHeight) { - int size = outputWidth * outputHeight * inputImage.getFormat().getBitsPerPixel() / 8; + public static GlImage scaleImage(GlImage inputImage, int outputWidth, int outputHeight) { + int size = outputWidth * outputHeight * inputImage.getGlFormat().getBitsPerPixel() / 8; ByteBuffer buffer = BufferUtils.createByteBuffer(size); - Image outputImage = new Image(inputImage.getFormat(), + GlImage outputImage = new GlImage(inputImage.getGlFormat(), outputWidth, outputHeight, buffer, @@ -87,17 +87,17 @@ public static Image scaleImage(Image inputImage, int outputWidth, int outputHeig return outputImage; } - public static Image resizeToPowerOf2(Image original){ + public static GlImage resizeToPowerOf2(GlImage original){ int potWidth = FastMath.nearestPowerOfTwo(original.getWidth()); int potHeight = FastMath.nearestPowerOfTwo(original.getHeight()); return scaleImage(original, potWidth, potHeight); } - public static void generateMipMaps(Image image){ + public static void generateMipMaps(GlImage image){ int width = image.getWidth(); int height = image.getHeight(); - Image current = image; + GlImage current = image; ArrayList output = new ArrayList<>(); int totalSize = 0; diff --git a/jme3-core/src/main/java/com/jme3/util/PlaceholderAssets.java b/jme3-core/src/main/java/com/jme3/util/PlaceholderAssets.java index 63edfecaa7..19adc6652e 100644 --- a/jme3-core/src/main/java/com/jme3/util/PlaceholderAssets.java +++ b/jme3-core/src/main/java/com/jme3/util/PlaceholderAssets.java @@ -38,9 +38,9 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.image.ColorSpace; import java.nio.ByteBuffer; @@ -78,20 +78,20 @@ private PlaceholderAssets() { } @Deprecated - public static Image getPlaceholderImage(){ + public static GlImage getPlaceholderImage(){ ByteBuffer tempData = BufferUtils.createByteBuffer(3 * 4 * 4); tempData.put(imageData).flip(); - return new Image(Format.RGB8, 4, 4, tempData, null, ColorSpace.Linear); + return new GlImage(Format.RGB8, 4, 4, tempData, null, ColorSpace.Linear); } - public static Image getPlaceholderImage(AssetManager assetManager){ + public static GlImage getPlaceholderImage(AssetManager assetManager){ return assetManager.loadTexture("Common/Textures/MissingTexture.png").getImage(); } public static Material getPlaceholderMaterial(AssetManager assetManager){ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - Texture tex = assetManager.loadTexture("Common/Textures/MissingMaterial.png"); - tex.setWrap(Texture.WrapMode.Repeat); + GlTexture tex = assetManager.loadTexture("Common/Textures/MissingMaterial.png"); + tex.setWrap(GlTexture.WrapMode.Repeat); mat.setTexture("ColorMap", tex); return mat; } @@ -102,8 +102,8 @@ public static Spatial getPlaceholderModel(AssetManager assetManager){ Box box = new Box(1, 1, 1); Geometry geom = new Geometry("placeholder", box); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - Texture tex = assetManager.loadTexture("Common/Textures/MissingModel.png"); - tex.setWrap(Texture.WrapMode.Repeat); + GlTexture tex = assetManager.loadTexture("Common/Textures/MissingModel.png"); + tex.setWrap(GlTexture.WrapMode.Repeat); mat.setTexture("ColorMap", tex); geom.setMaterial(mat); return geom; diff --git a/jme3-core/src/main/java/com/jme3/util/SkyFactory.java b/jme3-core/src/main/java/com/jme3/util/SkyFactory.java index 48794ad991..724f8e12e0 100644 --- a/jme3-core/src/main/java/com/jme3/util/SkyFactory.java +++ b/jme3-core/src/main/java/com/jme3/util/SkyFactory.java @@ -41,9 +41,9 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Sphere; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.TextureCubeMap; import java.nio.ByteBuffer; @@ -108,11 +108,11 @@ private SkyFactory() { * * @return a new spatial representing the sky, ready to be attached to the * scene graph - * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, + * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, GlTexture, * com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)} */ @Deprecated - public static Spatial createSky(AssetManager assetManager, Texture texture, + public static Spatial createSky(AssetManager assetManager, GlTexture texture, Vector3f normalScale, boolean sphereMap) { return createSky(assetManager, texture, normalScale, sphereMap, 10); } @@ -132,7 +132,7 @@ public static Spatial createSky(AssetManager assetManager, Texture texture, * @return a new spatial representing the sky, ready to be attached to the * scene graph */ - public static Spatial createSky(AssetManager assetManager, Texture texture, + public static Spatial createSky(AssetManager assetManager, GlTexture texture, Vector3f normalScale, EnvMapType envMapType) { return createSky(assetManager, texture, normalScale, envMapType, 10); } @@ -159,11 +159,11 @@ public static Spatial createSky(AssetManager assetManager, Texture texture, * frustum * @return a new spatial representing the sky, ready to be attached to the * scene graph - * @deprecated use {@link #createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, + * @deprecated use {@link #createSky(com.jme3.asset.AssetManager, GlTexture, * com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType, float)} */ @Deprecated - public static Spatial createSky(AssetManager assetManager, Texture texture, + public static Spatial createSky(AssetManager assetManager, GlTexture texture, Vector3f normalScale, boolean sphereMap, int sphereRadius) { return createSky(assetManager, texture, normalScale, sphereMap ? EnvMapType.SphereMap : EnvMapType.CubeMap, sphereRadius); @@ -184,7 +184,7 @@ public static Spatial createSky(AssetManager assetManager, Texture texture, * @return a new spatial representing the sky, ready to be attached to the * scene graph */ - public static Spatial createSky(AssetManager assetManager, Texture texture, + public static Spatial createSky(AssetManager assetManager, GlTexture texture, Vector3f normalScale, EnvMapType envMapType, float sphereRadius) { if (texture == null) { throw new IllegalArgumentException("texture cannot be null"); @@ -202,7 +202,7 @@ public static Spatial createSky(AssetManager assetManager, Texture texture, case CubeMap: // make sure it's a cubemap if (!(texture instanceof TextureCubeMap)) { - Image img = texture.getImage(); + GlImage img = texture.getImage(); texture = new TextureCubeMap(); texture.setImage(img); } @@ -223,10 +223,10 @@ public static Spatial createSky(AssetManager assetManager, Texture texture, throw new IllegalArgumentException("envMapType=" + envMapType); } skyMat.setVector3("NormalScale", normalScale); - texture.setMagFilter(Texture.MagFilter.Bilinear); - texture.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + texture.setMagFilter(GlTexture.MagFilter.Bilinear); + texture.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); texture.setAnisotropicFilter(0); - texture.setWrap(Texture.WrapMode.EdgeClamp); + texture.setWrap(GlTexture.WrapMode.EdgeClamp); skyMat.setTexture("Texture", texture); sky.setMaterial(skyMat); @@ -249,11 +249,11 @@ public static Spatial createSky(AssetManager assetManager, Texture texture, * * @return a new spatial representing the sky, ready to be attached to the * scene graph - * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, com.jme3.texture.Texture, + * @deprecated use {@link SkyFactory#createSky(com.jme3.asset.AssetManager, GlTexture, * com.jme3.math.Vector3f, com.jme3.util.SkyFactory.EnvMapType)} */ @Deprecated - public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap) { + public static Spatial createSky(AssetManager assetManager, GlTexture texture, boolean sphereMap) { return createSky(assetManager, texture, Vector3f.UNIT_XYZ, sphereMap ? EnvMapType.SphereMap : EnvMapType.CubeMap); } @@ -291,7 +291,7 @@ public static Spatial createSky(AssetManager assetManager, String textureName, b * @return a new spatial representing the sky, ready to be attached to the * scene graph */ - public static Spatial createSky(AssetManager assetManager, Texture texture, EnvMapType envMapType) { + public static Spatial createSky(AssetManager assetManager, GlTexture texture, EnvMapType envMapType) { return createSky(assetManager, texture, Vector3f.UNIT_XYZ, envMapType); } @@ -308,13 +308,13 @@ public static Spatial createSky(AssetManager assetManager, String textureName, E TextureKey key = new TextureKey(textureName, true); key.setGenerateMips(false); if (envMapType == EnvMapType.CubeMap) { - key.setTextureTypeHint(Texture.Type.CubeMap); + key.setTextureTypeHint(GlTexture.Type.CubeMap); } - Texture tex = assetManager.loadTexture(key); + GlTexture tex = assetManager.loadTexture(key); return createSky(assetManager, tex, envMapType); } - private static void checkImage(Image image) { + private static void checkImage(GlImage image) { // if (image.getDepth() != 1) // throw new IllegalArgumentException("3D/Array images not allowed"); @@ -327,12 +327,12 @@ private static void checkImage(Image image) { } } - private static void checkImagesForCubeMap(Image... images) { + private static void checkImagesForCubeMap(GlImage... images) { if (images.length == 1) { return; } - Format fmt = images[0].getFormat(); + Format fmt = images[0].getGlFormat(); int width = images[0].getWidth(); int height = images[0].getHeight(); @@ -342,9 +342,9 @@ private static void checkImagesForCubeMap(Image... images) { checkImage(images[0]); for (int i = 1; i < images.length; i++) { - Image image = images[i]; + GlImage image = images[i]; checkImage(images[i]); - if (image.getFormat() != fmt) { + if (image.getGlFormat() != fmt) { throw new IllegalArgumentException("Images must have same format"); } if (image.getWidth() != width || image.getHeight() != height) { @@ -378,9 +378,9 @@ private static void checkImagesForCubeMap(Image... images) { * @return a new spatial representing the sky, ready to be attached to the * scene graph */ - public static Spatial createSky(AssetManager assetManager, Texture west, - Texture east, Texture north, Texture south, Texture up, - Texture down, Vector3f normalScale) { + public static Spatial createSky(AssetManager assetManager, GlTexture west, + GlTexture east, GlTexture north, GlTexture south, GlTexture up, + GlTexture down, Vector3f normalScale) { return createSky(assetManager, west, east, north, south, up, down, normalScale, 10); } @@ -404,20 +404,20 @@ public static Spatial createSky(AssetManager assetManager, Texture west, * @return a new spatial representing the sky, ready to be attached to the * scene graph */ - public static Spatial createSky(AssetManager assetManager, Texture west, - Texture east, Texture north, Texture south, Texture up, - Texture down, Vector3f normalScale, float sphereRadius) { + public static Spatial createSky(AssetManager assetManager, GlTexture west, + GlTexture east, GlTexture north, GlTexture south, GlTexture up, + GlTexture down, Vector3f normalScale, float sphereRadius) { - Image westImg = west.getImage(); - Image eastImg = east.getImage(); - Image northImg = north.getImage(); - Image southImg = south.getImage(); - Image upImg = up.getImage(); - Image downImg = down.getImage(); + GlImage westImg = west.getImage(); + GlImage eastImg = east.getImage(); + GlImage northImg = north.getImage(); + GlImage southImg = south.getImage(); + GlImage upImg = up.getImage(); + GlImage downImg = down.getImage(); checkImagesForCubeMap(westImg, eastImg, northImg, southImg, upImg, downImg); - Image cubeImage = new Image(westImg.getFormat(), westImg.getWidth(), westImg.getHeight(), + GlImage cubeImage = new GlImage(westImg.getGlFormat(), westImg.getWidth(), westImg.getHeight(), null, westImg.getColorSpace()); cubeImage.addData(westImg.getData(0)); @@ -445,7 +445,7 @@ public static Spatial createSky(AssetManager assetManager, Texture west, * scene graph */ public static Spatial createSky(AssetManager assetManager, - Texture west, Texture east, Texture north, Texture south, Texture up, Texture down) { + GlTexture west, GlTexture east, GlTexture north, GlTexture south, GlTexture up, GlTexture down) { return createSky(assetManager, west, east, north, south, up, down, Vector3f.UNIT_XYZ); } } diff --git a/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java b/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java index f19aacd914..a8209e7edc 100644 --- a/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java +++ b/jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java @@ -238,7 +238,7 @@ public static void generate(Mesh mesh, boolean approxTangents) { } private static List processTriangles(Mesh mesh, - int[] index, Vector3f[] v, Vector2f[] t, boolean splitMirrored) { + int[] index, Vector3f[] v, Vector2f[] t, boolean splitMirrored) { IndexBuffer indexBuffer = mesh.getIndexBuffer(); FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); if (mesh.getBuffer(Type.TexCoord) == null) { @@ -447,7 +447,7 @@ private static void putValue(VertexBuffer.Format format, Buffer buf1, Buffer buf } private static List processTriangleStrip(Mesh mesh, - int[] index, Vector3f[] v, Vector2f[] t) { + int[] index, Vector3f[] v, Vector2f[] t) { IndexBuffer indexBuffer = mesh.getIndexBuffer(); FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); @@ -496,7 +496,7 @@ private static List processTriangleStrip(Mesh mesh, } private static List processTriangleFan(Mesh mesh, - int[] index, Vector3f[] v, Vector2f[] t) { + int[] index, Vector3f[] v, Vector2f[] t) { IndexBuffer indexBuffer = mesh.getIndexBuffer(); FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); @@ -673,7 +673,7 @@ && approxEqual(vertexInfo.texCoord, texCoord)) { } private static void processTriangleData(Mesh mesh, List vertices, - boolean approxTangent, boolean splitMirrored) { + boolean approxTangent, boolean splitMirrored) { ArrayList vertexMap = linkVertices(mesh, splitMirrored); FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.size() * 4); @@ -863,7 +863,7 @@ private static int parity(Vector3f n1, Vector3f n) { } /** - * @deprecated Use {@link TangentUtils#genTbnLines(com.jme3.scene.Mesh, float) } instead. + * @deprecated Use {@link TangentUtils#genTbnLines(Mesh, float) } instead. */ @Deprecated public static Mesh genTbnLines(Mesh mesh, float scale) { @@ -871,7 +871,7 @@ public static Mesh genTbnLines(Mesh mesh, float scale) { } /** - * @deprecated Use {@link TangentUtils#genNormalLines(com.jme3.scene.Mesh, float) } instead. + * @deprecated Use {@link TangentUtils#genNormalLines(Mesh, float) } instead. */ @Deprecated public static Mesh genNormalLines(Mesh mesh, float scale) { diff --git a/jme3-core/src/main/java/com/jme3/util/natives/AbstractNative.java b/jme3-core/src/main/java/com/jme3/util/natives/AbstractNative.java new file mode 100644 index 0000000000..c5b1e60190 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/util/natives/AbstractNative.java @@ -0,0 +1,37 @@ +package com.jme3.util.natives; + +import org.lwjgl.system.MemoryStack; + +public abstract class AbstractNative implements Native { + + protected T object; + protected NativeReference ref; + + @Override + public T getNativeObject() { + return object; + } + + @Override + public void prematureNativeDestruction() {} + + @Override + public NativeReference getNativeReference() { + return ref; + } + + public static abstract class Builder implements AutoCloseable { + + protected final MemoryStack stack = MemoryStack.stackPush(); + + @Override + public void close() { + build(); + stack.pop(); + } + + protected abstract void build(); + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/util/natives/BasicNativeManager.java b/jme3-core/src/main/java/com/jme3/util/natives/BasicNativeManager.java new file mode 100644 index 0000000000..2ef3076b84 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/util/natives/BasicNativeManager.java @@ -0,0 +1,115 @@ +package com.jme3.util.natives; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +public class BasicNativeManager implements NativeManager { + + private static NativeManager globalInstance = new BasicNativeManager(); + + public static void setGlobalInstance(NativeManager instance) { + globalInstance = Objects.requireNonNull(instance, "NativeManager global instance cannot be null."); + } + + public static NativeManager getGlobalInstance() { + return globalInstance; + } + + private final ReferenceQueue unreachable = new ReferenceQueue<>(); + private final Map refMap = new ConcurrentHashMap<>(); + private final AtomicLong nextId = new AtomicLong(0L); + + @Override + public NativeRef register(Native object) { + NativeRef ref = new NativeRef(nextId.getAndIncrement(), object, unreachable); + refMap.put(ref.getId(), ref); + return ref; + } + + @Override + public int flush() { + int flushed = 0; + for (NativeRef ref; (ref = (NativeRef)unreachable.poll()) != null;) { + ref.destroy(); + refMap.remove(ref.id); + flushed++; + } + if (flushed > 0) { + refMap.values().removeIf(NativeRef::isDestroyed); + } + return flushed; + } + + @Override + public int clear() { + int size = refMap.size(); + for (NativeRef ref : refMap.values()) { + ref.destroy(); + } + refMap.clear(); + return size; + } + + public class NativeRef extends WeakReference implements NativeReference { + + private final long id; + private final WeakReference weakRef; + private final AtomicBoolean active = new AtomicBoolean(true); + private final Collection dependents = new ArrayList<>(); + private Runnable destroyer; + + private NativeRef(long id, Native referent, ReferenceQueue q) { + super(referent, q); + this.id = id; + destroyer = referent.createNativeDestroyer(); + weakRef = new WeakReference<>(referent); + } + + @Override + public void destroy() { + if (active.getAndSet(false)) { + for (NativeReference ref : dependents) { + ref.destroy(); + } + dependents.clear(); + destroyer.run(); + Native referent = weakRef.get(); + if (referent != null) { + referent.prematureNativeDestruction(); + } + } + } + + @Override + public void addDependent(NativeReference reference) { + if (isDestroyed()) { + throw new IllegalStateException("Cannot add dependent to destroyed resource."); + } + dependents.add(reference); + } + + @Override + public boolean isDestroyed() { + return !active.get(); + } + + @Override + public void refresh() { + Native obj = weakRef.get(); + if (obj != null) { + destroyer = obj.createNativeDestroyer(); + } + } + + private long getId() { + return id; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/util/natives/GlNative.java b/jme3-core/src/main/java/com/jme3/util/natives/GlNative.java new file mode 100644 index 0000000000..84495aea45 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/util/natives/GlNative.java @@ -0,0 +1,76 @@ +package com.jme3.util.natives; + +import com.jme3.renderer.opengl.GLRenderer; + +import java.lang.ref.WeakReference; + +public abstract class GlNative extends AbstractNative implements Cloneable { + + protected GLRenderer renderer; + protected boolean updateNeeded = true; + private WeakReference> weakRef; + + public GlNative() {} + + public GlNative(T object) { + this.object = object; + } + + public abstract void resetObject(); + + protected void setId(T id) { + setId(null, id); + } + + public void setId(GLRenderer renderer, T id) { + object = id; + if (ref != null) { + ref.destroy(); + } + this.renderer = renderer; + ref = Native.get().register(this); + } + + public void setUpdateNeeded() { + updateNeeded = true; + } + + public void clearUpdateNeeded() { + updateNeeded = false; + } + + public boolean isUpdateNeeded() { + return updateNeeded; + } + + public void dispose() { + if (ref != null) { + ref.destroy(); + ref = null; + } + } + + @SuppressWarnings("unchecked") + public WeakReference getWeakRef() { + if (weakRef == null) { + weakRef = new WeakReference<>(this); + } + return (WeakReference) weakRef; + } + + @Override + @SuppressWarnings("unchecked") + public GlNative clone() { + try { + GlNative clone = (GlNative) super.clone(); + // TODO: copy mutable state here, so the clone can't change the internals of the original + clone.updateNeeded = true; + clone.renderer = renderer; + clone.object = object; + return clone; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/util/natives/Native.java b/jme3-core/src/main/java/com/jme3/util/natives/Native.java new file mode 100644 index 0000000000..1e6fd2b035 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/util/natives/Native.java @@ -0,0 +1,31 @@ +package com.jme3.util.natives; + +import org.lwjgl.system.MemoryUtil; + +public interface Native { + + T getNativeObject(); + + Runnable createNativeDestroyer(); + + void prematureNativeDestruction(); + + NativeReference getNativeReference(); + + static void set(NativeManager manager) { + BasicNativeManager.setGlobalInstance(manager); + } + + static NativeManager get() { + return BasicNativeManager.getGlobalInstance(); + } + + static T getObject(Native n) { + return n != null ? n.getNativeObject() : null; + } + + static long getId(Native n) { + return n != null ? n.getNativeObject() : MemoryUtil.NULL; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/util/natives/NativeManager.java b/jme3-core/src/main/java/com/jme3/util/natives/NativeManager.java new file mode 100644 index 0000000000..95e2dce698 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/util/natives/NativeManager.java @@ -0,0 +1,13 @@ +package com.jme3.util.natives; + +import org.lwjgl.system.NativeResource; + +public interface NativeManager { + + NativeReference register(Native object); + + int flush(); + + int clear(); + +} diff --git a/jme3-core/src/main/java/com/jme3/util/natives/NativeReference.java b/jme3-core/src/main/java/com/jme3/util/natives/NativeReference.java new file mode 100644 index 0000000000..f699c81b39 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/util/natives/NativeReference.java @@ -0,0 +1,13 @@ +package com.jme3.util.natives; + +public interface NativeReference { + + void destroy(); + + void refresh(); + + void addDependent(NativeReference reference); + + boolean isDestroyed(); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/Format.java b/jme3-core/src/main/java/com/jme3/vulkan/Format.java new file mode 100644 index 0000000000..542b78be41 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/Format.java @@ -0,0 +1,391 @@ +package com.jme3.vulkan; + +import com.jme3.vulkan.images.VulkanImage; +import com.jme3.vulkan.util.Flag; + +import java.nio.ByteBuffer; +import java.util.Iterator; + +import static org.lwjgl.vulkan.VK10.*; + +public enum Format implements Iterable { + + RGBA32SFloat(VK_FORMAT_R32G32B32A32_SFLOAT, array(cf(4), cf(4), cf(4), cf(4)), true, false, false), + RGB32SFloat(VK_FORMAT_R32G32B32_SFLOAT, array(cf(4), cf(4), cf(4)), true, false, false), + RG32SFloat(VK_FORMAT_R32G32_SFLOAT, array(cf(4), cf(4)), true, false, false), + + RGBA8_SRGB(VK_FORMAT_R8G8B8A8_SRGB, array(cf(1), cf(1), cf(1), cf(1)), true, false, false), + R8_SRGB(VK_FORMAT_R8_SRGB, array(cf(1)), true, false, false), + BGR8_SRGB(VK_FORMAT_B8G8R8_SRGB, array(cf(1), cf(1), cf(1)), true, false, false), + ABGR8_SRGB(VK_FORMAT_A8B8G8R8_SRGB_PACK32, array(cf(1), cf(1), cf(1), cf(1)), true, false, false), + B8G8R8A8_SRGB(VK_FORMAT_B8G8R8A8_SRGB, array(cf(1), cf(1), cf(1), cf(1)), true, false, false), + + Depth32SFloat(VK_FORMAT_D32_SFLOAT, array(cf(4)), false, true, false), + Depth32SFloat_Stencil8UInt(VK_FORMAT_D32_SFLOAT_S8_UINT, array(cf(4), c(1)), false, true, true), + Depth24UNorm_Stencil8UInt(VK_FORMAT_D24_UNORM_S8_UINT, array(cf(3), c(1)), false, true, true), + Depth16UNorm(VK_FORMAT_D16_UNORM, array(cf(2)), false, true, false), + Depth16UNorm_Stencil8UInt(VK_FORMAT_D16_UNORM_S8_UINT, array(cf(2), c(1)), false, true, true); + + public enum Feature implements Flag { + + DepthStencilAttachment(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT), + BlitDst(VK_FORMAT_FEATURE_BLIT_DST_BIT), + BlitSrc(VK_FORMAT_FEATURE_BLIT_SRC_BIT), + ColorAttachment(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT), + SampledImage(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT), + ColorAttachmentBlend(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT), + SampledImageFilterLinear(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT), + StorageImageAtomic(VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT), + StorageImage(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT), + StorageTexelBufferAtomic(VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT), + StorageTexelBuffer(VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT), + UniformTexelBuffer(VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT), + VertexBuffer(VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT); + + private final int bits; + + Feature(int bits) { + this.bits = bits; + } + + @Override + public int bits() { + return bits; + } + + } + + private final int vkEnum, totalBytes; + private final Component[] components; + private final boolean color, depth, stencil; + + Format(int vkEnum, Component[] components, boolean color, boolean depth, boolean stencil) { + this.vkEnum = vkEnum; + this.components = components; + this.color = color; + this.depth = depth; + this.stencil = stencil; + int total = 0; + for (Component c : components) { + c.setOffset(total); + total += c.getBytes(); + } + this.totalBytes = total; + } + + @Override + public Iterator iterator() { + return new ComponentIterator(components); + } + + public int getVkEnum() { + return vkEnum; + } + + public Flag getAspects() { + int bits = 0; + if (color) bits |= VulkanImage.Aspect.Color.bits(); + if (depth) bits |= VulkanImage.Aspect.Depth.bits(); + if (stencil) bits |= VulkanImage.Aspect.Stencil.bits(); + return Flag.of(bits); + } + + public int getTotalBits() { + return totalBytes * Byte.SIZE; + } + + public int getTotalBytes() { + return totalBytes; + } + + public int getNumComponents() { + return components.length; + } + + public Component getComponent(int component) { + return components[component]; + } + + public boolean isColor() { + return color; + } + + public boolean isDepth() { + return depth; + } + + public boolean isStencil() { + return stencil; + } + + public static Format byVkEnum(int vkEnum) { + for (Format f : Format.values()) { + if (f.getVkEnum() == vkEnum) { + return f; + } + } + return null; + } + + private static Component[] array(Component... components) { + return components; + } + + private static Component c(int bytes) { + return new Component(bytes, false); + } + + private static Component cf(int bytes) { + return new Component(bytes, true); + } + + public static class Component { + + private final int bytes; + private final boolean floatingPoint; + private int offset; + + private Component(int bytes, boolean floatingPoint) { + assert bytes > 0 : "Component size in bytes must be positive"; + this.bytes = bytes; + this.floatingPoint = floatingPoint && bytes >= 4; + } + + private void setOffset(int offset) { + this.offset = offset; + } + + public int getBytes() { + return bytes; + } + + public int getOffset() { + return offset; + } + + public boolean isFloatingPoint() { + return floatingPoint; + } + + public Component putByte(ByteBuffer buffer, int position, byte value) { + position += offset; + switch (bytes) { + case 1: buffer.put(position, value); break; + case 2: case 3: buffer.putShort(position, value); break; + case 4: case 5: case 6: case 7: { + if (floatingPoint) buffer.putFloat(position, value); + else buffer.putInt(position, value); + } break; + default: { + if (floatingPoint) buffer.putDouble(position, value); + else buffer.putLong(position, value); + } + } + return this; + } + + public Component putShort(ByteBuffer buffer, int position, short value) { + position += offset; + switch (bytes) { + case 1: buffer.put(position, (byte)value); break; + case 2: case 3: buffer.putShort(position, value); break; + case 4: case 5: case 6: case 7: { + if (floatingPoint) buffer.putFloat(position, value); + else buffer.putInt(position, value); + } break; + default: { + if (floatingPoint) buffer.putDouble(position, value); + else buffer.putLong(position, value); + } + } + return this; + } + + public Component putInt(ByteBuffer buffer, int position, int value) { + position += offset; + switch (bytes) { + case 1: buffer.put(position, (byte)value); break; + case 2: case 3: buffer.putShort(position, (short)value); break; + case 4: case 5: case 6: case 7: { + if (floatingPoint) buffer.putFloat(position, value); + else buffer.putInt(position, value); + } break; + default: { + if (floatingPoint) buffer.putDouble(position, value); + else buffer.putLong(position, value); + } + } + return this; + } + + public Component putFloat(ByteBuffer buffer, int position, float value) { + position += offset; + switch (bytes) { + case 1: buffer.put(position, (byte)value); break; + case 2: case 3: buffer.putShort(position, (short)value); break; + case 4: case 5: case 6: case 7: { + if (floatingPoint) buffer.putFloat(position, value); + else buffer.putInt(position, (int)value); + } break; + default: { + if (floatingPoint) buffer.putDouble(position, value); + else buffer.putLong(position, (long)value); + } + } + return this; + } + + public Component putDouble(ByteBuffer buffer, int position, double value) { + position += offset; + switch (bytes) { + case 1: buffer.put(position, (byte)value); break; + case 2: case 3: buffer.putShort(position, (short)value); break; + case 4: case 5: case 6: case 7: { + if (floatingPoint) buffer.putFloat(position, (float)value); + else buffer.putInt(position, (int)value); + } break; + default: { + if (floatingPoint) buffer.putDouble(position, value); + else buffer.putLong(position, (long)value); + } + } + return this; + } + + public Component putLong(ByteBuffer buffer, int position, long value) { + position += offset; + switch (bytes) { + case 1: buffer.put(position, (byte)value); break; + case 2: case 3: buffer.putShort(position, (short)value); break; + case 4: case 5: case 6: case 7: { + if (floatingPoint) buffer.putFloat(position, value); + else buffer.putInt(position, (int)value); + } break; + default: { + if (floatingPoint) buffer.putDouble(position, value); + else buffer.putLong(position, value); + } + } + return this; + } + + public byte getByte(ByteBuffer buffer, int position) { + position += offset; + switch (bytes) { + case 1: return buffer.get(position); + case 2: case 3: return (byte)buffer.getShort(position); + case 4: case 5: case 6: case 7: { + if (floatingPoint) return (byte)buffer.getFloat(position); + else return (byte)buffer.getInt(position); + } + default: { + if (floatingPoint) return (byte)buffer.getDouble(position); + else return (byte)buffer.getLong(position); + } + } + } + + public short getShort(ByteBuffer buffer, int position) { + position += offset; + switch (bytes) { + case 1: return buffer.get(position); + case 2: case 3: return buffer.getShort(position); + case 4: case 5: case 6: case 7: { + if (floatingPoint) return (short)buffer.getFloat(position); + else return (short)buffer.getInt(position); + } + default: { + if (floatingPoint) return (short)buffer.getDouble(position); + else return (short)buffer.getLong(position); + } + } + } + + public int getInt(ByteBuffer buffer, int position) { + position += offset; + switch (bytes) { + case 1: return buffer.get(position); + case 2: case 3: return buffer.getShort(position); + case 4: case 5: case 6: case 7: { + if (floatingPoint) return (int)buffer.getFloat(position); + else return buffer.getInt(position); + } + default: { + if (floatingPoint) return (int)buffer.getDouble(position); + else return (int)buffer.getLong(position); + } + } + } + + public float getFloat(ByteBuffer buffer, int position) { + position += offset; + switch (bytes) { + case 1: return buffer.get(position); + case 2: case 3: return buffer.getShort(position); + case 4: case 5: case 6: case 7: { + if (floatingPoint) return buffer.getFloat(position); + else return buffer.getInt(position); + } + default: { + if (floatingPoint) return (float)buffer.getDouble(position); + else return buffer.getLong(position); + } + } + } + + public double getDouble(ByteBuffer buffer, int position) { + position += offset; + switch (bytes) { + case 1: return buffer.get(position); + case 2: case 3: return buffer.getShort(position); + case 4: case 5: case 6: case 7: { + if (floatingPoint) return buffer.getFloat(position); + else return buffer.getInt(position); + } + default: { + if (floatingPoint) return buffer.getDouble(position); + else return buffer.getLong(position); + } + } + } + + public long getLong(ByteBuffer buffer, int position) { + position += offset; + switch (bytes) { + case 1: return buffer.get(position); + case 2: case 3: return buffer.getShort(position); + case 4: case 5: case 6: case 7: { + if (floatingPoint) return (long)buffer.getFloat(position); + else return buffer.getInt(position); + } + default: { + if (floatingPoint) return (long)buffer.getDouble(position); + else return buffer.getLong(position); + } + } + } + + } + + private static class ComponentIterator implements Iterator { + + private final Component[] components; + private int index = 0; + + private ComponentIterator(Component[] components) { + this.components = components; + } + + @Override + public boolean hasNext() { + return index < components.length; + } + + @Override + public Component next() { + return components[index++]; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/SharingMode.java b/jme3-core/src/main/java/com/jme3/vulkan/SharingMode.java new file mode 100644 index 0000000000..1368b80b0d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/SharingMode.java @@ -0,0 +1,27 @@ +package com.jme3.vulkan; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum SharingMode implements IntEnum { + + Exclusive(VK_SHARING_MODE_EXCLUSIVE), + Concurrent(VK_SHARING_MODE_CONCURRENT); + + private final int vkEnum; + + SharingMode(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + public static SharingMode concurrent(boolean concurrent) { + return concurrent ? Concurrent : Exclusive; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/Swizzle.java b/jme3-core/src/main/java/com/jme3/vulkan/Swizzle.java new file mode 100644 index 0000000000..8717c51d3c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/Swizzle.java @@ -0,0 +1,28 @@ +package com.jme3.vulkan; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum Swizzle implements IntEnum { + + Identity(VK_COMPONENT_SWIZZLE_IDENTITY), + R(VK_COMPONENT_SWIZZLE_R), + G(VK_COMPONENT_SWIZZLE_G), + B(VK_COMPONENT_SWIZZLE_B), + A(VK_COMPONENT_SWIZZLE_A), + One(VK_COMPONENT_SWIZZLE_ONE), + Zero(VK_COMPONENT_SWIZZLE_ZERO); + + private final int vkEnum; + + Swizzle(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/VulkanInstance.java b/jme3-core/src/main/java/com/jme3/vulkan/VulkanInstance.java new file mode 100644 index 0000000000..86f6c5602e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/VulkanInstance.java @@ -0,0 +1,140 @@ +package com.jme3.vulkan; + +import com.jme3.system.JmeVersion; +import com.jme3.util.natives.AbstractNative; +import com.jme3.util.natives.Native; +import org.lwjgl.PointerBuffer; +import org.lwjgl.glfw.GLFWVulkan; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.vulkan.EXTDebugUtils; +import org.lwjgl.vulkan.VkApplicationInfo; +import org.lwjgl.vulkan.VkInstance; +import org.lwjgl.vulkan.VkInstanceCreateInfo; + +import java.util.*; +import java.util.logging.Level; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class VulkanInstance extends AbstractNative { + + public static final String ENGINE_NAME = "jMonkeyEngine"; + public static final String LUNARG_LAYER = "VK_LAYER_KHRONOS_validation"; + + private final Set extensions = new HashSet<>(); + private final Set layers = new HashSet<>(); + private String appName = "Unnamed App"; + private int appVersion = VK_MAKE_VERSION(0, 0, 0); + private int apiVersion; + private VulkanLogger logger; + + public VulkanInstance() { + this(VK_API_VERSION_1_0); + } + + public VulkanInstance(int apiVersion) { + this.apiVersion = apiVersion; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyInstance(object, null); + } + + public VulkanLogger createLogger(Level exceptionThreshold) { + return logger = new VulkanLogger(this, exceptionThreshold); + } + + public VulkanLogger getLogger() { + return logger; + } + + public Set getExtensions() { + return extensions; + } + + public Set getLayers() { + return layers; + } + + public Builder build() { + return new Builder(); + } + + public class Builder extends AbstractNative.Builder { + + @Override + protected void build() { + String[] ver = JmeVersion.VERSION_NUMBER.split("\\.", 3); + VkApplicationInfo info = VkApplicationInfo.calloc(stack) + .apiVersion(apiVersion) + .pEngineName(stack.UTF8(ENGINE_NAME)) + .engineVersion(VK_MAKE_VERSION( + Integer.parseInt(ver[0]), + Integer.parseInt(ver[1]), + Integer.parseInt(ver[2]))) + .pApplicationName(stack.UTF8(appName)) + .applicationVersion(appVersion); + VkInstanceCreateInfo create = VkInstanceCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) + .pApplicationInfo(info); + if (!extensions.isEmpty()) { + PointerBuffer exts = stack.mallocPointer(extensions.size()); + for (String e : extensions) { + exts.put(stack.UTF8(e)); + } + create.ppEnabledExtensionNames(exts.flip()); + } + if (!layers.isEmpty()) { + PointerBuffer lyrs = stack.mallocPointer(layers.size()); + for (String l : layers) { + lyrs.put(stack.UTF8(l)); + } + create.ppEnabledLayerNames(lyrs.flip()); + } + PointerBuffer ptr = stack.mallocPointer(1); + check(vkCreateInstance(create, null, ptr), "Failed to create instance."); + object = new VkInstance(ptr.get(0), create); + ref = Native.get().register(VulkanInstance.this); + } + + public void setApplicationName(String name) { + VulkanInstance.this.appName = name; + } + + public void setApplicationVersion(int major, int minor, int patch) { + VulkanInstance.this.appVersion = VK_MAKE_VERSION(major, minor, patch); + } + + public void setApiVersion(int version) { + VulkanInstance.this.apiVersion = version; + } + + public void addGlfwExtensions() { + PointerBuffer exts = Objects.requireNonNull(GLFWVulkan.glfwGetRequiredInstanceExtensions(), + "Vulkan extensions for GLFW are not available."); + for (int i = 0; i < exts.limit(); i++) { + extensions.add(MemoryUtil.memUTF8(exts.get(i))); + } + } + + public void addDebugExtension() { + extensions.add(EXTDebugUtils.VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + + public void addLunarGLayer() { + layers.add(LUNARG_LAYER); + } + + public void addExtension(String ext) { + extensions.add(ext); + } + + public void addLayer(String layer) { + layers.add(layer); + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/VulkanLogger.java b/jme3-core/src/main/java/com/jme3/vulkan/VulkanLogger.java new file mode 100644 index 0000000000..a11fed7644 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/VulkanLogger.java @@ -0,0 +1,101 @@ +package com.jme3.vulkan; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.EXTDebugUtils; +import org.lwjgl.vulkan.VkDebugUtilsMessengerCallbackDataEXT; +import org.lwjgl.vulkan.VkDebugUtilsMessengerCallbackEXT; +import org.lwjgl.vulkan.VkDebugUtilsMessengerCreateInfoEXT; + +import java.util.logging.Level; + +import static com.jme3.renderer.vulkan.VulkanUtils.getLong; +import static com.jme3.renderer.vulkan.VulkanUtils.verifyExtensionMethod; +import static org.lwjgl.vulkan.EXTDebugUtils.*; +import static org.lwjgl.vulkan.VK10.VK_FALSE; + +public class VulkanLogger implements Native { + + private final VulkanInstance instance; + private final Level exceptionThreshold; + private final NativeReference ref; + private final long id; + private final VkDebugUtilsMessengerCallbackEXT callback = new VkDebugUtilsMessengerCallbackEXT() { + @Override + public int invoke(int messageSeverity, int messageTypes, long pCallbackData, long pUserData) { + return message(messageSeverity, messageTypes, pCallbackData, pUserData); + } + }; + + public VulkanLogger(VulkanInstance instance, Level exceptionThreshold) { + this.instance = instance; + this.exceptionThreshold = exceptionThreshold; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkDebugUtilsMessengerCreateInfoEXT create = VkDebugUtilsMessengerCreateInfoEXT.calloc(stack) + .sType(VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) + .messageSeverity( + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT + ).messageType( + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT + ).pfnUserCallback(callback); + verifyExtensionMethod(instance.getNativeObject(), "vkCreateDebugUtilsMessengerEXT"); + id = getLong(stack, ptr -> vkCreateDebugUtilsMessengerEXT(instance.getNativeObject(), create, null, ptr)); + } + ref = Native.get().register(this); + instance.getNativeReference().addDependent(ref); + } + + public int message(int messageSeverity, int messageTypes, long pCallbackData, long pUserData) { + VkDebugUtilsMessengerCallbackDataEXT data = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData); + Level lvl = getLoggingLevel(messageSeverity); + System.err.println(lvl.getName() + " " + data.pMessageString()); + if (exceptionThreshold != null && lvl.intValue() >= exceptionThreshold.intValue()) { + throw new RuntimeException(lvl.getName() + ": " + data.pMessageString()); + } + return VK_FALSE; // always return false, true is only really used for testing validation layers + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> { + verifyExtensionMethod(instance.getNativeObject(), "vkDestroyDebugUtilsMessengerEXT"); + vkDestroyDebugUtilsMessengerEXT(instance.getNativeObject(), id, null); + callback.close(); + }; + } + + @Override + public void prematureNativeDestruction() {} + + @Override + public NativeReference getNativeReference() { + return ref; + } + + private Level getLoggingLevel(int messageSeverity) { + switch (messageSeverity) { + case EXTDebugUtils.VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + return Level.SEVERE; + case EXTDebugUtils.VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + return Level.WARNING; + case EXTDebugUtils.VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + return Level.INFO; + case EXTDebugUtils.VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + return Level.FINE; + default: throw new UnsupportedOperationException("Unsupported severity bit: " + + Integer.numberOfTrailingZeros(Integer.highestOneBit(messageSeverity))); + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/app/VulkanApplication.java b/jme3-core/src/main/java/com/jme3/vulkan/app/VulkanApplication.java new file mode 100644 index 0000000000..9d32f9623c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/app/VulkanApplication.java @@ -0,0 +1,18 @@ +package com.jme3.vulkan.app; + +import com.jme3.app.SimpleApplication; +import com.jme3.vulkan.VulkanInstance; +import org.lwjgl.system.MemoryStack; + +public class VulkanApplication extends SimpleApplication { + + protected VulkanInstance instance; + + @Override + public void simpleInitApp() { + try (MemoryStack stack = MemoryStack.stackPush()) { + + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/BackedStaticBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BackedStaticBuffer.java new file mode 100644 index 0000000000..f5303f693b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BackedStaticBuffer.java @@ -0,0 +1,60 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +public class BackedStaticBuffer extends StaticBuffer { + + private final PointerBuffer location = MemoryUtil.memAllocPointer(1); + private final ByteBuffer backing; + private boolean backed = false; + + public BackedStaticBuffer(LogicalDevice device, MemorySize size, Flag usage, Flag mem, boolean concurrent) { + super(device, size, usage, mem, concurrent); + backing = MemoryUtil.memCalloc(size.getBytes(), Byte.BYTES); + ref.refresh(); + } + + @Override + public PointerBuffer map(int offset, int size) { + if (backed) { + location.put(0, MemoryUtil.memAddress(backing, offset)); + return location; + } + return super.map(offset, size); + } + + @Override + public ByteBuffer mapBytes() { + if (backed) { + return backing; + } + return super.mapBytes(); + } + + @Override + public void unmap() { + super.unmap(); + ByteBuffer data = super.mapBytes(); + MemoryUtil.memCopy(data, backing); + super.unmap(); + backed = true; + } + + @Override + public Runnable createNativeDestroyer() { + Runnable sup = super.createNativeDestroyer(); + return () -> { + sup.run(); + MemoryUtil.memFree(location); + MemoryUtil.memFree(backing); + }; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/BasicVulkanBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BasicVulkanBuffer.java new file mode 100644 index 0000000000..4c72abcb85 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BasicVulkanBuffer.java @@ -0,0 +1,93 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.renderer.vulkan.VulkanUtils; +import com.jme3.util.natives.Native; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemoryRegion; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkBufferCreateInfo; +import org.lwjgl.vulkan.VkMemoryRequirements; + +import java.nio.BufferOverflowException; +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.check; +import static org.lwjgl.vulkan.VK10.*; + +public class BasicVulkanBuffer extends AbstractNative implements VulkanBuffer { + + private final LogicalDevice device; + private final MemorySize size; + protected final MemoryRegion memory; + + public BasicVulkanBuffer(LogicalDevice device, MemorySize size, Flag usage, Flag mem, boolean concurrent) { + this.device = device; + this.size = size; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkBufferCreateInfo create = VkBufferCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO) + .size(size.getBytes()) + .usage(usage.bits()) + .sharingMode(VulkanUtils.sharingMode(concurrent)); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateBuffer(device.getNativeObject(), create, null, idBuf), + "Failed to create buffer."); + object = idBuf.get(0); + VkMemoryRequirements bufferMem = VkMemoryRequirements.malloc(stack); + vkGetBufferMemoryRequirements(device.getNativeObject(), object, bufferMem); + memory = new MemoryRegion(device, bufferMem.size(), mem, bufferMem.memoryTypeBits()); + memory.bind(this, 0); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + memory.getNativeReference().addDependent(ref); + } + + @Override + public long getId() { + return object; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyBuffer(device.getNativeObject(), object, null); + } + + @Override + public void verifyBufferSize(int elements, long bytesPerElement) { + if (elements * bytesPerElement > size.getBytes()) { + throw new BufferOverflowException(); + } + } + + @Override + public PointerBuffer map(int offset, int size) { + return memory.map(offset, size); + } + + @Override + public void unmap() { + memory.unmap(); + } + + @Override + public void freeMemory() { + memory.getNativeReference().destroy(); + } + + @Override + public MemorySize size() { + return size; + } + + @Override + public LogicalDevice getDevice() { + return device; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/BufferRegion.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BufferRegion.java new file mode 100644 index 0000000000..c613ab7135 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BufferRegion.java @@ -0,0 +1,68 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.vulkan.memory.MemorySize; + +public class BufferRegion { + + private int offset, end; + + public BufferRegion(int offset, int size) { + this.offset = verifyOffset(offset); + this.end = offset + verifySize(size); + } + + public BufferRegion set(BufferRegion region) { + this.offset = region.offset; + this.end = region.end; + return this; + } + + public BufferRegion set(int offset, int size) { + this.offset = verifyOffset(offset); + this.end = offset + verifySize(size); + return this; + } + + public BufferRegion unionLocal(BufferRegion region) { + offset = Math.min(offset, region.offset); + end = Math.max(end, region.end); + return this; + } + + public BufferRegion unionLocal(int offset, int size) { + this.offset = Math.min(this.offset, verifyOffset(offset)); + this.end = Math.max(this.end, offset + verifySize(size)); + return this; + } + + public int getOffset() { + return offset; + } + + public int getSize() { + return end - offset; + } + + public int getEnd() { + return end; + } + + public static BufferRegion all(MemorySize size) { + return new BufferRegion(0, size.getBytes()); + } + + private static int verifyOffset(int offset) { + if (offset < 0) { + throw new IllegalArgumentException("Offset cannot be negative."); + } + return offset; + } + + private static int verifySize(int size) { + if (size <= 0) { + throw new IllegalArgumentException("Size must be positive."); + } + return size; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/BufferUsage.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BufferUsage.java new file mode 100644 index 0000000000..8e78019c98 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/BufferUsage.java @@ -0,0 +1,30 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.vulkan.util.Flag; + +import static org.lwjgl.vulkan.VK10.*; + +public enum BufferUsage implements Flag { + + Uniform(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), + Index(VK_BUFFER_USAGE_INDEX_BUFFER_BIT), + Storage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), + StorageTexel(VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), + Indirect(VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), + TransferDst(VK_BUFFER_USAGE_TRANSFER_DST_BIT), + TransferSrc(VK_BUFFER_USAGE_TRANSFER_SRC_BIT), + UniformTexel(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT), + Vertex(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + + private final int vkEnum; + + BufferUsage(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int bits() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/GpuBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/GpuBuffer.java new file mode 100644 index 0000000000..3e942d04e9 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/GpuBuffer.java @@ -0,0 +1,207 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.scene.mesh.IndexBuffer; +import com.jme3.scene.mesh.IndexByteBuffer; +import com.jme3.scene.mesh.IndexIntBuffer; +import com.jme3.scene.mesh.IndexShortBuffer; +import com.jme3.vulkan.memory.MemorySize; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.system.Struct; +import org.lwjgl.system.StructBuffer; + +import java.nio.*; +import java.util.function.Function; +import java.util.function.LongFunction; + +public interface GpuBuffer { + + /** + * Maps the memory of this buffer and returns a pointer to the mapped + * region. If the memory is currently mapped when this is called, an + * exception is thrown. + * + * @param offset offset, in bytes, of the mapping + * @param size size, in bytes, of the mapping + * @return Buffer containing a pointer to the mapped memory + */ + PointerBuffer map(int offset, int size); + + void unmap(); + + void freeMemory(); + + MemorySize size(); + + long getId(); + + default void verifyBufferSize(int elements, long bytesPerElement) { + if (elements * bytesPerElement > size().getBytes()) { + throw new BufferOverflowException(); + } + } + + default PointerBuffer map(int offset) { + return map(offset, size().getBytes() - offset); + } + + default PointerBuffer map() { + return map(0, size().getBytes()); + } + + default T map(int offset, int size, Function factory) { + return factory.apply(map(offset, size)); + } + + default T map(int offset, Function factory) { + return factory.apply(map(offset, size().getBytes() - offset)); + } + + default T map(Function factory) { + return factory.apply(map(0, size().getBytes())); + } + + default T map(int offset, int size, LongFunction factory) { + return factory.apply(map(offset, size).get(0)); + } + + default T map(int offset, LongFunction factory) { + return factory.apply(map(offset, size().getBytes() - offset).get(0)); + } + + default T map(LongFunction factory) { + return factory.apply(map(0, size().getBytes()).get(0)); + } + + default ByteBuffer mapBytes(int offset, int size) { + return map(offset * Byte.BYTES, size * Byte.BYTES).getByteBuffer(0, size); + } + + default ByteBuffer mapBytes(int offset) { + return mapBytes(offset, size().getBytes() - offset); + } + + default ByteBuffer mapBytes() { + return mapBytes(0, size().getBytes()); + } + + default ShortBuffer mapShorts(int offset, int size) { + return map(offset * Short.BYTES, size * Short.BYTES).getShortBuffer(0, size); + } + + default ShortBuffer mapShorts(int offset) { + return mapShorts(offset, size().getShorts() - offset); + } + + default ShortBuffer mapShorts() { + return mapShorts(0, size().getShorts()); + } + + default IntBuffer mapInts(int offset, int size) { + return map(offset * Integer.BYTES, size * Integer.BYTES).getIntBuffer(0, size); + } + + default IntBuffer mapInts(int offset) { + return mapInts(offset, size().getInts() - offset); + } + + default IntBuffer mapInts() { + return mapInts(0, size().getInts()); + } + + default FloatBuffer mapFloats(int offset, int size) { + return map(offset * Float.BYTES, size * Float.BYTES).getFloatBuffer(0, size); + } + + default FloatBuffer mapFloats(int offset) { + return mapFloats(offset, size().getFloats() - offset); + } + + default FloatBuffer mapFloats() { + return mapFloats(0, size().getFloats()); + } + + default DoubleBuffer mapDoubles(int offset, int size) { + return map(offset * Double.BYTES, size * Double.BYTES).getDoubleBuffer(0, size); + } + + default DoubleBuffer mapDoubles(int offset) { + return mapDoubles(offset, size().getDoubles() - offset); + } + + default DoubleBuffer mapDoubles() { + return mapDoubles(0, size().getDoubles()); + } + + default LongBuffer mapLongs(int offset, int size) { + return map(offset * Long.BYTES, size * Long.BYTES).getLongBuffer(0, size); + } + + default LongBuffer mapLongs(int offset) { + return mapLongs(offset, size().getLongs() - offset); + } + + default LongBuffer mapLongs() { + return mapLongs(0, size().getLongs()); + } + + default IndexBuffer mapIndices() { + switch (size().getBytesPerElement()) { + case Byte.BYTES: return new IndexByteBuffer(mapBytes()); + case Short.BYTES: return new IndexShortBuffer(mapShorts()); + case Integer.BYTES: return new IndexIntBuffer(mapInts()); + default: throw new UnsupportedOperationException("Cannot map to index buffer with " + + size().getBytesPerElement() + " bytes per element."); + } + } + + default void copy(ByteBuffer buffer) { + verifyBufferSize(buffer.limit(), Byte.BYTES); + MemoryUtil.memCopy(buffer, mapBytes(0, buffer.limit())); + unmap(); + } + + default void copy(ShortBuffer buffer) { + verifyBufferSize(buffer.limit(), Short.BYTES); + MemoryUtil.memCopy(buffer, mapShorts(0, buffer.limit())); + unmap(); + } + + default void copy(IntBuffer buffer) { + verifyBufferSize(buffer.limit(), Integer.BYTES); + MemoryUtil.memCopy(buffer, mapInts(0, buffer.limit())); + unmap(); + } + + default void copy(FloatBuffer buffer) { + verifyBufferSize(buffer.limit(), Float.BYTES); + MemoryUtil.memCopy(buffer, mapFloats(0, buffer.limit())); + unmap(); + } + + default void copy(DoubleBuffer buffer) { + verifyBufferSize(buffer.limit(), Double.BYTES); + MemoryUtil.memCopy(buffer, mapDoubles(0, buffer.limit())); + unmap(); + } + + default void copy(LongBuffer buffer) { + verifyBufferSize(buffer.limit(), Long.BYTES); + MemoryUtil.memCopy(buffer, mapLongs(0, buffer.limit())); + unmap(); + } + + default void copy(Struct struct) { + verifyBufferSize(struct.sizeof(), Byte.BYTES); + MemoryUtil.memCopy(MemoryUtil.memByteBuffer(struct.address(), struct.sizeof()), mapBytes(0, struct.sizeof())); + unmap(); + } + + default void copy(StructBuffer buffer) { + verifyBufferSize(buffer.limit(), buffer.sizeof()); + int size = buffer.limit() * buffer.sizeof(); + MemoryUtil.memCopy(MemoryUtil.memByteBuffer(buffer.address(), size), mapBytes(0, size)); + unmap(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/PersistentBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/PersistentBuffer.java new file mode 100644 index 0000000000..43de9ce30c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/PersistentBuffer.java @@ -0,0 +1,53 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +public class PersistentBuffer extends BasicVulkanBuffer { + + private final PointerBuffer regionAddress; + private final ByteBuffer regionBuffer; + private final PointerBuffer mappedAddress = MemoryUtil.memCallocPointer(1); + + public PersistentBuffer(LogicalDevice device, MemorySize size, Flag usage, boolean concurrent) { + this(device, size, usage, Flag.of(MemoryProp.HostVisible, MemoryProp.HostCoherent), concurrent); + } + + public PersistentBuffer(LogicalDevice device, MemorySize size, Flag usage, Flag mem, boolean concurrent) { + super(device, size, usage, mem, concurrent); + if (!mem.contains(MemoryProp.HostVisible)) { + throw new IllegalArgumentException("Memory must be host visible."); + } + regionAddress = memory.map(0, size.getBytes()); + regionBuffer = regionAddress.getByteBuffer(0, size.getBytes()); + } + + @Override + public PointerBuffer map(int offset, int size) { + if (offset > 0) { + mappedAddress.put(0, MemoryUtil.memAddress(regionBuffer, offset)); + } else { + mappedAddress.put(0, regionAddress.get(0)); + } + return mappedAddress; + } + + @Override + public void unmap() {} + + @Override + public Runnable createNativeDestroyer() { + Runnable sup = super.createNativeDestroyer(); + return () -> { + sup.run(); + MemoryUtil.memFree(mappedAddress); + }; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/StageableBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/StageableBuffer.java new file mode 100644 index 0000000000..f6ae4f1d95 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/StageableBuffer.java @@ -0,0 +1,94 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.commands.CommandPool; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.sync.SyncGroup; +import com.jme3.vulkan.update.Command; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; + +public class StageableBuffer extends BasicVulkanBuffer implements Command { + + protected VulkanBuffer stage; + protected BufferRegion dirtyRegion; + + public StageableBuffer(LogicalDevice device, MemorySize size, + Flag usage, Flag mem, boolean concurrent) { + super(device, size, usage.add(BufferUsage.TransferDst), mem, concurrent); + } + + @Override + public boolean run(CommandBuffer cmd, int frame) { + return transfer(cmd); + } + + @Override + public PointerBuffer map(int offset, int size) { + if (dirtyRegion != null) { + dirtyRegion.unionLocal(offset, size); + } else { + dirtyRegion = new BufferRegion(offset, size); + } + if (stage == null) { + stage = createStagingBuffer(); + } + return stage.map(offset, size); + } + + @Override + public void unmap() { + stage.unmap(); + } + + @Override + public void freeMemory() { + super.freeMemory(); + stage.freeMemory(); + dirtyRegion = null; + } + + protected VulkanBuffer createStagingBuffer() { + return new BasicVulkanBuffer(getDevice(), size(), BufferUsage.TransferSrc, + Flag.of(MemoryProp.HostVisible, MemoryProp.HostCoherent), false); + } + + public void transfer(CommandPool transferPool) { + transfer(transferPool, SyncGroup.ASYNC); + } + + public void transfer(CommandPool transferPool, SyncGroup sync) { + if (stage != null && dirtyRegion != null) { + CommandBuffer cmd = transferPool.allocateTransientCommandBuffer(); + cmd.begin(); + transfer(cmd); + cmd.endAndSubmit(sync); + } + } + + public boolean transfer(CommandBuffer cmd) { + if (stage != null && dirtyRegion != null) { + try (MemoryStack stack = MemoryStack.stackPush()) { + recordCopy(stack, cmd, stage, dirtyRegion.getOffset(), dirtyRegion.getOffset(), dirtyRegion.getSize()); + } + dirtyRegion = null; + return true; + } + return false; + } + + public void freeStagingBuffer() { + if (stage != null) { + stage.freeMemory(); + stage = null; + } + } + + public GpuBuffer getStagingBuffer() { + return stage; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/StaticBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/StaticBuffer.java new file mode 100644 index 0000000000..ddaefc9a0e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/StaticBuffer.java @@ -0,0 +1,23 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.util.Flag; + +public class StaticBuffer extends StageableBuffer { + + public StaticBuffer(LogicalDevice device, MemorySize size, Flag usage, Flag mem, boolean concurrent) { + super(device, size, usage, mem, concurrent); + } + + @Override + public boolean run(CommandBuffer cmd, int frame) { + if (dirtyRegion == null) { + freeStagingBuffer(); + } + return super.run(cmd, frame); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/buffers/VulkanBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/buffers/VulkanBuffer.java new file mode 100644 index 0000000000..46b560582b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/buffers/VulkanBuffer.java @@ -0,0 +1,23 @@ +package com.jme3.vulkan.buffers; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkBufferCopy; + +import static org.lwjgl.vulkan.VK10.*; + +public interface VulkanBuffer extends GpuBuffer { + + LogicalDevice getDevice(); + + default void recordCopy(MemoryStack stack, CommandBuffer commands, GpuBuffer source, + long srcOffset, long dstOffset, long size) { + VkBufferCopy.Buffer copy = VkBufferCopy.calloc(1, stack) + .srcOffset(srcOffset) + .dstOffset(dstOffset) + .size(size); + vkCmdCopyBuffer(commands.getBuffer(), source.getId(), getId(), copy); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/commands/CommandBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/commands/CommandBuffer.java new file mode 100644 index 0000000000..219abc6090 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/commands/CommandBuffer.java @@ -0,0 +1,104 @@ +package com.jme3.vulkan.commands; + +import com.jme3.vulkan.sync.SyncGroup; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkCommandBuffer; +import org.lwjgl.vulkan.VkCommandBufferAllocateInfo; +import org.lwjgl.vulkan.VkCommandBufferBeginInfo; +import org.lwjgl.vulkan.VkSubmitInfo; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class CommandBuffer { + + protected final CommandPool pool; + protected final VkCommandBuffer buffer; + protected boolean recording = false; + + public CommandBuffer(CommandPool pool) { + this.pool = pool; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkCommandBufferAllocateInfo allocate = VkCommandBufferAllocateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO) + .commandPool(pool.getNativeObject()) + .level(VK_COMMAND_BUFFER_LEVEL_PRIMARY) + .commandBufferCount(1); + PointerBuffer ptr = stack.mallocPointer(1); + check(vkAllocateCommandBuffers(pool.getDevice().getNativeObject(), allocate, ptr), + "Failed to allocate command buffer"); + buffer = new VkCommandBuffer(ptr.get(0), pool.getDevice().getNativeObject()); + } + } + + public void begin() { + if (recording) { + throw new IllegalStateException("Command buffer already recording."); + } + try (MemoryStack stack = MemoryStack.stackPush()) { + VkCommandBufferBeginInfo begin = VkCommandBufferBeginInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO); + check(vkBeginCommandBuffer(buffer, begin), "Failed to begin command buffer"); + recording = true; + } + } + + public void resetAndBegin() { + reset(); + begin(); + } + + public void end() { + if (!recording) { + throw new IllegalStateException("Command buffer has not begun recording."); + } + check(vkEndCommandBuffer(buffer), "Failed to record command buffer"); + recording = false; + } + + public void submit(SyncGroup sync) { + if (recording) { + throw new IllegalStateException("Command buffer is still recording."); + } + try (MemoryStack stack = MemoryStack.stackPush()) { + VkSubmitInfo.Buffer submit = VkSubmitInfo.calloc(1, stack) + .sType(VK_STRUCTURE_TYPE_SUBMIT_INFO) + .pCommandBuffers(stack.pointers(buffer)); + if (sync.containsWaits()) { + submit.waitSemaphoreCount(sync.getWaits().length) + .pWaitSemaphores(sync.toWaitBuffer(stack)) + .pWaitDstStageMask(sync.toDstStageBuffer(stack)); + } + if (sync.containsSignals()) { + submit.pSignalSemaphores(sync.toSignalBuffer(stack)); + } + pool.getQueue().submit(submit, sync.getFence()); + } + } + + public void endAndSubmit(SyncGroup sync) { + end(); + submit(sync); + } + + public void reset() { + if (!pool.getFlags().contains(CommandPool.Create.ResetCommandBuffer)) { + throw new UnsupportedOperationException("Command buffer resetting is not supported by the allocating pool."); + } + vkResetCommandBuffer(buffer, 0); + } + + public CommandPool getPool() { + return pool; + } + + public VkCommandBuffer getBuffer() { + return buffer; + } + + public boolean isRecording() { + return recording; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/commands/CommandPool.java b/jme3-core/src/main/java/com/jme3/vulkan/commands/CommandPool.java new file mode 100644 index 0000000000..de3d4dfeed --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/commands/CommandPool.java @@ -0,0 +1,104 @@ +package com.jme3.vulkan.commands; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkCommandPoolCreateInfo; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK11.*; + +public class CommandPool implements Native { + + public enum Create implements Flag { + + Transient(VK_COMMAND_POOL_CREATE_TRANSIENT_BIT), + ResetCommandBuffer(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT), + Protected(VK_COMMAND_POOL_CREATE_PROTECTED_BIT); + + private final int vkEnum; + + Create(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int bits() { + return vkEnum; + } + + } + + private final Queue queue; + private final NativeReference ref; + private final Flag flags; + private long id; + + public CommandPool(Queue queue) { + this(queue, Create.ResetCommandBuffer); + } + + public CommandPool(Queue queue, Flag flags) { + this.queue = queue; + this.flags = flags; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkCommandPoolCreateInfo create = VkCommandPoolCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO) + .flags(this.flags.bits()) + .queueFamilyIndex(queue.getFamilyIndex()); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateCommandPool(queue.getDevice().getNativeObject(), create, null, idBuf), + "Failed to create command pool."); + id = idBuf.get(0); + } + ref = Native.get().register(this); + queue.getDevice().getNativeReference().addDependent(ref); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> { + vkDestroyCommandPool(queue.getDevice().getNativeObject(), id, null); + }; + } + + @Override + public void prematureNativeDestruction() { + id = VK_NULL_HANDLE; + } + + @Override + public NativeReference getNativeReference() { + return null; + } + + public CommandBuffer allocateCommandBuffer() { + return new CommandBuffer(this); + } + + public TransientCommandBuffer allocateTransientCommandBuffer() { + return new TransientCommandBuffer(this); + } + + public LogicalDevice getDevice() { + return queue.getDevice(); + } + + public Queue getQueue() { + return queue; + } + + public Flag getFlags() { + return flags; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/commands/Queue.java b/jme3-core/src/main/java/com/jme3/vulkan/commands/Queue.java new file mode 100644 index 0000000000..faaff260f4 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/commands/Queue.java @@ -0,0 +1,59 @@ +package com.jme3.vulkan.commands; + +import com.jme3.vulkan.sync.Fence; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkQueue; +import org.lwjgl.vulkan.VkSubmitInfo; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class Queue { + + private final LogicalDevice device; + private final VkQueue queue; + private final int familyIndex, queueIndex; + + public Queue(LogicalDevice device, int familyIndex, int queueIndex) { + this.device = device; + this.familyIndex = familyIndex; + this.queueIndex = queueIndex; + try (MemoryStack stack = MemoryStack.stackPush()) { + PointerBuffer ptr = stack.mallocPointer(1); + vkGetDeviceQueue(device.getNativeObject(), familyIndex, queueIndex, ptr); + queue = new VkQueue(ptr.get(0), device.getNativeObject()); + } + } + + public void submit(VkSubmitInfo.Buffer info) { + submit(info, null); + } + + public void submit(VkSubmitInfo.Buffer info, Fence fence) { + check(vkQueueSubmit(queue, info, fence != null ? fence.getNativeObject() : VK_NULL_HANDLE), + "Failed to submit to queue."); + } + + public void waitIdle() { + vkQueueWaitIdle(queue); + } + + public LogicalDevice getDevice() { + return device; + } + + public VkQueue getQueue() { + return queue; + } + + public int getFamilyIndex() { + return familyIndex; + } + + public int getQueueIndex() { + return queueIndex; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/commands/QueueFamilies.java b/jme3-core/src/main/java/com/jme3/vulkan/commands/QueueFamilies.java new file mode 100644 index 0000000000..0290b5d5b3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/commands/QueueFamilies.java @@ -0,0 +1,23 @@ +package com.jme3.vulkan.commands; + +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.devices.PhysicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDeviceQueueCreateInfo; +import org.lwjgl.vulkan.VkQueueFamilyProperties; + +import java.nio.IntBuffer; + +public interface QueueFamilies { + + boolean populate(PhysicalDevice device, VkQueueFamilyProperties.Buffer properties); + + VkDeviceQueueCreateInfo.Buffer createLogicalBuffers(MemoryStack stack); + + void createQueues(LogicalDevice device); + + boolean isComplete(); + + IntBuffer getSwapchainConcurrentBuffers(MemoryStack stack); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/commands/TransientCommandBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/commands/TransientCommandBuffer.java new file mode 100644 index 0000000000..b2de94614a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/commands/TransientCommandBuffer.java @@ -0,0 +1,64 @@ +package com.jme3.vulkan.commands; + +import com.jme3.vulkan.sync.SyncGroup; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkCommandBufferBeginInfo; +import org.lwjgl.vulkan.VkSubmitInfo; + +import static org.lwjgl.vulkan.VK10.*; + +public class TransientCommandBuffer extends CommandBuffer { + + private boolean active = false; + + public TransientCommandBuffer(CommandPool pool) { + super(pool); + } + + @Override + public void begin() { + if (recording) { + throw new IllegalStateException("Command buffer already recording."); + } + if (active) { + throw new IllegalStateException("One-time command buffer has already been used."); + } + try (MemoryStack stack = MemoryStack.stackPush()) { + VkCommandBufferBeginInfo begin = VkCommandBufferBeginInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO) + .flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkBeginCommandBuffer(buffer, begin); + } + recording = true; + } + + @Override + public void submit(SyncGroup sync) { + if (recording) { + throw new IllegalStateException("Command buffer is still recording."); + } + try (MemoryStack stack = MemoryStack.stackPush()) { + VkSubmitInfo.Buffer submit = VkSubmitInfo.calloc(1, stack) + .sType(VK_STRUCTURE_TYPE_SUBMIT_INFO) + .pCommandBuffers(stack.pointers(buffer)); + if (sync.containsWaits()) { + submit.waitSemaphoreCount(sync.getWaits().length) + .pWaitSemaphores(sync.toWaitBuffer(stack)) + .pWaitDstStageMask(sync.toDstStageBuffer(stack)); + } + if (sync.containsSignals()) { + submit.pSignalSemaphores(sync.toSignalBuffer(stack)); + } + pool.getQueue().submit(submit, sync.getFence()); + pool.getQueue().waitIdle(); + vkFreeCommandBuffers(pool.getDevice().getNativeObject(), pool.getNativeObject(), buffer); + } + active = false; + recording = false; + } + + public boolean isActive() { + return active; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BaseDescriptorWriter.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BaseDescriptorWriter.java new file mode 100644 index 0000000000..3440148f8b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BaseDescriptorWriter.java @@ -0,0 +1,41 @@ +package com.jme3.vulkan.descriptors; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkWriteDescriptorSet; + +public class BaseDescriptorWriter implements DescriptorSetWriter { + + private final Descriptor type; + private final int binding, arrayElement, descriptorCount; + + public BaseDescriptorWriter(Descriptor type, int binding, int arrayElement, int descriptorCount) { + this.type = type; + this.binding = binding; + this.arrayElement = arrayElement; + this.descriptorCount = descriptorCount; + } + + @Override + public void populateWrite(MemoryStack stack, VkWriteDescriptorSet write) { + write.descriptorType(type.getEnum()).dstBinding(binding) + .dstArrayElement(arrayElement) + .descriptorCount(descriptorCount); + } + + public Descriptor getType() { + return type; + } + + public int getBinding() { + return binding; + } + + public int getArrayElement() { + return arrayElement; + } + + public int getDescriptorCount() { + return descriptorCount; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BufferDescriptor.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BufferDescriptor.java new file mode 100644 index 0000000000..a8cd7e58b3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BufferDescriptor.java @@ -0,0 +1,37 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.vulkan.buffers.GpuBuffer; +import org.lwjgl.vulkan.VkDescriptorBufferInfo; + +public class BufferDescriptor { + + private final GpuBuffer buffer; + private final long offset, range; + + public BufferDescriptor(GpuBuffer buffer) { + this(buffer, 0, buffer.size().getBytes()); + } + + public BufferDescriptor(GpuBuffer buffer, long offset, long range) { + this.buffer = buffer; + this.offset = offset; + this.range = range; + } + + public void fillDescriptorInfo(VkDescriptorBufferInfo info) { + info.buffer(buffer.getId()).offset(offset).range(range); + } + + public GpuBuffer getBuffer() { + return buffer; + } + + public long getOffset() { + return offset; + } + + public long getRange() { + return range; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BufferSetWriter.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BufferSetWriter.java new file mode 100644 index 0000000000..f0b27d7d61 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/BufferSetWriter.java @@ -0,0 +1,27 @@ +package com.jme3.vulkan.descriptors; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDescriptorBufferInfo; +import org.lwjgl.vulkan.VkWriteDescriptorSet; + +public class BufferSetWriter extends BaseDescriptorWriter { + + private final BufferDescriptor[] descriptors; + + public BufferSetWriter(Descriptor type, int binding, int arrayElement, BufferDescriptor... descriptors) { + super(type, binding, arrayElement, descriptors.length); + this.descriptors = descriptors; + } + + @Override + public void populateWrite(MemoryStack stack, VkWriteDescriptorSet write) { + super.populateWrite(stack, write); + VkDescriptorBufferInfo.Buffer info = VkDescriptorBufferInfo.calloc(descriptors.length, stack); + for (BufferDescriptor d : descriptors) { + d.fillDescriptorInfo(info.get()); + } + info.flip(); + write.pBufferInfo(info); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/Descriptor.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/Descriptor.java new file mode 100644 index 0000000000..69a08b21d7 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/Descriptor.java @@ -0,0 +1,32 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum Descriptor implements IntEnum { + + UniformBuffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER), + UniformBufferDynamic(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC), + StorageBuffer(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER), + StorageBufferDynamic(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC), + CombinedImageSampler(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER), + Sampler(VK_DESCRIPTOR_TYPE_SAMPLER), + SampledImage(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE), + InputAttachment(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT), + StorageImage(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE), + StorageTexelBuffer(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER), + UniformTexelBuffer(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER); + + private final int vkEnum; + + Descriptor(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorPool.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorPool.java new file mode 100644 index 0000000000..5485f1347b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorPool.java @@ -0,0 +1,113 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.renderer.vulkan.VulkanUtils; +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.check; +import static org.lwjgl.vulkan.VK10.*; + +public class DescriptorPool implements Native { + + public enum Create implements Flag { + + FreeDescriptorSets(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT); + + private final int vkEnum; + + Create(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int bits() { + return vkEnum; + } + + } + + private final LogicalDevice device; + private final NativeReference ref; + private final Flag flags; + private final long id; + + public DescriptorPool(LogicalDevice device, int sets, PoolSize... sizes) { + this(device, sets, Flag.empty(), sizes); + } + + public DescriptorPool(LogicalDevice device, int sets, Flag flags, PoolSize... sizes) { + this.device = device; + this.flags = flags; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkDescriptorPoolCreateInfo create = VkDescriptorPoolCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO) + .pPoolSizes(PoolSize.aggregate(stack, sizes)) + .maxSets(sets) + .flags(this.flags.bits()); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateDescriptorPool(device.getNativeObject(), create, null, idBuf), + "Failed to create descriptor pool."); + id = idBuf.get(0); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyDescriptorPool(device.getNativeObject(), id, null); + } + + @Override + public void prematureNativeDestruction() {} + + @Override + public NativeReference getNativeReference() { + return ref; + } + + /** + * Allocates a {@link DescriptorSet} for each {@link DescriptorSetLayout} provided. + * + * @param layouts layouts to allocate DescriptorSets with + * @return allocated DescriptorSets, in the same order as {@code layouts} + */ + public DescriptorSet[] allocateSets(DescriptorSetLayout... layouts) { + assert layouts.length > 0 : "Must specify at least one set layout."; + // layouts length = number of descriptor sets created + DescriptorSet[] sets = new DescriptorSet[layouts.length]; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkDescriptorSetAllocateInfo allocate = VkDescriptorSetAllocateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO) + .descriptorPool(id) + .pSetLayouts(VulkanUtils.accumulate(stack, layouts)); + LongBuffer setBuf = stack.mallocLong(layouts.length); + check(vkAllocateDescriptorSets(device.getNativeObject(), allocate, setBuf), + "Failed to allocate descriptor sets."); + for (int i = 0; i < setBuf.limit(); i++) { + sets[i] = new DescriptorSet(device, this, layouts[i], setBuf.get(i)); + } + } + return sets; + } + + public void reset() { + vkResetDescriptorPool(device.getNativeObject(), id, 0); + } + + public Flag getFlags() { + return flags; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSet.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSet.java new file mode 100644 index 0000000000..11c8f8cced --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSet.java @@ -0,0 +1,67 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkWriteDescriptorSet; + +import static org.lwjgl.vulkan.VK10.*; + +public class DescriptorSet extends AbstractNative { + + private final LogicalDevice device; + private final DescriptorPool pool; + private final DescriptorSetLayout layout; + + public DescriptorSet(LogicalDevice device, DescriptorPool pool, DescriptorSetLayout layout, long id) { + this.device = device; + this.pool = pool; + this.layout = layout; + this.object = id; + ref = Native.get().register(this); + pool.getNativeReference().addDependent(ref); + } + + @Override + public Runnable createNativeDestroyer() { + return () -> { + if (pool.getFlags().contains(DescriptorPool.Create.FreeDescriptorSets)) { + try (MemoryStack stack = MemoryStack.stackPush()) { + vkFreeDescriptorSets(device.getNativeObject(), pool.getNativeObject(), stack.longs(object)); + } + } + }; + } + + public void write(DescriptorSetWriter... writers) { + try (MemoryStack stack = MemoryStack.stackPush()) { + VkWriteDescriptorSet.Buffer write = VkWriteDescriptorSet.calloc(writers.length, stack); + for (DescriptorSetWriter w : writers) { + w.populateWrite(stack, write.get() + .sType(VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET) + .dstSet(object)); + } + write.flip(); + vkUpdateDescriptorSets(device.getNativeObject(), write, null); + } + } + + @Deprecated + public long getId() { + return object; + } + + public LogicalDevice getDevice() { + return device; + } + + public DescriptorPool getPool() { + return pool; + } + + public DescriptorSetLayout getLayout() { + return layout; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSetLayout.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSetLayout.java new file mode 100644 index 0000000000..321bb5f298 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSetLayout.java @@ -0,0 +1,65 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDescriptorSetLayoutBinding; +import org.lwjgl.vulkan.VkDescriptorSetLayoutCreateInfo; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.check; +import static org.lwjgl.vulkan.VK10.*; + +public class DescriptorSetLayout implements Native { + + private final LogicalDevice device; + private final NativeReference ref; + private final SetLayoutBinding[] bindings; + private final long id; + + public DescriptorSetLayout(LogicalDevice device, SetLayoutBinding... bindings) { + this.device = device; + this.bindings = bindings; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkDescriptorSetLayoutBinding.Buffer layoutBindings = VkDescriptorSetLayoutBinding.calloc(bindings.length, stack); + for (SetLayoutBinding b : bindings) { + b.fillLayoutBinding(layoutBindings.get()); + } + layoutBindings.flip(); + VkDescriptorSetLayoutCreateInfo create = VkDescriptorSetLayoutCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO) + .pBindings(layoutBindings); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateDescriptorSetLayout(device.getNativeObject(), create, null, idBuf), + "Failed to create descriptor set layout."); + id = idBuf.get(0); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyDescriptorSetLayout(device.getNativeObject(), id, null); + } + + @Override + public void prematureNativeDestruction() {} + + @Override + public NativeReference getNativeReference() { + return ref; + } + + public SetLayoutBinding[] getBindings() { + return bindings; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSetWriter.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSetWriter.java new file mode 100644 index 0000000000..f21740f2de --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/DescriptorSetWriter.java @@ -0,0 +1,10 @@ +package com.jme3.vulkan.descriptors; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkWriteDescriptorSet; + +public interface DescriptorSetWriter { + + void populateWrite(MemoryStack stack, VkWriteDescriptorSet write); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/ImageDescriptor.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/ImageDescriptor.java new file mode 100644 index 0000000000..9575318b28 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/ImageDescriptor.java @@ -0,0 +1,40 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.vulkan.images.*; +import org.lwjgl.vulkan.VkDescriptorImageInfo; + +public class ImageDescriptor { + + private final VulkanImageView view; + private final Sampler sampler; + private final VulkanImage.Layout layout; + + public ImageDescriptor(VulkanTexture texture, VulkanImage.Layout layout) { + this(texture.getImage(), texture, layout); + } + + public ImageDescriptor(VulkanImageView view, Sampler sampler, VulkanImage.Layout layout) { + this.view = view; + this.sampler = sampler; + this.layout = layout; + } + + public void fillDescriptorInfo(VkDescriptorImageInfo info) { + info.imageView(view.getNativeObject()) + .sampler(sampler.getNativeObject()) + .imageLayout(layout.getEnum()); + } + + public VulkanImageView getView() { + return view; + } + + public Sampler getSampler() { + return sampler; + } + + public VulkanImage.Layout getLayout() { + return layout; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/ImageSetWriter.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/ImageSetWriter.java new file mode 100644 index 0000000000..b3d7d0c789 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/ImageSetWriter.java @@ -0,0 +1,27 @@ +package com.jme3.vulkan.descriptors; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDescriptorImageInfo; +import org.lwjgl.vulkan.VkWriteDescriptorSet; + +public class ImageSetWriter extends BaseDescriptorWriter { + + private final ImageDescriptor[] descriptors; + + public ImageSetWriter(Descriptor type, int binding, int arrayElement, ImageDescriptor... descriptors) { + super(type, binding, arrayElement, descriptors.length); + this.descriptors = descriptors; + } + + @Override + public void populateWrite(MemoryStack stack, VkWriteDescriptorSet write) { + super.populateWrite(stack, write); + VkDescriptorImageInfo.Buffer info = VkDescriptorImageInfo.calloc(descriptors.length, stack); + for (ImageDescriptor d : descriptors) { + d.fillDescriptorInfo(info.get()); + } + info.flip(); + write.pImageInfo(info); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/PoolSize.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/PoolSize.java new file mode 100644 index 0000000000..976f7214b5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/PoolSize.java @@ -0,0 +1,34 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDescriptorPoolSize; + +public class PoolSize { + + private final IntEnum type; + private final int size; + + public PoolSize(IntEnum type, int size) { + this.type = type; + this.size = size; + } + + public IntEnum getType() { + return type; + } + + public int getSize() { + return size; + } + + public static VkDescriptorPoolSize.Buffer aggregate(MemoryStack stack, PoolSize... sizes) { + VkDescriptorPoolSize.Buffer buffer = VkDescriptorPoolSize.calloc(sizes.length, stack); + for (PoolSize poolSize : sizes) { + buffer.get().set(poolSize.type.getEnum(), poolSize.size); + } + buffer.flip(); + return buffer; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/descriptors/SetLayoutBinding.java b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/SetLayoutBinding.java new file mode 100644 index 0000000000..6e37abf797 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/descriptors/SetLayoutBinding.java @@ -0,0 +1,50 @@ +package com.jme3.vulkan.descriptors; + +import com.jme3.vulkan.shader.ShaderStage; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.vulkan.VkDescriptorSetLayoutBinding; + +public class SetLayoutBinding { + + private final IntEnum type; + private final int binding, descriptors; + private final Flag stages; + + public SetLayoutBinding(IntEnum type, int binding, int descriptors) { + this(type, binding, descriptors, ShaderStage.All); + } + + public SetLayoutBinding(IntEnum type, int binding, int descriptors, Flag stages) { + this.type = type; + this.binding = binding; + this.descriptors = descriptors; + this.stages = stages; + } + + @SuppressWarnings("DataFlowIssue") + public void fillLayoutBinding(VkDescriptorSetLayoutBinding layoutBinding) { + layoutBinding.descriptorType(type.getEnum()) + .binding(binding) + .descriptorCount(descriptors) + .stageFlags(stages.bits()) + .pImmutableSamplers(null); + } + + public IntEnum getType() { + return type; + } + + public int getBinding() { + return binding; + } + + public int getDescriptors() { + return descriptors; + } + + public Flag getStages() { + return stages; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/AbstractPhysicalDevice.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/AbstractPhysicalDevice.java new file mode 100644 index 0000000000..3a551c7313 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/AbstractPhysicalDevice.java @@ -0,0 +1,108 @@ +package com.jme3.vulkan.devices; + +import com.jme3.vulkan.Format; +import com.jme3.vulkan.VulkanInstance; +import com.jme3.vulkan.images.VulkanImage; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.surface.Surface; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.enumerateBuffer; +import static org.lwjgl.vulkan.VK10.*; + +public abstract class AbstractPhysicalDevice implements PhysicalDevice { + + private final VulkanInstance instance; + private final VkPhysicalDevice physicalDevice; + + public AbstractPhysicalDevice(VulkanInstance instance, long id) { + this.instance = instance; + this.physicalDevice = new VkPhysicalDevice(id, instance.getNativeObject()); + } + + @Override + public VulkanInstance getInstance() { + return instance; + } + + @Override + public VkPhysicalDevice getDeviceHandle() { + return physicalDevice; + } + + @Override + public VkQueueFamilyProperties.Buffer getQueueFamilyProperties(MemoryStack stack) { + return enumerateBuffer(stack, n -> VkQueueFamilyProperties.calloc(n, stack), (count, buffer) + -> vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, count, buffer)); + } + + @Override + public VkPhysicalDeviceProperties getProperties(MemoryStack stack) { + VkPhysicalDeviceProperties props = VkPhysicalDeviceProperties.malloc(stack); + vkGetPhysicalDeviceProperties(physicalDevice, props); + return props; + } + + @Override + public VkPhysicalDeviceFeatures getFeatures(MemoryStack stack) { + VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.malloc(stack); + vkGetPhysicalDeviceFeatures(physicalDevice, features); + return features; + } + + @Override + public VkExtensionProperties.Buffer getExtensionProperties(MemoryStack stack) { + return enumerateBuffer(stack, n -> VkExtensionProperties.malloc(n, stack), (count, buffer) -> + vkEnumerateDeviceExtensionProperties(physicalDevice, (ByteBuffer)null, count, buffer)); + } + + @Override + public VkPhysicalDeviceMemoryProperties getMemoryProperties(MemoryStack stack) { + VkPhysicalDeviceMemoryProperties mem = VkPhysicalDeviceMemoryProperties.malloc(stack); + vkGetPhysicalDeviceMemoryProperties(physicalDevice, mem); + return mem; + } + + @Override + public int findSupportedMemoryType(MemoryStack stack, int types, Flag flags) { + VkPhysicalDeviceMemoryProperties mem = getMemoryProperties(stack); + for (int i = 0; i < mem.memoryTypeCount(); i++) { + if ((types & (1 << i)) != 0 && (mem.memoryTypes().get(i).propertyFlags() & flags.bits()) != 0) { + return i; + } + } + throw new NullPointerException("Suitable memory type not found."); + } + + @Override + public Format findSupportedFormat(VulkanImage.Tiling tiling, int features, Format... candidates) { + VkFormatProperties props = VkFormatProperties.create(); + for (Format f : candidates) { + vkGetPhysicalDeviceFormatProperties(physicalDevice, f.getVkEnum(), props); + if ((tiling == VulkanImage.Tiling.Linear && (props.linearTilingFeatures() & features) == features) + || (tiling == VulkanImage.Tiling.Optimal && (props.optimalTilingFeatures() & features) == features)) { + return f; + } + } + throw new NullPointerException("Failed to find supported format."); + } + + @Override + public boolean querySwapchainSupport(Surface surface) { + try (MemoryStack stack = MemoryStack.stackPush()) { + IntBuffer count = stack.mallocInt(1); + KHRSurface.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface.getNativeObject(), count, null); + if (count.get(0) <= 0) { + return false; + } + KHRSurface.vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface.getNativeObject(), count, null); + return count.get(0) > 0; + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceExtension.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceExtension.java new file mode 100644 index 0000000000..35eca346d3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceExtension.java @@ -0,0 +1,65 @@ +package com.jme3.vulkan.devices; + +import java.util.Objects; +import java.util.Set; + +public class DeviceExtension { + + private final String name; + private final Float success, fail; + + public DeviceExtension(String name) { + this(name, 1f, null); + } + + public DeviceExtension(String name, Float success) { + this(name, success, null); + } + + public DeviceExtension(String name, Float success, Float fail) { + this.name = name; + this.success = success; + this.fail = fail; + } + + public Float evaluate(Set extensions) { + return extensions.contains(name) ? success : fail; + } + + public String getName() { + return name; + } + + public Float getSuccessWeight() { + return success; + } + + public Float getFailWeight() { + return fail; + } + + public boolean isRejectOnFailure() { + return fail == null; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + DeviceExtension that = (DeviceExtension) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } + + public static DeviceExtension critical(String name) { + return new DeviceExtension(name, 1f, null); + } + + public static DeviceExtension optional(String name, float successWeight) { + return new DeviceExtension(name, successWeight); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceFeature.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceFeature.java new file mode 100644 index 0000000000..886c2ccf5f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceFeature.java @@ -0,0 +1,24 @@ +package com.jme3.vulkan.devices; + +import org.lwjgl.vulkan.VkPhysicalDeviceFeatures; + +public interface DeviceFeature { + + void enableFeature(VkPhysicalDeviceFeatures features); + + Float evaluateFeatureSupport(VkPhysicalDeviceFeatures features); + + static DeviceFeature anisotropy(Float pass, boolean rejectOnFail) { + return new DeviceFeature() { + @Override + public void enableFeature(VkPhysicalDeviceFeatures features) { + features.samplerAnisotropy(true); + } + @Override + public Float evaluateFeatureSupport(VkPhysicalDeviceFeatures features) { + return features.samplerAnisotropy() ? pass : (rejectOnFail ? null : 0f); + } + }; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceFilter.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceFilter.java new file mode 100644 index 0000000000..a59a15b69c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceFilter.java @@ -0,0 +1,84 @@ +package com.jme3.vulkan.devices; + +import com.jme3.vulkan.surface.Surface; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkExtensionProperties; + +import java.util.Arrays; +import java.util.Collection; + +public interface DeviceFilter { + + Float evaluateDevice(PhysicalDevice device); + + static DeviceExtensionSupport extensions(String... exts) { + return new DeviceExtensionSupport(Arrays.asList(exts)); + } + + static DeviceExtensionSupport extensions(Collection exts) { + return new DeviceExtensionSupport(exts); + } + + static DeviceSwapchainSupport swapchain(Surface surface) { + return new DeviceSwapchainSupport(surface); + } + + static DeviceAnisotropySupport anisotropy() { + return new DeviceAnisotropySupport(); + } + + class DeviceExtensionSupport implements DeviceFilter { + + private final Collection extensions; + + public DeviceExtensionSupport(Collection extensions) { + this.extensions = extensions; + } + + @Override + public Float evaluateDevice(PhysicalDevice device) { + try (MemoryStack stack = MemoryStack.stackPush()) { + VkExtensionProperties.Buffer exts = device.getExtensionProperties(stack); + if (extensions.stream().allMatch(e -> exts.stream().anyMatch( + p -> p.extensionNameString().equals(e)))) { + return 0f; + } + return null; + } + } + + } + + class DeviceSwapchainSupport implements DeviceFilter { + + private final Surface surface; + + public DeviceSwapchainSupport(Surface surface) { + this.surface = surface; + } + + @Override + public Float evaluateDevice(PhysicalDevice device) { + if (device.querySwapchainSupport(surface)) { + return 0f; + } + return null; + } + + } + + class DeviceAnisotropySupport implements DeviceFilter { + + @Override + public Float evaluateDevice(PhysicalDevice device) { + try (MemoryStack stack = MemoryStack.stackPush()) { + if (device.getFeatures(stack).samplerAnisotropy()) { + return 0f; + } + return null; + } + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceProperty.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceProperty.java new file mode 100644 index 0000000000..f2919af8ae --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/DeviceProperty.java @@ -0,0 +1,13 @@ +package com.jme3.vulkan.devices; + +import org.lwjgl.vulkan.VkPhysicalDeviceProperties; + +public interface DeviceProperty { + + Float evaluateDeviceProperties(VkPhysicalDeviceProperties properties); + + static DeviceProperty maxAnisotropy(float threshold) { + return p -> p.limits().maxSamplerAnisotropy() >= threshold ? 0f : null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/GeneralPhysicalDevice.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/GeneralPhysicalDevice.java new file mode 100644 index 0000000000..50c73a46b7 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/GeneralPhysicalDevice.java @@ -0,0 +1,93 @@ +package com.jme3.vulkan.devices; + +import com.jme3.vulkan.commands.Queue; +import com.jme3.vulkan.VulkanInstance; +import com.jme3.vulkan.surface.Surface; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.KHRSurface; +import org.lwjgl.vulkan.VkDeviceQueueCreateInfo; +import org.lwjgl.vulkan.VkQueueFamilyProperties; + +import java.nio.IntBuffer; + +import static org.lwjgl.vulkan.VK10.*; + +public class GeneralPhysicalDevice extends AbstractPhysicalDevice implements GraphicalDevice, PresentDevice { + + private final Surface surface; + private Integer graphicsIndex, presentIndex; + private Queue graphics, present; + + public GeneralPhysicalDevice(VulkanInstance instance, Surface surface, long id) { + super(instance, id); + this.surface = surface; + } + + @Override + public boolean populateQueueFamilyIndices() { + try (MemoryStack stack = MemoryStack.stackPush()) { + VkQueueFamilyProperties.Buffer properties = getQueueFamilyProperties(stack); + IntBuffer ibuf = stack.callocInt(1); + for (int i = 0; i < properties.limit(); i++) { + VkQueueFamilyProperties props = properties.get(i); + int flags = props.queueFlags(); + if (graphicsIndex == null && (flags & VK_QUEUE_GRAPHICS_BIT) > 0) { + graphicsIndex = i; + } else if (presentIndex == null) { + KHRSurface.vkGetPhysicalDeviceSurfaceSupportKHR(getDeviceHandle(), + i, surface.getNativeObject(), ibuf); + if (ibuf.get(0) == VK_TRUE) { + presentIndex = i; + } + } + if (allQueuesAvailable()) { + return true; + } + } + } + return allQueuesAvailable(); + } + + @Override + public VkDeviceQueueCreateInfo.Buffer createQueueFamilyInfo(MemoryStack stack) { + VkDeviceQueueCreateInfo.Buffer create = VkDeviceQueueCreateInfo.calloc(2, stack); + create.get(0).sType(VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO) + .queueFamilyIndex(graphicsIndex) + .pQueuePriorities(stack.floats(1f)); + create.get(1).sType(VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO) + .queueFamilyIndex(presentIndex) + .pQueuePriorities(stack.floats(1f)); + return create; + } + + @Override + public void createQueues(LogicalDevice device) { + graphics = new Queue(device, graphicsIndex, 0); + present = new Queue(device, presentIndex, 0); + } + + @Override + public Queue getGraphics() { + return graphics; + } + + @Override + public Queue getPresent() { + return present; + } + + @Override + public Queue getCompute() { + return graphics; + } + + @Override + public Queue getDataTransfer() { + return graphics; + } + + public boolean allQueuesAvailable() { + return graphicsIndex != null && presentIndex != null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/GraphicalDevice.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/GraphicalDevice.java new file mode 100644 index 0000000000..cae4a8fb73 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/GraphicalDevice.java @@ -0,0 +1,9 @@ +package com.jme3.vulkan.devices; + +import com.jme3.vulkan.commands.Queue; + +public interface GraphicalDevice extends PhysicalDevice { + + Queue getGraphics(); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/LogicalDevice.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/LogicalDevice.java new file mode 100644 index 0000000000..af92f359a0 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/LogicalDevice.java @@ -0,0 +1,228 @@ +package com.jme3.vulkan.devices; + +import com.jme3.util.natives.Native; +import com.jme3.vulkan.VulkanInstance; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.commands.CommandPool; +import com.jme3.vulkan.commands.Queue; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class LogicalDevice extends AbstractNative { + + private final VulkanInstance instance; + private final Set enabledExtensions = new HashSet<>(); + private final VkPhysicalDeviceFeatures enabledFeatures = VkPhysicalDeviceFeatures.calloc(); + private final Map> pools = new ConcurrentHashMap<>(); + private T physical; + + public LogicalDevice(VulkanInstance instance) { + this.instance = instance; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> { + vkDestroyDevice(object, null); + enabledFeatures.free(); + }; + } + + public void waitIdle() { + vkDeviceWaitIdle(object); + } + + public T getPhysicalDevice() { + return physical; + } + + public Set getEnabledExtensions() { + return Collections.unmodifiableSet(enabledExtensions); + } + + public VkPhysicalDeviceFeatures getEnabledFeatures() { + return enabledFeatures; + } + + public CommandPool getShortTermPool(Queue queue) { + return getPool(queue, CommandPool.Create.Transient); + } + + public CommandPool getLongTermPool(Queue queue) { + return getPool(queue, CommandPool.Create.ResetCommandBuffer); + } + + public CommandPool getPool(Queue queue, Flag flags) { + if (queue.getDevice() != this) { + throw new IllegalArgumentException("Queue must belong to this device."); + } + Collection p = pools.computeIfAbsent(Thread.currentThread(), + t -> new ArrayList<>()); + for (CommandPool pool : p) { + if (pool.getQueue() == queue && pool.getFlags().contains(flags)) { + return pool; + } + } + CommandPool pool = new CommandPool(queue, flags); + p.add(pool); + return pool; + } + + public Builder build(Function deviceFactory) { + return new Builder(deviceFactory); + } + + public class Builder extends AbstractNative.Builder { + + private final Function deviceFactory; + private final Set extensions = new HashSet<>(); + private final Collection features = new ArrayList<>(); + private final Collection filters = new ArrayList<>(); + private boolean enableAllFeatures = false; + + public Builder(Function deviceFactory) { + this.deviceFactory = deviceFactory; + } + + @Override + protected void build() { + findSuitablePhysicalDevice(); + VkPhysicalDeviceFeatures supportedFeatures = physical.getFeatures(stack); + if (enableAllFeatures) { + enabledFeatures.set(supportedFeatures); + } else for (DeviceFeature f : features) { + if (f.evaluateFeatureSupport(supportedFeatures) != null) { + f.enableFeature(enabledFeatures); + } + } + VkDeviceCreateInfo create = VkDeviceCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO) + .pQueueCreateInfos(physical.createQueueFamilyInfo(stack)) + .pEnabledFeatures(enabledFeatures); + if (!extensions.isEmpty()) { + PointerBuffer exts = stack.mallocPointer(extensions.size()); + for (DeviceExtension e : extensions) { + enabledExtensions.add(e.getName()); + exts.put(stack.UTF8(e.getName())); + } + create.ppEnabledExtensionNames(exts.flip()); + } + Set layers = physical.getInstance().getLayers(); + if (!layers.isEmpty()) { + PointerBuffer lyrs = stack.mallocPointer(layers.size()); + for (String l : layers) { + lyrs.put(stack.UTF8(l)); + } + create.ppEnabledLayerNames(lyrs.flip()); + } + PointerBuffer ptr = stack.mallocPointer(1); + check(vkCreateDevice(physical.getDeviceHandle(), create, null, ptr), + "Failed to create logical device."); + object = new VkDevice(ptr.get(0), physical.getDeviceHandle(), create); + ref = Native.get().register(LogicalDevice.this); + physical.getInstance().getNativeReference().addDependent(ref); + physical.createQueues(LogicalDevice.this); + } + + private void findSuitablePhysicalDevice() { + PointerBuffer devices = enumerateBuffer(stack, stack::mallocPointer, + (count, buffer) -> check( + vkEnumeratePhysicalDevices(instance.getNativeObject(), count, buffer), + "Failed to enumerate physical devices.")); + physical = null; + float topWeight = Float.NEGATIVE_INFINITY; + deviceLoop: for (T d : iteratePointers(devices, deviceFactory::apply)) { + if (!d.populateQueueFamilyIndices()) { + continue; + } + // attempting to evaluate all devices with only one memory stack + // results in an out of memory error + try (MemoryStack stack = MemoryStack.stackPush()) { + float deviceWeight = 0f; + // extensions + VkExtensionProperties.Buffer supportedExts = d.getExtensionProperties(stack); + Set extSet = new HashSet<>(); + supportedExts.stream().forEach(e -> extSet.add(e.extensionNameString())); + for (DeviceExtension ext : extensions) { + Float weight = ext.evaluate(extSet); + if (weight == null) { + continue deviceLoop; + } + deviceWeight += weight; + } + // features + VkPhysicalDeviceFeatures ftrs = d.getFeatures(stack); + for (DeviceFeature f : features) { + Float weight = f.evaluateFeatureSupport(ftrs); + if (weight == null) { + continue deviceLoop; + } + deviceWeight += weight; + } + // miscellaneous filters + for (DeviceFilter f : filters) { + Float weight = f.evaluateDevice(d); + if (weight == null) { + continue deviceLoop; + } + deviceWeight += weight; + } + // compare + if (deviceWeight > topWeight) { + physical = d; + topWeight = deviceWeight; + } + } + } + if (physical == null) { + throw new NullPointerException("Failed to find suitable physical device."); + } + } + + public void addExtension(DeviceExtension extension) { + extensions.add(extension); + } + + public void addCriticalExtension(String name) { + addExtension(DeviceExtension.critical(name)); + } + + public void addOptionalExtension(String name, float successWeight) { + addExtension(DeviceExtension.optional(name, successWeight)); + } + + public void addFeature(DeviceFeature feature) { + features.add(feature); + } + + public void addFilter(DeviceFilter filter) { + filters.add(filter); + } + + public void setEnableAllFeatures(boolean enableAllFeatures) { + this.enableAllFeatures = enableAllFeatures; + } + + } + + private static class EvaluatedDevice { + + public final T device; + public final Collection features = new ArrayList<>(); + + private EvaluatedDevice(T device) { + this.device = device; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/PhysicalDevice.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/PhysicalDevice.java new file mode 100644 index 0000000000..b1f3c6359b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/PhysicalDevice.java @@ -0,0 +1,45 @@ +package com.jme3.vulkan.devices; + +import com.jme3.vulkan.Format; +import com.jme3.vulkan.commands.Queue; +import com.jme3.vulkan.images.VulkanImage; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.surface.Surface; +import com.jme3.vulkan.VulkanInstance; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +public interface PhysicalDevice { + + boolean populateQueueFamilyIndices(); + + VkDeviceQueueCreateInfo.Buffer createQueueFamilyInfo(MemoryStack stack); + + void createQueues(LogicalDevice device); + + VulkanInstance getInstance(); + + VkPhysicalDevice getDeviceHandle(); + + VkQueueFamilyProperties.Buffer getQueueFamilyProperties(MemoryStack stack); + + VkPhysicalDeviceProperties getProperties(MemoryStack stack); + + VkPhysicalDeviceFeatures getFeatures(MemoryStack stack); + + VkExtensionProperties.Buffer getExtensionProperties(MemoryStack stack); + + VkPhysicalDeviceMemoryProperties getMemoryProperties(MemoryStack stack); + + int findSupportedMemoryType(MemoryStack stack, int types, Flag flags); + + Format findSupportedFormat(VulkanImage.Tiling tiling, int features, Format... candidates); + + boolean querySwapchainSupport(Surface surface); + + Queue getCompute(); + + Queue getDataTransfer(); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/devices/PresentDevice.java b/jme3-core/src/main/java/com/jme3/vulkan/devices/PresentDevice.java new file mode 100644 index 0000000000..9f10f520e3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/devices/PresentDevice.java @@ -0,0 +1,9 @@ +package com.jme3.vulkan.devices; + +import com.jme3.vulkan.commands.Queue; + +public interface PresentDevice extends PhysicalDevice { + + Queue getPresent(); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/frames/PerFrameCommand.java b/jme3-core/src/main/java/com/jme3/vulkan/frames/PerFrameCommand.java new file mode 100644 index 0000000000..4c926e2c44 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/frames/PerFrameCommand.java @@ -0,0 +1,19 @@ +package com.jme3.vulkan.frames; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.update.Command; + +import java.util.function.IntFunction; + +public class PerFrameCommand extends PerFrameResource implements Command { + + public PerFrameCommand(UpdateFrameManager frames, IntFunction generator) { + super(frames, generator); + } + + @Override + public boolean run(CommandBuffer cmd, int frame) { + return get(frame).run(cmd, frame); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/frames/PerFrameResource.java b/jme3-core/src/main/java/com/jme3/vulkan/frames/PerFrameResource.java new file mode 100644 index 0000000000..c23314215d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/frames/PerFrameResource.java @@ -0,0 +1,51 @@ +package com.jme3.vulkan.frames; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.function.IntFunction; + +public class PerFrameResource implements VersionedResource { + + private final UpdateFrameManager frames; + private final List resources; + + public PerFrameResource(UpdateFrameManager frames, IntFunction generator) { + this.frames = frames; + resources = new ArrayList<>(frames.getTotalFrames()); + for (int i = 0; i < frames.getTotalFrames(); i++) { + resources.add(generator.apply(i)); + } + } + + @Override + public void set(T resource) { + resources.set(frames.getCurrentFrame(), resource); + } + + @Override + public void set(int frame, T resource) { + resources.set(frame, resource); + } + + @Override + public T get() { + return resources.get(frames.getCurrentFrame()); + } + + @Override + public T get(int frame) { + return resources.get(frame); + } + + @Override + public int getNumResources() { + return resources.size(); + } + + @Override + public Iterator iterator() { + return resources.iterator(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/frames/SingleCommand.java b/jme3-core/src/main/java/com/jme3/vulkan/frames/SingleCommand.java new file mode 100644 index 0000000000..9ae1a3f8ae --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/frames/SingleCommand.java @@ -0,0 +1,19 @@ +package com.jme3.vulkan.frames; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.update.Command; + +public class SingleCommand extends SingleResource implements Command { + + public SingleCommand() {} + + public SingleCommand(T resource) { + super(resource); + } + + @Override + public boolean run(CommandBuffer cmd, int frame) { + return get(frame).run(cmd, frame); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/frames/SingleResource.java b/jme3-core/src/main/java/com/jme3/vulkan/frames/SingleResource.java new file mode 100644 index 0000000000..4e3e6972cc --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/frames/SingleResource.java @@ -0,0 +1,67 @@ +package com.jme3.vulkan.frames; + +import java.util.Iterator; + +public class SingleResource implements VersionedResource { + + private T resource; + + public SingleResource() {} + + public SingleResource(T resource) { + this.resource = resource; + } + + @Override + public void set(T resource) { + this.resource = resource; + } + + @Override + public void set(int frame, T resource) { + this.resource = resource; + } + + @Override + public T get() { + return resource; + } + + @Override + public T get(int frame) { + return resource; + } + + @Override + public int getNumResources() { + return 1; + } + + @Override + public Iterator iterator() { + return new IteratorImpl<>(resource); + } + + private static class IteratorImpl implements Iterator { + + private T value; + + public IteratorImpl(T value) { + this.value = value; + } + + @Override + public boolean hasNext() { + return value != null; + } + + @Override + public T next() { + T v = value; + value = null; + return v; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/frames/UpdateFrame.java b/jme3-core/src/main/java/com/jme3/vulkan/frames/UpdateFrame.java new file mode 100644 index 0000000000..a7a012bd63 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/frames/UpdateFrame.java @@ -0,0 +1,7 @@ +package com.jme3.vulkan.frames; + +public interface UpdateFrame { + + void update(UpdateFrameManager frames, float tpf); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/frames/UpdateFrameManager.java b/jme3-core/src/main/java/com/jme3/vulkan/frames/UpdateFrameManager.java new file mode 100644 index 0000000000..1693746c1e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/frames/UpdateFrameManager.java @@ -0,0 +1,42 @@ +package com.jme3.vulkan.frames; + +import com.jme3.vulkan.update.Command; + +import java.util.function.IntFunction; + +public class UpdateFrameManager { + + private final UpdateFrame[] frames; + private int currentFrame = 0; + + public UpdateFrameManager(int frames, IntFunction generator) { + this.frames = new UpdateFrame[frames]; + for (int i = 0; i < frames; i++) { + this.frames[i] = generator.apply(i); + } + } + + public void update(float tpf) { + frames[currentFrame].update(this, tpf); + if (++currentFrame >= frames.length) { + currentFrame = 0; + } + } + + public int getTotalFrames() { + return frames.length; + } + + public int getCurrentFrame() { + return currentFrame; + } + + public PerFrameResource perFrame(IntFunction generator) { + return new PerFrameResource<>(this, generator); + } + + public PerFrameCommand perFrameCommand(IntFunction generator) { + return new PerFrameCommand<>(this, generator); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/frames/VersionedResource.java b/jme3-core/src/main/java/com/jme3/vulkan/frames/VersionedResource.java new file mode 100644 index 0000000000..f18b1c0f36 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/frames/VersionedResource.java @@ -0,0 +1,44 @@ +package com.jme3.vulkan.frames; + +/** + * Immutably maps frame indices to resources. + * + * @param resource type + */ +public interface VersionedResource extends Iterable { + + /** + * Sets the resource for the current frame. + * + * @param resource resource to assign (not null) + */ + void set(T resource); + + /** + * Sets the resource for the specified frame. + * + * @param frame frame to assign to (not negative) + * @param resource resource to assign (not null) + */ + void set(int frame, T resource); + + /** + * Gets the resource for the current frame. Must return the same value + * over the course of a frame. + */ + T get(); + + /** + * Gets the resource for the specified frame index. + * + * @param frame frame index (not negative) + * @return resource version mapped to the frame index + */ + T get(int frame); + + /** + * Gets the number of unique resources this resource maintains. + */ + int getNumResources(); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/AddressMode.java b/jme3-core/src/main/java/com/jme3/vulkan/images/AddressMode.java new file mode 100644 index 0000000000..e131b3cb1e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/AddressMode.java @@ -0,0 +1,25 @@ +package com.jme3.vulkan.images; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum AddressMode implements IntEnum { + + ClampToBorder(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER), + ClampToEdge(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE), + Repeat(VK_SAMPLER_ADDRESS_MODE_REPEAT), + MirroredRepeat(VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT); + + private final int vkEnum; + + AddressMode(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/BasicVulkanImage.java b/jme3-core/src/main/java/com/jme3/vulkan/images/BasicVulkanImage.java new file mode 100644 index 0000000000..6de30f759c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/BasicVulkanImage.java @@ -0,0 +1,237 @@ +package com.jme3.vulkan.images; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.Format; +import com.jme3.vulkan.SharingMode; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemoryRegion; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkImageCreateInfo; +import org.lwjgl.vulkan.VkImageMemoryBarrier; +import org.lwjgl.vulkan.VkMemoryRequirements; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class BasicVulkanImage extends AbstractNative implements VulkanImage { + + private final LogicalDevice device; + private final IntEnum type; + private MemoryRegion memory; + + private int width, height, depth; + private int mipmaps, layers; + private Flag usage; + private Format format = Format.RGBA8_SRGB; + private IntEnum tiling = Tiling.Optimal; + private IntEnum sharing = SharingMode.Exclusive; + + public BasicVulkanImage(LogicalDevice device, IntEnum type) { + this.device = device; + this.type = type; + width = height = depth = 1; + mipmaps = layers = 1; + } + + @Override + public LogicalDevice getDevice() { + return device; + } + + @Override + public long getId() { + return object; + } + + @Override + public IntEnum getType() { + return type; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getDepth() { + return depth; + } + + @Override + public int getMipmaps() { + return mipmaps; + } + + @Override + public int getLayers() { + return layers; + } + + @Override + public Flag getUsage() { + return usage; + } + + @Override + public Format getFormat() { + return format; + } + + @Override + public IntEnum getTiling() { + return tiling; + } + + @Override + public IntEnum getSharingMode() { + return sharing; + } + + @Override + public void addNativeDependent(NativeReference ref) { + this.ref.addDependent(ref); + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyImage(device.getNativeObject(), object, null); + } + + // todo: replace with transition autocloseable and deprecate this method + public void transitionLayout(CommandBuffer commands, Layout srcLayout, Layout dstLayout) { + try (MemoryStack stack = MemoryStack.stackPush()) { + int[] args = VulkanImage.Layout.getTransferArguments(srcLayout, dstLayout); + VkImageMemoryBarrier.Buffer barrier = VkImageMemoryBarrier.calloc(1, stack) + .sType(VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER) + .oldLayout(srcLayout.getEnum()) + .newLayout(dstLayout.getEnum()) + .srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) // for transfering queue ownership + .image(object) + .srcAccessMask(args[0]) + .dstAccessMask(args[1]); + barrier.subresourceRange() + .baseMipLevel(0) + .levelCount(1) + .baseArrayLayer(0) + .layerCount(1) + .aspectMask(format.getAspects().bits()); + vkCmdPipelineBarrier(commands.getBuffer(), args[2], args[3], 0, null, null, barrier); + } + } + + public Builder build() { + return new Builder(); + } + + public class Builder extends AbstractNative.Builder { + + private Flag mem; + private IntEnum layout = Layout.Undefined; + + @Override + protected void build() { + VkImageCreateInfo create = VkImageCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO) + .imageType(type.getEnum()) + .mipLevels(mipmaps) + .arrayLayers(layers) + .format(format.getVkEnum()) + .tiling(tiling.getEnum()) + .initialLayout(layout.getEnum()) + .usage(usage.bits()) + .samples(VK_SAMPLE_COUNT_1_BIT) // todo: multisampling + .sharingMode(sharing.getEnum()); + create.extent().width(width).height(height).depth(depth); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateImage(device.getNativeObject(), create, null, idBuf), + "Failed to create image."); + object = idBuf.get(0); + VkMemoryRequirements memReq = VkMemoryRequirements.malloc(stack); + vkGetImageMemoryRequirements(device.getNativeObject(), object, memReq); + memory = new MemoryRegion(device, memReq.size(), mem, memReq.memoryTypeBits()); + memory.bind(BasicVulkanImage.this, 0); + ref = Native.get().register(BasicVulkanImage.this); + device.getNativeReference().addDependent(ref); + } + + public void setWidth(int w) { + width = w; + } + + public void setHeight(int h) { + height = h; + } + + public void setDepth(int d) { + depth = d; + } + + public void setSize(int w) { + width = w; + } + + public void setSize(int w, int h) { + width = w; + height = h; + } + + public void setSize(int w, int h, int d) { + width = w; + height = h; + depth = d; + } + + public void setNumMipmaps(int m) { + mipmaps = m; + } + + public void setNumLayers(int l) { + layers = l; + } + + public void setUsage(Flag u) { + usage = u; + } + + public void setMemoryProps(Flag m) { + this.mem = m; + } + + public void setFormat(Format f) { + format = f; + } + + public void setTiling(IntEnum t) { + tiling = t; + } + + public void setLayout(IntEnum l) { + this.layout = l; + } + + public Flag getMemoryProps() { + return mem; + } + + public IntEnum getLayout() { + return layout; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/BorderColor.java b/jme3-core/src/main/java/com/jme3/vulkan/images/BorderColor.java new file mode 100644 index 0000000000..def7e52452 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/BorderColor.java @@ -0,0 +1,27 @@ +package com.jme3.vulkan.images; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum BorderColor implements IntEnum { + + FloatOpaqueBlack(VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK), + FloatOpaqueWhite(VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE), + FloatTransparentBlack(VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK), + IntOpaqueBlack(VK_BORDER_COLOR_INT_OPAQUE_BLACK), + IntOpaqueWhite(VK_BORDER_COLOR_INT_OPAQUE_WHITE), + IntTransparentBlack(VK_BORDER_COLOR_INT_TRANSPARENT_BLACK); + + private final int vkEnum; + + BorderColor(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/Filter.java b/jme3-core/src/main/java/com/jme3/vulkan/images/Filter.java new file mode 100644 index 0000000000..aeacf554b0 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/Filter.java @@ -0,0 +1,40 @@ +package com.jme3.vulkan.images; + +import com.jme3.texture.GlTexture; +import com.jme3.vulkan.util.IntEnum; + +import java.util.Objects; + +import static org.lwjgl.vulkan.VK10.*; + +public enum Filter implements IntEnum { + + Linear(VK_FILTER_LINEAR), + Nearest(VK_FILTER_NEAREST); + + private final int vkEnum; + + Filter(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + public static Filter of(GlTexture.MinFilter min) { + switch (min) { + case BilinearNearestMipMap: + case BilinearNoMipMaps: + case Trilinear: return Linear; + default: return Nearest; + } + } + + public static Filter of(GlTexture.MagFilter mag) { + if (mag == GlTexture.MagFilter.Bilinear) return Linear; + else return Nearest; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/GpuImage.java b/jme3-core/src/main/java/com/jme3/vulkan/images/GpuImage.java new file mode 100644 index 0000000000..ee9ede4dd8 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/GpuImage.java @@ -0,0 +1,46 @@ +package com.jme3.vulkan.images; + +import com.jme3.texture.GlTexture; +import com.jme3.vulkan.Format; +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public interface GpuImage { + + enum Type implements IntEnum { + + OneDemensional(VK_IMAGE_TYPE_1D), + TwoDemensional(VK_IMAGE_TYPE_2D), + ThreeDemensional(VK_IMAGE_TYPE_3D); + + private final int vkEnum; + + Type(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + } + + long getId(); + + IntEnum getType(); + + int getWidth(); + + int getHeight(); + + int getDepth(); + + int getMipmaps(); + + int getLayers(); + + Format getFormat(); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/ImageUsage.java b/jme3-core/src/main/java/com/jme3/vulkan/images/ImageUsage.java new file mode 100644 index 0000000000..3492344c09 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/ImageUsage.java @@ -0,0 +1,29 @@ +package com.jme3.vulkan.images; + +import com.jme3.vulkan.util.Flag; + +import static org.lwjgl.vulkan.VK10.*; + +public enum ImageUsage implements Flag { + + TransferDst(VK_IMAGE_USAGE_TRANSFER_DST_BIT), + TransferSrc(VK_IMAGE_USAGE_TRANSFER_SRC_BIT), + ColorAttachment(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), + Sampled(VK_IMAGE_USAGE_SAMPLED_BIT), + Storage(VK_IMAGE_USAGE_STORAGE_BIT), + DepthStencilAttachment(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), + InputAttachment(VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT), + TransientAttachment(VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT); + + private final int bits; + + ImageUsage(int bits) { + this.bits = bits; + } + + @Override + public int bits() { + return bits; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/MipmapMode.java b/jme3-core/src/main/java/com/jme3/vulkan/images/MipmapMode.java new file mode 100644 index 0000000000..b8dd674b54 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/MipmapMode.java @@ -0,0 +1,32 @@ +package com.jme3.vulkan.images; + +import com.jme3.texture.GlTexture; +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum MipmapMode implements IntEnum { + + Linear(VK_SAMPLER_MIPMAP_MODE_LINEAR), + Nearest(VK_SAMPLER_MIPMAP_MODE_NEAREST); + + private final int vkEnum; + + MipmapMode(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + public static MipmapMode of(GlTexture.MinFilter min) { + switch (min) { + case NearestLinearMipMap: + case Trilinear: return Linear; + default: return Nearest; + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/Sampler.java b/jme3-core/src/main/java/com/jme3/vulkan/images/Sampler.java new file mode 100644 index 0000000000..327fca4e2b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/Sampler.java @@ -0,0 +1,223 @@ +package com.jme3.vulkan.images; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.pipelines.CompareOp; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.vulkan.VkPhysicalDeviceProperties; +import org.lwjgl.vulkan.VkSamplerCreateInfo; + +import java.nio.LongBuffer; +import java.util.Objects; + +import static com.jme3.renderer.vulkan.VulkanUtils.check; +import static org.lwjgl.vulkan.VK10.*; + +public class Sampler extends AbstractNative { + + public static final int U = 0, V = 1, W = 2; + public static final float DISABLE_ANISOTROPY = 0f; + + private final LogicalDevice device; + private IntEnum mipmapMode = MipmapMode.Nearest; + private IntEnum min = Filter.Linear; + private IntEnum mag = Filter.Linear; + private final IntEnum[] edgeModes = {AddressMode.ClampToEdge, AddressMode.ClampToEdge, AddressMode.ClampToEdge}; + private float anisotropy = Float.MAX_VALUE; + private IntEnum borderColor = BorderColor.FloatOpaqueBlack; + private IntEnum compare = CompareOp.Always; + private float mipLodBias = 0f; + private float minLod = 0f; + private float maxLod = VK_LOD_CLAMP_NONE; + private boolean unnormalizedCoords = false; + + public Sampler(LogicalDevice device) { + this.device = device; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroySampler(device.getNativeObject(), object, null); + } + + public LogicalDevice getDevice() { + return device; + } + + public IntEnum getMipmapMode() { + return mipmapMode; + } + + public IntEnum getMinFilter() { + return min; + } + + public IntEnum getMagFilter() { + return mag; + } + + public IntEnum[] getEdgeModes() { + return edgeModes; + } + + public float getAnisotropy() { + return anisotropy; + } + + public boolean isAnisotropyEnabled() { + return anisotropy > DISABLE_ANISOTROPY; + } + + public IntEnum getBorderColor() { + return borderColor; + } + + public IntEnum getCompare() { + return compare; + } + + public float getMipLodBias() { + return mipLodBias; + } + + public float getMinLod() { + return minLod; + } + + public float getMaxLod() { + return maxLod; + } + + public boolean isUnnormalizedCoords() { + return unnormalizedCoords; + } + + public Builder build() { + return new Builder(); + } + + public class Builder extends AbstractNative.Builder { + + private Builder() {} + + @Override + protected void build() { + VkPhysicalDeviceProperties props = device.getPhysicalDevice().getProperties(stack); + VkSamplerCreateInfo create = VkSamplerCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO) + .minFilter(min.getEnum()) + .magFilter(mag.getEnum()) + .addressModeU(edgeModes[U].getEnum()) + .addressModeV(edgeModes[V].getEnum()) + .addressModeW(edgeModes[W].getEnum()) + .anisotropyEnable(anisotropy > DISABLE_ANISOTROPY) + .maxAnisotropy(Math.min(anisotropy, props.limits().maxSamplerAnisotropy())) + .borderColor(borderColor.getEnum()) + .unnormalizedCoordinates(unnormalizedCoords) + .compareEnable(compare != null) + .compareOp(IntEnum.get(compare, CompareOp.Always).getEnum()) + .mipmapMode(mipmapMode.getEnum()) + .mipLodBias(mipLodBias) + .minLod(minLod) + .maxLod(maxLod); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateSampler(device.getNativeObject(), create, null, idBuf), + "Failed to create sampler."); + object = idBuf.get(0); + ref = Native.get().register(Sampler.this); + device.getNativeReference().addDependent(ref); + } + + public void setMipmapMode(IntEnum m) { + mipmapMode = Objects.requireNonNull(m); + } + + public void setMinFilter(IntEnum f) { + min = Objects.requireNonNull(f); + } + + public void setMagFilter(IntEnum f) { + mag = Objects.requireNonNull(f); + } + + public void setMinMagFilters(IntEnum min, IntEnum mag) { + setMagFilter(min); + setMagFilter(mag); + } + + public void setEdgeMode(int axis, IntEnum a) { + if (axis < 0 || axis >= edgeModes.length) { + throw new IndexOutOfBoundsException("Invalid axis index (" + axis + "). " + + "Must be 0 (U), 1 (V), or 2 (W)."); + } + edgeModes[axis] = Objects.requireNonNull(a); + } + + public void setEdgeModeU(IntEnum u) { + setEdgeMode(U, u); + } + + public void setEdgeModeV(IntEnum v) { + setEdgeMode(V, v); + } + + public void setEdgeModeW(IntEnum w) { + setEdgeMode(W, w); + } + + public void setEdgeModes(IntEnum u, IntEnum v, IntEnum w) { + setEdgeMode(U, u); + setEdgeMode(V, v); + setEdgeMode(W, w); + } + + public void setEdgeModes(IntEnum e) { + setEdgeMode(U, e); + setEdgeMode(V, e); + setEdgeMode(W, e); + } + + public void setAnisotropy(float a) { + anisotropy = a; + } + + public void maxAnisotropy() { + setAnisotropy(Float.MAX_VALUE); + } + + public void disableAnisotropy() { + setAnisotropy(DISABLE_ANISOTROPY); + } + + public void setBorderColor(IntEnum c) { + borderColor = Objects.requireNonNull(c); + } + + public void setCompare(IntEnum c) { + compare = Objects.requireNonNull(c); + } + + public void setMipLodBias(float bias) { + mipLodBias = bias; + } + + public void setMinLod(float lod) { + minLod = lod; + } + + public void setMaxLod(float lod) { + maxLod = lod; + } + + public void disableMaxLod() { + setMaxLod(VK_LOD_CLAMP_NONE); + } + + public void setUnnormalizedCoords(boolean u) { + unnormalizedCoords = u; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImage.java b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImage.java new file mode 100644 index 0000000000..e4f0da2ad1 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImage.java @@ -0,0 +1,146 @@ +package com.jme3.vulkan.images; + +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.SharingMode; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.vulkan.KHRSwapchain; + +import static org.lwjgl.vulkan.VK10.*; + +public interface VulkanImage extends GpuImage { + + enum Layout implements IntEnum { + + Undefined(VK_IMAGE_LAYOUT_UNDEFINED), + General(VK_IMAGE_LAYOUT_GENERAL), + PreInitialized(VK_IMAGE_LAYOUT_PREINITIALIZED), + ColorAttachmentOptimal(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL), + DepthStencilAttachmentOptimal(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), + DepthStencilReadOnlyOptimal(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL), + TransferSrcOptimal(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL), + TransferDstOptimal(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), + ShaderReadOnlyOptimal(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL), + PresentSrc(KHRSwapchain.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + private final int vkEnum; + + Layout(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + @SuppressWarnings("SwitchStatementWithTooFewBranches") + public static int[] getTransferArguments(Layout srcLayout, Layout dstLayout) { + // output array format: {srcAccessMask, dstAccessMask, srcStage, dstStage} + switch (srcLayout) { + case Undefined: switch (dstLayout) { + case TransferDstOptimal: return new int[] { + 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT}; + case DepthStencilAttachmentOptimal: return new int[] { + 0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT}; + } break; + case TransferDstOptimal: switch (dstLayout) { + case ShaderReadOnlyOptimal: return new int[] { + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT}; + } break; + } + throw new UnsupportedOperationException("Unsupported layout transition: " + srcLayout + " to " + dstLayout); + } + + } + + enum Tiling implements IntEnum { + + Optimal(VK_IMAGE_TILING_OPTIMAL), + Linear(VK_IMAGE_TILING_LINEAR); + + private final int vkEnum; + + Tiling(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + } + + enum Load implements IntEnum { + + Clear(VK_ATTACHMENT_LOAD_OP_CLEAR), + Load(VK_ATTACHMENT_LOAD_OP_LOAD), + DontCare(VK_ATTACHMENT_LOAD_OP_DONT_CARE); + + private final int vkEnum; + + Load(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + } + + enum Store implements IntEnum { + + Store(VK_ATTACHMENT_STORE_OP_STORE), + DontCare(VK_ATTACHMENT_STORE_OP_DONT_CARE); + + private final int vkEnum; + + Store(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + } + + enum Aspect implements Flag { + + Color(VK_IMAGE_ASPECT_COLOR_BIT), + Depth(VK_IMAGE_ASPECT_DEPTH_BIT), + Stencil(VK_IMAGE_ASPECT_STENCIL_BIT), + MetaData(VK_IMAGE_ASPECT_METADATA_BIT); + + private final int bits; + + Aspect(int bits) { + this.bits = bits; + } + + @Override + public int bits() { + return bits; + } + + } + + LogicalDevice getDevice(); + + Flag getUsage(); + + IntEnum getTiling(); + + IntEnum getSharingMode(); + + void addNativeDependent(NativeReference ref); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImageLoader.java b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImageLoader.java new file mode 100644 index 0000000000..ffff3fb704 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImageLoader.java @@ -0,0 +1,273 @@ +package com.jme3.vulkan.images; + +import com.jme3.asset.*; +import com.jme3.util.BufferUtils; +import com.jme3.vulkan.Format; +import com.jme3.vulkan.buffers.BasicVulkanBuffer; +import com.jme3.vulkan.buffers.BufferUsage; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.commands.CommandPool; +import com.jme3.vulkan.buffers.GpuBuffer; +import com.jme3.vulkan.sync.SyncGroup; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkBufferImageCopy; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferUShort; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import static org.lwjgl.vulkan.VK10.*; + +public class VulkanImageLoader implements AssetLoader { + + @Override + public Object load(AssetInfo info) throws IOException { + if (ImageIO.getImageReadersBySuffix(info.getKey().getExtension()) != null) { + boolean flip = ((Key)info.getKey()).isFlip(); + try (InputStream stream = info.openStream(); BufferedInputStream bin = new BufferedInputStream(stream)) { + ImageData data = load(bin, flip); + if (data == null) { + throw new AssetLoadException("The given image cannot be loaded " + info.getKey()); + } + if (info.getKey() instanceof ImageKey) { + return loadGpuImage(((ImageKey)info.getKey()).getPool(), data); + } + return data; + } + } + throw new AssetLoadException("Image extension " + info.getKey().getExtension() + " is not supported."); + } + + public ImageData load(InputStream in, boolean flip) throws IOException { + ImageIO.setUseCache(false); + BufferedImage img = ImageIO.read(in); + if (img == null){ + return null; + } + return load(img, flip); + } + + public ImageData load(BufferedImage img, boolean flipY) { + int width = img.getWidth(); + int height = img.getHeight(); + byte[] data = (byte[])extractImageData(img); + switch (img.getType()) { + case BufferedImage.TYPE_4BYTE_ABGR: { // most common in PNG images w/ alpha + if (flipY) { + flipImage(data, width, height, 32); + } + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4); + buffer.put(data); + return new ImageData(buffer, width, height, Format.ABGR8_SRGB); + } + case BufferedImage.TYPE_3BYTE_BGR: { // most common in JPEG images + if (flipY) { + flipImage(data, width, height, 24); + } + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 3); + buffer.put(data); + return new ImageData(buffer, width, height, Format.BGR8_SRGB); + } + case BufferedImage.TYPE_BYTE_GRAY: { // grayscale fonts + if (flipY) { + flipImage(data, width, height, 8); + } + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height); + buffer.put(data); + return new ImageData(buffer, width, height, Format.R8_SRGB); + } + } + if (img.getTransparency() == Transparency.OPAQUE) { + ByteBuffer buffer = BufferUtils.createByteBuffer(img.getWidth() * img.getHeight() * 4); + for (int y = 0; y < height; y++) { + int ny = y; + if (flipY) { + ny = height - y - 1; + } + for (int x = 0; x < width; x++) { + int rgb = img.getRGB(x, ny); + byte r = (byte) ((rgb & 0x00FF0000) >> 16); + byte g = (byte) ((rgb & 0x0000FF00) >> 8); + byte b = (byte) ((rgb & 0x000000FF)); + byte a = Byte.MAX_VALUE; + buffer.put(r).put(g).put(b).put(a); + } + } + buffer.flip(); + return new ImageData(buffer, width, height, Format.RGBA8_SRGB); + } else { + ByteBuffer buffer = BufferUtils.createByteBuffer(img.getWidth() * img.getHeight() * 4); + for (int y = 0; y < height; y++) { + int ny = y; + if (flipY) { + ny = height - y - 1; + } + for (int x = 0; x < width; x++) { + int rgb = img.getRGB(x,ny); + byte a = (byte) ((rgb & 0xFF000000) >> 24); + byte r = (byte) ((rgb & 0x00FF0000) >> 16); + byte g = (byte) ((rgb & 0x0000FF00) >> 8); + byte b = (byte) ((rgb & 0x000000FF)); + buffer.put(r).put(g).put(b).put(a); + } + } + buffer.flip(); + return new ImageData(buffer, width, height, Format.RGBA8_SRGB); + } + } + + private Object extractImageData(BufferedImage img) { + DataBuffer buf = img.getRaster().getDataBuffer(); + switch (buf.getDataType()) { + case DataBuffer.TYPE_BYTE: { + DataBufferByte byteBuf = (DataBufferByte) buf; + return byteBuf.getData(); + } + case DataBuffer.TYPE_USHORT: { + DataBufferUShort shortBuf = (DataBufferUShort) buf; + return shortBuf.getData(); + } + default: throw new UnsupportedOperationException("Image data type not supported: " + buf.getDataType()); + } + } + + private void flipImage(byte[] img, int width, int height, int bpp) { + int scSz = (width * bpp) / 8; + byte[] sln = new byte[scSz]; + for (int y1 = 0; y1 < height / 2; y1++) { + int y2 = height - y1 - 1; + System.arraycopy(img, y1 * scSz, sln, 0, scSz); + System.arraycopy(img, y2 * scSz, img, y1 * scSz, scSz); + System.arraycopy(sln, 0, img, y2 * scSz, scSz); + } + } + + private BasicVulkanImage loadGpuImage(CommandPool transferPool, ImageData data) { + try (MemoryStack stack = MemoryStack.stackPush()) { + GpuBuffer staging = new BasicVulkanBuffer(transferPool.getDevice(), MemorySize.bytes(data.getBuffer().limit()), + BufferUsage.TransferSrc, Flag.of(MemoryProp.HostVisible, MemoryProp.HostCached), false); + staging.copy(data.getBuffer()); + BasicVulkanImage image = new BasicVulkanImage(transferPool.getDevice(), VulkanImage.Type.TwoDemensional); + try (BasicVulkanImage.Builder i = image.build()) { + i.setSize(data.getWidth(), data.getHeight()); + i.setFormat(data.getFormat()); + i.setTiling(VulkanImage.Tiling.Optimal); + i.setUsage(Flag.of(ImageUsage.TransferDst, ImageUsage.Sampled)); + i.setMemoryProps(MemoryProp.DeviceLocal); + } + CommandBuffer commands = transferPool.allocateTransientCommandBuffer(); + commands.begin(); + image.transitionLayout(commands, VulkanImage.Layout.Undefined, VulkanImage.Layout.TransferDstOptimal); + VkBufferImageCopy.Buffer region = VkBufferImageCopy.calloc(1, stack) + .bufferOffset(0) + .bufferRowLength(0) // padding bytes + .bufferImageHeight(0); // padding bytes + region.imageSubresource().aspectMask(VulkanImage.Aspect.Color.bits()) + .mipLevel(0) + .baseArrayLayer(0) + .layerCount(1); + region.imageOffset().set(0, 0, 0); + region.imageExtent().set(data.getWidth(), data.getHeight(), 1); + vkCmdCopyBufferToImage(commands.getBuffer(), staging.getId(), + image.getNativeObject(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region); + image.transitionLayout(commands, VulkanImage.Layout.TransferDstOptimal, VulkanImage.Layout.ShaderReadOnlyOptimal); + commands.end(); + commands.submit(SyncGroup.ASYNC); + transferPool.getQueue().waitIdle(); + return image; + } + } + + public static Key key(String name) { + return new Key<>(name); + } + + public static ImageKey key(CommandPool pool, String name) { + return new ImageKey(pool, name); + } + + public static class Key extends AssetKey { + + private boolean flip; + + public Key(String name) { + this(name, false); + } + + public Key(String name, boolean flip) { + super(name); + this.flip = flip; + } + + public void setFlip(boolean flip) { + this.flip = flip; + } + + public boolean isFlip() { + return flip; + } + + } + + public static class ImageKey extends Key { + + private final CommandPool pool; + + public ImageKey(CommandPool pool, String name) { + super(name); + this.pool = pool; + } + + public ImageKey(CommandPool pool, String name, boolean flip) { + super(name, flip); + this.pool = pool; + } + + public CommandPool getPool() { + return pool; + } + + } + + public static class ImageData { + + private final ByteBuffer buffer; + private final int width, height; + private final Format format; + + public ImageData(ByteBuffer buffer, int width, int height, Format format) { + this.buffer = buffer; + this.width = width; + this.height = height; + this.format = format; + } + + public ByteBuffer getBuffer() { + return buffer; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public Format getFormat() { + return format; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImageView.java b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImageView.java new file mode 100644 index 0000000000..2a23e40ad6 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanImageView.java @@ -0,0 +1,171 @@ +package com.jme3.vulkan.images; + +import com.jme3.texture.ImageView; +import com.jme3.util.natives.Native; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.Swizzle; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.vulkan.VkImageViewCreateInfo; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.check; +import static org.lwjgl.vulkan.VK10.*; + +public class VulkanImageView extends AbstractNative implements ImageView { + + private final VulkanImage image; + private final IntEnum type; + + private IntEnum swizzleR = Swizzle.R; + private IntEnum swizzleG = Swizzle.G; + private IntEnum swizzleB = Swizzle.B; + private IntEnum swizzleA = Swizzle.A; + private Flag aspect = VulkanImage.Aspect.Color; + private int baseMipmap = 0; + private int mipmapCount = 1; + private int baseLayer = 0; + private int layerCount = 1; + + public VulkanImageView(VulkanImage image, IntEnum type) { + this.image = image; + this.type = type; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyImageView(image.getDevice().getNativeObject(), object, null); + } + + @Override + public long getId() { + return object; + } + + @Override + public VulkanImage getImage() { + return image; + } + + @Override + public IntEnum getViewType() { + return type; + } + + public IntEnum getSwizzleR() { + return swizzleR; + } + + public IntEnum getSwizzleG() { + return swizzleG; + } + + public IntEnum getSwizzleB() { + return swizzleB; + } + + public IntEnum getSwizzleA() { + return swizzleA; + } + + public Flag getAspect() { + return aspect; + } + + @Override + public int getBaseMipmap() { + return baseMipmap; + } + + @Override + public int getMipmapCount() { + return mipmapCount; + } + + @Override + public int getBaseLayer() { + return baseLayer; + } + + @Override + public int getLayerCount() { + return layerCount; + } + + public Builder build() { + return new Builder(); + } + + public class Builder extends AbstractNative.Builder { + + @Override + protected void build() { + VkImageViewCreateInfo create = VkImageViewCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO) + .image(image.getId()) + .viewType(type.getEnum()) + .format(image.getFormat().getVkEnum()); + create.components() + .r(swizzleR.getEnum()) + .g(swizzleG.getEnum()) + .b(swizzleB.getEnum()) + .a(swizzleA.getEnum()); + create.subresourceRange() + .aspectMask(aspect.bits()) + .baseMipLevel(baseMipmap) + .levelCount(mipmapCount) + .baseArrayLayer(baseLayer) + .layerCount(layerCount); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateImageView(image.getDevice().getNativeObject(), create, null, idBuf), + "Failed to create image view."); + object = idBuf.get(0); + ref = Native.get().register(VulkanImageView.this); + image.addNativeDependent(ref); + } + + public void allMipmaps() { + baseMipmap = 0; + mipmapCount = image.getMipmaps(); + } + + public void setSwizzleR(IntEnum swizzleR) { + VulkanImageView.this.swizzleR = swizzleR; + } + + public void setSwizzleG(IntEnum swizzleG) { + VulkanImageView.this.swizzleG = swizzleG; + } + + public void setSwizzleB(IntEnum swizzleB) { + VulkanImageView.this.swizzleB = swizzleB; + } + + public void setSwizzleA(IntEnum swizzleA) { + VulkanImageView.this.swizzleA = swizzleA; + } + + public void setAspect(Flag aspect) { + VulkanImageView.this.aspect = aspect; + } + + public void setBaseMipmap(int baseMipmap) { + VulkanImageView.this.baseMipmap = baseMipmap; + } + + public void setMipmapCount(int mipmapCount) { + VulkanImageView.this.mipmapCount = mipmapCount; + } + + public void setBaseLayer(int baseLayer) { + VulkanImageView.this.baseLayer = baseLayer; + } + + public void setLayerCount(int layerCount) { + VulkanImageView.this.layerCount = layerCount; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanTexture.java b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanTexture.java new file mode 100644 index 0000000000..e057f9976f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/images/VulkanTexture.java @@ -0,0 +1,27 @@ +package com.jme3.vulkan.images; + +import com.jme3.texture.Texture; +import com.jme3.vulkan.devices.LogicalDevice; + +import java.util.Objects; + +public class VulkanTexture extends Sampler implements Texture { + + private final VulkanImageView image; + + public VulkanTexture(LogicalDevice device, VulkanImageView image) { + super(device); + this.image = Objects.requireNonNull(image); + } + + @Override + public long getId() { + return object; + } + + @Override + public VulkanImageView getView() { + return image; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/MatrixTransformMaterial.java b/jme3-core/src/main/java/com/jme3/vulkan/material/MatrixTransformMaterial.java new file mode 100644 index 0000000000..bee4f2f3fc --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/MatrixTransformMaterial.java @@ -0,0 +1,25 @@ +package com.jme3.vulkan.material; + +import com.jme3.vulkan.descriptors.Descriptor; +import com.jme3.vulkan.descriptors.DescriptorPool; +import com.jme3.vulkan.material.uniforms.BufferUniform; +import com.jme3.vulkan.shader.ShaderStage; + +/** + * Material specifically for storing matrix transforms for a geometry. + */ +public class MatrixTransformMaterial extends NewMaterial { + + private final BufferUniform transforms = new BufferUniform("Transforms", + Descriptor.UniformBuffer, 0, ShaderStage.Vertex); + + public MatrixTransformMaterial(DescriptorPool pool) { + super(pool); + addSet(transforms); + } + + public BufferUniform getTransforms() { + return transforms; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/NewMaterial.java b/jme3-core/src/main/java/com/jme3/vulkan/material/NewMaterial.java new file mode 100644 index 0000000000..d9f4fce253 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/NewMaterial.java @@ -0,0 +1,120 @@ +package com.jme3.vulkan.material; + +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.light.LightList; +import com.jme3.material.Material; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.vulkan.buffers.GpuBuffer; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.descriptors.*; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.material.uniforms.Uniform; +import com.jme3.vulkan.pipelines.Pipeline; +import com.jme3.vulkan.struct.Structure; +import org.lwjgl.system.MemoryStack; + +import java.io.IOException; +import java.nio.LongBuffer; +import java.util.*; + +import static org.lwjgl.vulkan.VK10.*; + +/** + * Relates shader uniform values to sets and bindings. + */ +public class NewMaterial implements Material { + + private final DescriptorPool pool; + private final List uniformSets = new ArrayList<>(); + private final HashMap> uniformLookup = new HashMap<>(); + + public NewMaterial(DescriptorPool pool) { + this.pool = pool; + } + + public void bind(CommandBuffer cmd, Pipeline pipeline) { + bind(cmd, pipeline, 0); + } + + public void bind(CommandBuffer cmd, Pipeline pipeline, int offset) { + LinkedList availableLayouts = new LinkedList<>(); + Collections.addAll(availableLayouts, pipeline.getLayout().getDescriptorSetLayouts()); + try (MemoryStack stack = MemoryStack.stackPush()) { + LongBuffer setBuf = stack.mallocLong(uniformSets.size()); + for (UniformSet set : uniformSets) { + setBuf.put(set.acquireSet(pool, availableLayouts).getNativeObject()); + } + setBuf.flip(); + vkCmdBindDescriptorSets(cmd.getBuffer(), pipeline.getBindPoint().getVkEnum(), + pipeline.getLayout().getNativeObject(), offset, setBuf, null); + } + } + + @Override + public void render(Geometry geometry, LightList lights, RenderManager renderManager) { + bind(cmd, pipeline); + geometry.getMesh().draw(cmd, geometry); + } + + @Override + public void setParam(String uniform, String param, Object value) { + Uniform u = getUniform(uniform); + GpuBuffer buffer = u.getResource().get(); + buffer.map(Structure::new).set(param, value); + buffer.unmap(); + } + + @Override + @SuppressWarnings("unchecked") + public T getUniform(String name) { + // Not sure if caching the results is really worth it... + Uniform uniform = uniformLookup.get(name); + if (uniform != null) { + return (T)uniform; + } + for (UniformSet set : uniformSets) { + for (Uniform u : set) { + if (name.equals(u.getName())) { + uniformLookup.put(u.getName(), u); + return (T)u; + } + } + } + return null; + } + + public DescriptorSetLayout[] createLayouts(LogicalDevice device) { + return uniformSets.stream().map(u -> u.createLayout(device)).toArray(DescriptorSetLayout[]::new); + } + + protected UniformSet addSet(UniformSet set) { + uniformSets.add(set); + return set; + } + + protected UniformSet addSet(int setIndex, UniformSet set) { + uniformSets.add(setIndex, set); + return set; + } + + protected UniformSet addSet(Uniform... uniforms) { + return addSet(new UniformSet(uniforms)); + } + + public List getSets() { + return Collections.unmodifiableList(uniformSets); + } + + @Override + public void write(JmeExporter ex) throws IOException { + throw new UnsupportedOperationException("Exporting not yet supported."); + } + + @Override + public void read(JmeImporter im) throws IOException { + throw new UnsupportedOperationException("Importing not yet supported."); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/TestMaterial.java b/jme3-core/src/main/java/com/jme3/vulkan/material/TestMaterial.java new file mode 100644 index 0000000000..e5719c6a14 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/TestMaterial.java @@ -0,0 +1,22 @@ +package com.jme3.vulkan.material; + +import com.jme3.vulkan.descriptors.DescriptorPool; +import com.jme3.vulkan.images.VulkanImage; +import com.jme3.vulkan.material.uniforms.TextureUniform; +import com.jme3.vulkan.shader.ShaderStage; + +public class TestMaterial extends NewMaterial { + + private final TextureUniform baseColorMap = new TextureUniform( + "BaseColorMap", VulkanImage.Layout.ShaderReadOnlyOptimal, 1, ShaderStage.Fragment); + + public TestMaterial(DescriptorPool pool) { + super(pool); + addSet(baseColorMap); + } + + public TextureUniform getBaseColorMap() { + return baseColorMap; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/UniformSet.java b/jme3-core/src/main/java/com/jme3/vulkan/material/UniformSet.java new file mode 100644 index 0000000000..f9201756e5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/UniformSet.java @@ -0,0 +1,179 @@ +package com.jme3.vulkan.material; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.descriptors.*; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.material.uniforms.Uniform; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.*; + +public class UniformSet implements Iterable { + + private final Uniform[] uniforms; + private final Collection activeFrames = new ArrayList<>(); + private int frameCacheTimeout = 10; + + public UniformSet(Uniform... uniforms) { + this.uniforms = uniforms; + // ensure duplicate binding indices are not present + BitSet bindings = new BitSet(); + for (Uniform u : uniforms) { + int i = u.getBindingIndex(); + if (bindings.get(i)) { + throw new IllegalArgumentException("Duplicate binding index in set: " + u.getBindingIndex()); + } + bindings.set(i); + } + } + + @Override + public Iterator iterator() { + return new IteratorImpl(); + } + + public DescriptorSet acquireSet(DescriptorPool pool, List availableLayouts) { + activeFrames.removeIf(FrameData::cycleTimeout); + FrameData data = activeFrames.stream().filter(FrameData::isCurrent).findAny().orElse(null); + if (data == null) { + activeFrames.add(data = new FrameData()); + } + return data.get(pool, availableLayouts); + } + + public DescriptorSetLayout createLayout(LogicalDevice device) { + SetLayoutBinding[] bindings = new SetLayoutBinding[uniforms.length]; + for (int i = 0; i < uniforms.length; i++) { + bindings[i] = uniforms[i].createBinding(); + } + return new DescriptorSetLayout(device, bindings); + } + + public void setFrameCacheTimeout(int frameCacheTimeout) { + this.frameCacheTimeout = frameCacheTimeout; + } + + public int getFrameCacheTimeout() { + return frameCacheTimeout; + } + + /** + * Maps {@link DescriptorSetLayout DescriptorSetLayouts} to {@link DescriptorSet DescriptorSets} + * by the ID of the DescriptorSetLayout for a particular combination of uniform values. If no + * available layout has a mapped set, a new set is allocated with an available compatible layout + * and mapped with it. + */ + private class FrameData { + + private final FrameIndex index = new FrameIndex(); + private final Map sets = new HashMap<>(); + private int timeout = frameCacheTimeout; + + public DescriptorSet get(DescriptorPool pool, List availableLayouts) { + timeout = frameCacheTimeout; + for (Iterator it = availableLayouts.iterator(); it.hasNext();) { + DescriptorSetLayout layout = it.next(); + DescriptorSet set = sets.get(layout.getNativeObject()); + if (set != null) { + it.remove(); + return set; + } + } + for (Iterator it = availableLayouts.iterator(); it.hasNext();) { + DescriptorSetLayout layout = it.next(); + if (isLayoutCompatible(layout)) { + it.remove(); + DescriptorSet set = pool.allocateSets(layout)[0]; + sets.put(set.getLayout().getNativeObject(), set); + set.write(uniforms); + return set; + } + } + throw new UnsupportedOperationException("Material is not compatible with the pipeline (uniform set not supported)."); + } + + public boolean cycleTimeout() { + return --timeout <= 0 || index.isOutOfDate(); + } + + public boolean isCurrent() { + return index.isCurrent(); + } + + private boolean isLayoutCompatible(DescriptorSetLayout layout) { + for (Uniform u : uniforms) { + for (SetLayoutBinding b : layout.getBindings()) { + if (u.isBindingCompatible(b)) { + return true; + } + } + } + return false; + } + + } + + /** + * Represents a frame by the values used for that frame. If any resources have + * been reclaimed, the frame is considered out of date and will be removed. + */ + private class FrameIndex { + + private final ReferenceQueue queue = new ReferenceQueue<>(); + private final WeakReference[] versions; + + private FrameIndex() { + versions = new WeakReference[uniforms.length]; + update(); + } + + public void update() { + for (int i = 0; i < uniforms.length; i++) { + versions[i] = new WeakReference<>(uniforms[i].getResource().get(), queue); + } + } + + public boolean isCurrent() { + for (int i = 0; i < versions.length; i++) { + // todo: consider using refersTo() from Java 16 to not interfere with the GC + if (versions[i].get() != uniforms[i].getResource().get()) { + return false; + } + } + return true; + } + + public int getAccuracy() { + int accuracy = 0; + for (int i = 0; i < versions.length; i++) { + if (versions[i].get() != uniforms[i].getResource()) { + accuracy++; + } + } + return accuracy; + } + + public boolean isOutOfDate() { + return queue.poll() != null; + } + + } + + private class IteratorImpl implements Iterator { + + private int index = 0; + + @Override + public boolean hasNext() { + return index < uniforms.length; + } + + @Override + public Uniform next() { + return uniforms[index++]; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/AbstractUniform.java b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/AbstractUniform.java new file mode 100644 index 0000000000..4d0fd5e31d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/AbstractUniform.java @@ -0,0 +1,59 @@ +package com.jme3.vulkan.material.uniforms; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.descriptors.Descriptor; +import com.jme3.vulkan.descriptors.SetLayoutBinding; +import com.jme3.vulkan.frames.VersionedResource; +import com.jme3.vulkan.shader.ShaderStage; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; + +public abstract class AbstractUniform implements Uniform { + + protected final String name; + protected final IntEnum type; + protected final int bindingIndex; + protected final Flag stages; + protected VersionedResource resource; + + public AbstractUniform(String name, IntEnum type, int bindingIndex, Flag stages) { + this.name = name; + this.type = type; + this.bindingIndex = bindingIndex; + this.stages = stages; + } + + @Override + public SetLayoutBinding createBinding() { + return new SetLayoutBinding(type, bindingIndex, 1, stages); + } + + @Override + public String getName() { + return name; + } + + @Override + public int getBindingIndex() { + return bindingIndex; + } + + @Override + public void setResource(VersionedResource resource) { + this.resource = resource; + } + + @Override + public VersionedResource getResource() { + return resource; + } + + public IntEnum getType() { + return type; + } + + public Flag getStages() { + return stages; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/BufferUniform.java b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/BufferUniform.java new file mode 100644 index 0000000000..319bbcab90 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/BufferUniform.java @@ -0,0 +1,40 @@ +package com.jme3.vulkan.material.uniforms; + +import com.jme3.vulkan.buffers.*; +import com.jme3.vulkan.descriptors.Descriptor; +import com.jme3.vulkan.descriptors.SetLayoutBinding; +import com.jme3.vulkan.shader.ShaderStage; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDescriptorBufferInfo; +import org.lwjgl.vulkan.VkWriteDescriptorSet; + +public class BufferUniform extends AbstractUniform { + + public BufferUniform(String name, IntEnum type, int bindingIndex, Flag stages) { + super(name, type, bindingIndex, stages); + } + + @Override + public void populateWrite(MemoryStack stack, VkWriteDescriptorSet write) { + GpuBuffer buffer = resource.get(); + VkDescriptorBufferInfo.Buffer info = VkDescriptorBufferInfo.calloc(1, stack) + .buffer(buffer.getId()) + .offset(0L) + .range(buffer.size().getBytes()); + write.pBufferInfo(info) + .descriptorCount(1) + .dstArrayElement(0) + .dstBinding(bindingIndex) + .descriptorType(type.getEnum()); + } + + @Override + public boolean isBindingCompatible(SetLayoutBinding binding) { + return type.is(binding.getType()) + && bindingIndex == binding.getBinding() + && binding.getDescriptors() == 1; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/TextureUniform.java b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/TextureUniform.java new file mode 100644 index 0000000000..c4ba2b8758 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/TextureUniform.java @@ -0,0 +1,48 @@ +package com.jme3.vulkan.material.uniforms; + +import com.jme3.texture.Texture; +import com.jme3.vulkan.descriptors.Descriptor; +import com.jme3.vulkan.descriptors.SetLayoutBinding; +import com.jme3.vulkan.images.VulkanImage; +import com.jme3.vulkan.shader.ShaderStage; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDescriptorImageInfo; +import org.lwjgl.vulkan.VkWriteDescriptorSet; + +public class TextureUniform extends AbstractUniform { + + private final IntEnum layout; + + public TextureUniform(String name, IntEnum layout, int bindingIndex, Flag stages) { + super(name, Descriptor.CombinedImageSampler, bindingIndex, stages); + this.layout = layout; + } + + @Override + public void populateWrite(MemoryStack stack, VkWriteDescriptorSet write) { + Texture tex = resource.get(); + VkDescriptorImageInfo.Buffer info = VkDescriptorImageInfo.calloc(1, stack) + .imageView(tex.getView().getId()) + .sampler(tex.getId()) + .imageLayout(layout.getEnum()); + write.pImageInfo(info) + .descriptorType(type.getEnum()) + .dstBinding(bindingIndex) + .dstArrayElement(0) + .descriptorCount(1); + } + + @Override + public boolean isBindingCompatible(SetLayoutBinding binding) { + return type.is(binding.getType()) + && bindingIndex == binding.getBinding() + && binding.getDescriptors() == 1; + } + + public IntEnum getLayout() { + return layout; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/Uniform.java b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/Uniform.java new file mode 100644 index 0000000000..eeb6549150 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/material/uniforms/Uniform.java @@ -0,0 +1,53 @@ +package com.jme3.vulkan.material.uniforms; + +import com.jme3.material.GlMaterial; +import com.jme3.renderer.opengl.GLRenderer; +import com.jme3.vulkan.descriptors.DescriptorSetWriter; +import com.jme3.vulkan.descriptors.SetLayoutBinding; +import com.jme3.vulkan.frames.VersionedResource; + +public interface Uniform extends DescriptorSetWriter { + + /** + * Gets the name by which this uniform is identified. + */ + String getName(); + + /** + * Tests if the {@link SetLayoutBinding} is compatible with this uniform, + * indicating that this uniform may be bound to the binding which it represents. + * Bindings that previously tested as compatible should always be compatible with + * this uniform. + * + * @param binding binding to test + * @return true if the binding is compatible + */ + boolean isBindingCompatible(SetLayoutBinding binding); + + /** + * Creates a new {@link SetLayoutBinding} that is completely (and always will be) + * {@link #isBindingCompatible(SetLayoutBinding) compatible} with this uniform. + * + * @return new set layout binding that is compatible with this uniform + */ + SetLayoutBinding createBinding(); + + /** + * Sets the {@link VersionedResource} that will provide the uniform value. + */ + void setResource(VersionedResource resource); + + /** + * Returns the {@link VersionedResource} supplying the uniform value. + */ + VersionedResource getResource(); + + /** + * The binding this uniform is targeting. Should be unique among all + * uniforms within a single {@link com.jme3.vulkan.material.UniformSet UniformSet}. + * + * @return the index of the target binding + */ + int getBindingIndex(); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/memory/MemoryProp.java b/jme3-core/src/main/java/com/jme3/vulkan/memory/MemoryProp.java new file mode 100644 index 0000000000..cd7a9a3d8d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/memory/MemoryProp.java @@ -0,0 +1,26 @@ +package com.jme3.vulkan.memory; + +import com.jme3.vulkan.util.Flag; + +import static org.lwjgl.vulkan.VK10.*; + +public enum MemoryProp implements Flag { + + HostVisible(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT), + HostCoherent(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT), + HostCached(VK_MEMORY_PROPERTY_HOST_CACHED_BIT), + DeviceLocal(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), + LazilyAllocated(VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT); + + private final int vkEnum; + + MemoryProp(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int bits() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/memory/MemoryRegion.java b/jme3-core/src/main/java/com/jme3/vulkan/memory/MemoryRegion.java new file mode 100644 index 0000000000..f5b6848c04 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/memory/MemoryRegion.java @@ -0,0 +1,110 @@ +package com.jme3.vulkan.memory; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.buffers.GpuBuffer; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.images.GpuImage; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.vulkan.VkMemoryAllocateInfo; + +import java.nio.*; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class MemoryRegion implements Native { + + private final LogicalDevice device; + private final NativeReference ref; + private final Flag flags; + private final long id; + private final long size; + private final AtomicBoolean mapped = new AtomicBoolean(false); + private final PointerBuffer mapping = MemoryUtil.memCallocPointer(1); + + public MemoryRegion(LogicalDevice device, long size, Flag flags, int typeBits) { + this.device = device; + this.flags = flags; + this.size = size; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkMemoryAllocateInfo allocate = VkMemoryAllocateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO) + .allocationSize(size) + .memoryTypeIndex(device.getPhysicalDevice().findSupportedMemoryType(stack, typeBits, flags)); + LongBuffer idBuf = stack.mallocLong(1); + check(vkAllocateMemory(device.getNativeObject(), allocate, null, idBuf), + "Failed to allocate buffer memory."); + id = idBuf.get(0); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> { + vkFreeMemory(device.getNativeObject(), id, null); + MemoryUtil.memFree(mapping); + }; + } + + @Override + public void prematureNativeDestruction() {} + + @Override + public NativeReference getNativeReference() { + return ref; + } + + public void bind(GpuBuffer buffer, long offset) { + check(vkBindBufferMemory(device.getNativeObject(), buffer.getId(), id, offset), + "Failed to bind buffer memory."); + } + + public void bind(GpuImage image, long offset) { + check(vkBindImageMemory(device.getNativeObject(), image.getId(), id, offset), + "Failed to bind image memory."); + } + + public PointerBuffer map() { + return map(0L, VK_WHOLE_SIZE); + } + + public PointerBuffer map(long offset) { + return map(offset, VK_WHOLE_SIZE); + } + + public PointerBuffer map(long offset, long size) { + if (!flags.contains(MemoryProp.HostVisible)) { + throw new IllegalStateException("Cannot map memory that is not host visible."); + } + if (mapped.getAndSet(true)) { + throw new IllegalStateException("Memory already mapped."); + } + vkMapMemory(device.getNativeObject(), id, offset, size, 0, mapping); + return mapping; + } + + public void unmap() { + if (!mapped.getAndSet(false)) { + throw new IllegalStateException("Memory is not mapped."); + } + mapping.put(0, VK_NULL_HANDLE); + vkUnmapMemory(device.getNativeObject(), id); + } + + public long getSize() { + return size; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/memory/MemorySize.java b/jme3-core/src/main/java/com/jme3/vulkan/memory/MemorySize.java new file mode 100644 index 0000000000..1234df47ef --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/memory/MemorySize.java @@ -0,0 +1,85 @@ +package com.jme3.vulkan.memory; + +import java.util.Objects; + +public class MemorySize { + + private final int elements; + private final int bytesPerElement; + private final int bytes; + + public MemorySize(int elements, int bytesPerElement) { + this.elements = elements; + this.bytesPerElement = bytesPerElement; + this.bytes = this.elements * this.bytesPerElement; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + MemorySize that = (MemorySize) o; + return elements == that.elements && bytesPerElement == that.bytesPerElement; + } + + @Override + public int hashCode() { + return Objects.hash(elements, bytesPerElement); + } + + public int getElements() { + return elements; + } + + public int getBytesPerElement() { + return bytesPerElement; + } + + public int getBytes() { + return bytes; + } + + public int getShorts() { + return bytes / Short.BYTES; + } + + public int getInts() { + return bytes / Integer.BYTES; + } + + public int getFloats() { + return bytes / Float.BYTES; + } + + public int getDoubles() { + return bytes / Double.BYTES; + } + + public int getLongs() { + return bytes / Long.BYTES; + } + + public static MemorySize bytes(int elements) { + return new MemorySize(elements, 1); + } + + public static MemorySize shorts(int elements) { + return new MemorySize(elements, Short.BYTES); + } + + public static MemorySize ints(int elements) { + return new MemorySize(elements, Integer.BYTES); + } + + public static MemorySize floats(int elements) { + return new MemorySize(elements, Float.BYTES); + } + + public static MemorySize doubles(int elements) { + return new MemorySize(elements, Double.BYTES); + } + + public static MemorySize longs(int elements) { + return new MemorySize(elements, Long.BYTES); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/AdaptiveMesh.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/AdaptiveMesh.java new file mode 100644 index 0000000000..b87195e326 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/AdaptiveMesh.java @@ -0,0 +1,240 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingVolume; +import com.jme3.collision.Collidable; +import com.jme3.collision.CollisionResults; +import com.jme3.collision.UnsupportedCollisionException; +import com.jme3.collision.bih.BIHTree; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.math.Matrix4f; +import com.jme3.renderer.Renderer; +import com.jme3.scene.CollisionData; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.vulkan.buffers.*; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.frames.VersionedResource; +import com.jme3.vulkan.memory.MemorySize; +import org.lwjgl.system.MemoryStack; + +import java.io.IOException; +import java.nio.LongBuffer; +import java.util.*; + +import static org.lwjgl.vulkan.VK10.*; + +public abstract class AdaptiveMesh implements Mesh { + + protected enum VertexMode { + + Stream, Dynamic, Static; + + } + + protected final MeshDescription description; + private final List vertexBuffers = new ArrayList<>(); + protected final List> indexBuffers = new ArrayList<>(); + protected BoundingVolume volume = new BoundingBox(); + private int vertices; + private CollisionData collisionTree; + + public AdaptiveMesh(MeshDescription description) { + this.description = description; + } + + @Override + public void draw(CommandBuffer cmd, Geometry geometry) { + try (MemoryStack stack = MemoryStack.stackPush()) { + LongBuffer verts = stack.mallocLong(vertexBuffers.size()); + LongBuffer offsets = stack.mallocLong(vertexBuffers.size()); + for (VertexBuffer vb : vertexBuffers) { + verts.put(vb.getResource().get().getId()); + offsets.put(0L); + } + verts.flip(); + offsets.flip(); + vkCmdBindVertexBuffers(cmd.getBuffer(), 0, verts, offsets); + } + if (!indexBuffers.isEmpty()) { + GpuBuffer indices = indexBuffers.get(0).get(); + vkCmdBindIndexBuffer(cmd.getBuffer(), indices.getId(), 0, IndexType.of(indices).getEnum()); + vkCmdDrawIndexed(cmd.getBuffer(), indices.size().getElements(), 1, 0, 0, 0); + } else { + vkCmdDraw(cmd.getBuffer(), vertices, 1, 0, 0); + } + } + + @Override + public void draw(Renderer renderer, Geometry geometry, int instances, com.jme3.scene.VertexBuffer[] instanceData) { + // todo: figure out how to possibly implement this + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getVertexCount() { + return vertices; + } + + @Override + public int getTriangleCount() { + return !indexBuffers.isEmpty() ? indexBuffers.get(0).get().size().getElements() / 3 : 0; + } + + @Override + public int collideWith(Collidable other, Geometry geometry, CollisionResults results) { + if (collisionTree == null) { + collisionTree = createCollisionTree(); + } + return collisionTree.collideWith(other, geometry.getWorldMatrix(), geometry.getWorldBound(), results); + } + + @Override + public int collideWith(Collidable other, CollisionResults results) { + if (collisionTree == null) { + collisionTree = createCollisionTree(); + } + return collisionTree.collideWith(other, Matrix4f.IDENTITY, volume, results); + } + + @Override + public void updateBound() { + try (AttributeModifier position = modifyPosition()) { + volume.computeFromPoints(position); + } + } + + @Override + public void setBound(BoundingVolume volume) { + this.volume = volume; + } + + @Override + public BoundingVolume getBound() { + return volume; + } + + @Override + public int getNumLodLevels() { + return indexBuffers.size(); + } + + @Override + @SuppressWarnings("resource") + public AttributeModifier modifyAttribute(String attribute) { + VertexAttribute attr = description.getAttribute(attribute); + if (attr != null) { + return new AttributeModifier(vertexBuffers.get(attr.getBinding().getBindingIndex()), attr).map(); + } else { + return new NullAttributeModifier().map(); + } + } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + throw new UnsupportedOperationException("Exporting not yet supported."); + } + + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + throw new UnsupportedOperationException("Importing not yet supported."); + } + + private CollisionData createCollisionTree() { + try (AttributeModifier positions = modifyPosition()) { + BIHTree tree = new BIHTree(positions, indexBuffers.get(0).get().mapIndices()); + tree.construct(); + return tree; + } + } + + protected abstract AttributeModifier modifyPosition(); + + protected abstract VersionedResource createStreamingBuffer(MemorySize size); + + protected abstract VersionedResource createDynamicBuffer(MemorySize size); + + protected abstract VersionedResource createStaticBuffer(MemorySize size); + + protected Builder buildVertexBuffers(int vertices) { + return new Builder(vertices); + } + + protected class Builder implements AutoCloseable { + + private final Map attributes = new HashMap<>(); + + private Builder(int vertices) { + AdaptiveMesh.this.vertices = vertices; + for (VertexBinding b : description) { + for (VertexAttribute a : b) { + attributes.put(a.getName(), new AttributeInfo()); + } + } + } + + @Override + public void close() { + VertexMode[] modes = new VertexMode[description.getBindings().size()]; + for (Map.Entry e : attributes.entrySet()) { + int i = description.getAttribute(e.getKey()).getBinding().getBindingIndex(); + VertexMode mode = modes[i]; + if (mode == null || e.getValue().getMode().ordinal() < mode.ordinal()) { + modes[i] = e.getValue().getMode(); + } + } + for (int i = 0; i < modes.length; i++) { + vertexBuffers.add(new VertexBuffer(createBufferResource(description.getBinding(i), modes[i]))); + } + } + + public void setMode(String name, VertexMode mode) { + AttributeInfo attr = attributes.get(name); + if (attr != null) { + attr.setMode(mode); + } + } + + public void setMode(BuiltInAttribute name, VertexMode mode) { + setMode(name.getName(), mode); + } + + private VersionedResource createBufferResource(VertexBinding binding, VertexMode mode) { + MemorySize size = MemorySize.bytes(binding.getStride() * vertices); + switch (mode) { + case Stream: return createStreamingBuffer(size); + case Dynamic: return createDynamicBuffer(size); + case Static: return createStaticBuffer(size); + default: throw new UnsupportedOperationException(); + } + } + + } + + /** + * Contains information about an attribute with the purpose + * of generating vertex buffers from that information. + * + *

This could technically be collapsed into VertexMode, but there + * may be other properties in the future that could be set.

+ */ + private static class AttributeInfo { + + private VertexMode mode = VertexMode.Static; + + public void setMode(VertexMode mode) { + this.mode = mode; + } + + public VertexMode getMode() { + return mode; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/AttributeModifier.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/AttributeModifier.java new file mode 100644 index 0000000000..5c357526e1 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/AttributeModifier.java @@ -0,0 +1,333 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.vulkan.Format; + +import java.nio.*; + +public class AttributeModifier implements AutoCloseable, VertexReader, VertexWriter { + + private final VertexBuffer vertex; + private final VertexAttribute attribute; + private ByteBuffer buffer; + + public AttributeModifier(VertexBuffer vertex, VertexAttribute attribute) { + this.vertex = vertex; + this.attribute = attribute; + } + + protected AttributeModifier map() { + buffer = vertex.mapBytes(); + return this; + } + + @Override + public void close() { + vertex.unmap(); + } + + public int vertexToPosition(int vertex) { + return attribute.getBinding().getStride() * vertex + attribute.getOffset(); + } + + public int positionToVertex(int position) { + return (position - attribute.getOffset()) / attribute.getBinding().getStride(); + } + + @Override + public int capacity() { + return buffer.capacity() / attribute.getBinding().getStride(); + } + + @Override + public int limit() { + return positionToVertex(buffer.limit()); + } + + @Override + public int components() { + return attribute.getFormat().getNumComponents(); + } + + @Override + public AttributeModifier limit(int vertex) { + buffer.limit(vertexToPosition(vertex)); + return this; + } + + @Override + public AttributeModifier putByte(int vertex, int component, byte value) { + attribute.getFormat().getComponent(component).putByte(buffer, vertexToPosition(vertex), value); + return this; + } + + @Override + public AttributeModifier putShort(int vertex, int component, short value) { + attribute.getFormat().getComponent(component).putShort(buffer, vertexToPosition(vertex), value); + return this; + } + + @Override + public AttributeModifier putInt(int vertex, int component, int value) { + attribute.getFormat().getComponent(component).putInt(buffer, vertexToPosition(vertex), value); + return this; + } + + @Override + public AttributeModifier putFloat(int vertex, int component, float value) { + attribute.getFormat().getComponent(component).putFloat(buffer, vertexToPosition(vertex), value); + return this; + } + + @Override + public AttributeModifier putDouble(int vertex, int component, double value) { + attribute.getFormat().getComponent(component).putDouble(buffer, vertexToPosition(vertex), value); + return this; + } + + @Override + public AttributeModifier putLong(int vertex, int component, long value) { + attribute.getFormat().getComponent(component).putLong(buffer, vertexToPosition(vertex), value); + return this; + } + + @Override + public AttributeModifier putVector2(int vertex, int baseComponent, float x, float y) { + vertex = vertexToPosition(vertex); + Format f = attribute.getFormat(); + f.getComponent(baseComponent++).putFloat(buffer, vertex, x); + f.getComponent(baseComponent ).putFloat(buffer, vertex, y); + return this; + } + + @Override + public AttributeModifier putVector3(int vertex, int baseComponent, float x, float y, float z) { + vertex = vertexToPosition(vertex); + Format f = attribute.getFormat(); + f.getComponent(baseComponent++).putFloat(buffer, vertex, x); + f.getComponent(baseComponent++).putFloat(buffer, vertex, y); + f.getComponent(baseComponent ).putFloat(buffer, vertex, z); + return this; + } + + @Override + public AttributeModifier putVector4(int vertex, int baseComponent, float x, float y, float z, float w) { + vertex = vertexToPosition(vertex); + Format f = attribute.getFormat(); + f.getComponent(baseComponent++).putFloat(buffer, vertex, x); + f.getComponent(baseComponent++).putFloat(buffer, vertex, y); + f.getComponent(baseComponent++).putFloat(buffer, vertex, z); + f.getComponent(baseComponent ).putFloat(buffer, vertex, w); + return this; + } + + @Override + public AttributeModifier putBytes(int baseVertex, int baseComponent, byte... values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + for (byte v : values) { + f.getComponent(baseComponent).putByte(buffer, vertPos, v); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + return this; + } + + @Override + public AttributeModifier putBytes(int baseVertex, int baseComponent, ByteBuffer values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + int bufPos = values.position(); + while (values.hasRemaining()) { + f.getComponent(baseComponent).putByte(buffer, vertPos, values.get()); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + values.position(bufPos); + return this; + } + + @Override + public AttributeModifier putShorts(int baseVertex, int baseComponent, short... values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + for (short v : values) { + f.getComponent(baseComponent).putShort(buffer, vertPos, v); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + return this; + } + + @Override + public AttributeModifier putShorts(int baseVertex, int baseComponent, ShortBuffer values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + int bufPos = values.position(); + while (values.hasRemaining()) { + f.getComponent(baseComponent).putShort(buffer, vertPos, values.get()); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + values.position(bufPos); + return this; + } + + @Override + public AttributeModifier putInts(int baseVertex, int baseComponent, int... values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + for (int v : values) { + f.getComponent(baseComponent).putInt(buffer, vertPos, v); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + return this; + } + + @Override + public AttributeModifier putInts(int baseVertex, int baseComponent, IntBuffer values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + int bufPos = values.position(); + while (values.hasRemaining()) { + f.getComponent(baseComponent).putInt(buffer, vertPos, values.get()); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + values.position(bufPos); + return this; + } + + @Override + public AttributeModifier putFloats(int baseVertex, int baseComponent, float... values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + for (float v : values) { + f.getComponent(baseComponent).putFloat(buffer, vertPos, v); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + return this; + } + + @Override + public AttributeModifier putFloats(int baseVertex, int baseComponent, FloatBuffer values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + int bufPos = values.position(); + while (values.hasRemaining()) { + f.getComponent(baseComponent).putFloat(buffer, vertPos, values.get()); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + values.position(bufPos); + return this; + } + + @Override + public AttributeModifier putDoubles(int baseVertex, int baseComponent, double... values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + for (double v : values) { + f.getComponent(baseComponent).putDouble(buffer, vertPos, v); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + return this; + } + + @Override + public AttributeModifier putDoubles(int baseVertex, int baseComponent, DoubleBuffer values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + int bufPos = values.position(); + while (values.hasRemaining()) { + f.getComponent(baseComponent).putDouble(buffer, vertPos, values.get()); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + values.position(bufPos); + return this; + } + + @Override + public AttributeModifier putLongs(int baseVertex, int baseComponent, long... values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + for (long v : values) { + f.getComponent(baseComponent).putLong(buffer, vertPos, v); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + return this; + } + + @Override + public AttributeModifier putLongs(int baseVertex, int baseComponent, LongBuffer values) { + Format f = attribute.getFormat(); + int vertPos = vertexToPosition(baseVertex); + int bufPos = values.position(); + while (values.hasRemaining()) { + f.getComponent(baseComponent).putLong(buffer, vertPos, values.get()); + if (++baseComponent >= f.getNumComponents()) { + baseComponent = 0; + vertPos = vertexToPosition(++baseVertex); + } + } + values.position(bufPos); + return this; + } + + @Override + public byte getByte(int vertex, int component) { + return attribute.getFormat().getComponent(component).getByte(buffer, vertexToPosition(vertex)); + } + + @Override + public short getShort(int vertex, int component) { + return attribute.getFormat().getComponent(component).getShort(buffer, vertexToPosition(vertex)); + } + + @Override + public int getInt(int vertex, int component) { + return attribute.getFormat().getComponent(component).getInt(buffer, vertexToPosition(vertex)); + } + + @Override + public float getFloat(int vertex, int component) { + return attribute.getFormat().getComponent(component).getFloat(buffer, vertexToPosition(vertex)); + } + + @Override + public double getDouble(int vertex, int component) { + return attribute.getFormat().getComponent(component).getDouble(buffer, vertexToPosition(vertex)); + } + + @Override + public long getLong(int vertex, int component) { + return attribute.getFormat().getComponent(component).getLong(buffer, vertexToPosition(vertex)); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/BuiltInAttribute.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/BuiltInAttribute.java new file mode 100644 index 0000000000..7ca00ae465 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/BuiltInAttribute.java @@ -0,0 +1,24 @@ +package com.jme3.vulkan.mesh; + +/** + * Names of common attributes such as position, texture coordinates, and normals. + */ +public enum BuiltInAttribute { + + Position("jme_position"), + TexCoord("jme_texcoord"), + Normal("jme_normal"), + Tangent("jme_tangent"), + Color("jme_color"); + + private final String name; + + BuiltInAttribute(String name) { + this.name = name; + } + + public String getName() { + return name; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/IndexType.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/IndexType.java new file mode 100644 index 0000000000..e7fa3b213c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/IndexType.java @@ -0,0 +1,38 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.vulkan.buffers.GpuBuffer; +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum IndexType implements IntEnum { + + UInt32(VK_INDEX_TYPE_UINT32, 2), + UInt16(VK_INDEX_TYPE_UINT16, 4); + + private final int vkEnum; + private final int bytes; + + IndexType(int vkEnum, int bytes) { + this.vkEnum = vkEnum; + this.bytes = bytes; + } + + @Override + public int getEnum() { + return vkEnum; + } + + public int getBytes() { + return bytes; + } + + public static IndexType of(GpuBuffer buffer) { + if (buffer.size().getBytesPerElement() <= UInt16.bytes) { + return UInt16; + } else { + return UInt32; + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/InputRate.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/InputRate.java new file mode 100644 index 0000000000..6fbda3315b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/InputRate.java @@ -0,0 +1,23 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum InputRate implements IntEnum { + + Vertex(VK_VERTEX_INPUT_RATE_VERTEX), + Instance(VK_VERTEX_INPUT_RATE_INSTANCE); + + private final int vkEnum; + + InputRate(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/MeshDescription.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/MeshDescription.java new file mode 100644 index 0000000000..190ac999ac --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/MeshDescription.java @@ -0,0 +1,93 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.vulkan.Format; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkVertexInputAttributeDescription; +import org.lwjgl.vulkan.VkVertexInputBindingDescription; + +import java.util.*; + +/** + * Describes the layout of vertex bindings and attributes, and simultaneously + * acts as a compatability layer between a mesh and a mesh control. + */ +public class MeshDescription implements Iterable { + + private final List bindings = new ArrayList<>(); + + public VkVertexInputBindingDescription.Buffer getBindingInfo(MemoryStack stack) { + VkVertexInputBindingDescription.Buffer binds = VkVertexInputBindingDescription.calloc(bindings.size(), stack); + for (VertexBinding b : bindings) { + binds.get().binding(b.getBindingIndex()) + .stride(b.getStride()) + .inputRate(b.getRate().getEnum()); + } + binds.flip(); + return binds; + } + + public VkVertexInputAttributeDescription.Buffer getAttributeInfo(MemoryStack stack) { + int size = 0; + for (VertexBinding b : bindings) { + size += b.getAttributes().size(); + } + VkVertexInputAttributeDescription.Buffer attr = VkVertexInputAttributeDescription.calloc(size, stack); + for (VertexBinding binding : bindings) { + for (VertexAttribute a : binding) { + attr.get().binding(binding.getBindingIndex()) + .location(a.getLocation()) + .format(a.getFormat().getVkEnum()) + .offset(a.getOffset()); + } + } + attr.flip(); + return attr; + } + + public int addBinding(IntEnum rate) { + VertexBinding binding = new VertexBinding(bindings.size(), rate); + bindings.add(binding); + return binding.getBindingIndex(); + } + + public int addAttribute(String name, IntEnum rate, Format format, int location) { + int binding = addBinding(rate); + addAttribute(name, binding, format, location); + return binding; + } + + public void addAttribute(String name, int bindingIndex, Format format, int location) { + getBinding(bindingIndex).addAttribute(name, format, location); + } + + public int addAttribute(BuiltInAttribute name, IntEnum rate, Format format, int location) { + return addAttribute(name.getName(), rate, format, location); + } + + public void addAttribute(BuiltInAttribute name, int bindingIndex, Format format, int location) { + addAttribute(name.getName(), bindingIndex, format, location); + } + + public VertexBinding getBinding(int index) { + return bindings.get(index); + } + + public VertexAttribute getAttribute(String name) { + for (VertexBinding b : bindings) { + VertexAttribute a = b.getAttribute(name); + if (a != null) return a; + } + return null; + } + + public List getBindings() { + return Collections.unmodifiableList(bindings); + } + + @Override + public Iterator iterator() { + return bindings.iterator(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/MyCustomMesh.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/MyCustomMesh.java new file mode 100644 index 0000000000..051677365c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/MyCustomMesh.java @@ -0,0 +1,87 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.math.Vector3f; +import com.jme3.vulkan.buffers.*; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.frames.SingleCommand; +import com.jme3.vulkan.frames.UpdateFrameManager; +import com.jme3.vulkan.frames.VersionedResource; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.update.CommandBatch; + +import java.nio.ShortBuffer; + +public class MyCustomMesh extends AdaptiveMesh { + + private final LogicalDevice device; + private final UpdateFrameManager frames; + private final CommandBatch updateStaticBuffers; + + public MyCustomMesh(LogicalDevice device, + UpdateFrameManager frames, + MeshDescription description, + CommandBatch updateSharedBuffers, + Vector3f normal, Vector3f up, float width, float height, float centerX, float centerY) { + super(description); + this.device = device; + this.frames = frames; + this.updateStaticBuffers = updateSharedBuffers; + VersionedResource indices = createStaticBuffer(MemorySize.shorts(6)); + indexBuffers.add(indices); + for (GpuBuffer buf : indices) { + ShortBuffer iBuf = buf.mapShorts(); + iBuf.put((short)0).put((short)2).put((short)3) + .put((short)0).put((short)1).put((short)2); + buf.unmap(); + } + try (Builder m = buildVertexBuffers(4)) { + m.setMode(BuiltInAttribute.Position, VertexMode.Static); + m.setMode(BuiltInAttribute.TexCoord, VertexMode.Static); + m.setMode(BuiltInAttribute.Normal, VertexMode.Static); + } + Vector3f x = normal.cross(up); + Vector3f y = normal.cross(x); + Vector3f tempX = new Vector3f(); + Vector3f tempY = new Vector3f(); + try (AttributeModifier position = modifyAttribute(BuiltInAttribute.Position); + AttributeModifier normals = modifyAttribute(BuiltInAttribute.Normal); + AttributeModifier texCoord = modifyAttribute(BuiltInAttribute.TexCoord)) { + position.putVector3(0, 0, x.mult(-width * centerX, tempX).addLocal(y.mult(height * (1f - centerY), tempY))); + position.putVector3(1, 0, x.mult(width * (1.0f - centerX), tempX).addLocal(y.mult(height * (1f - centerY), tempY))); + position.putVector3(2, 0, x.mult(width * (1.0f - centerX), tempX).addLocal(y.mult(-height * centerY, tempY))); + position.putVector3(3, 0, x.mult(-width * centerX, tempX).addLocal(y.mult(-height * centerY, tempY))); + normals.putVector3(0, 0, normal); + normals.putVector3(1, 0, normal); + normals.putVector3(2, 0, normal); + normals.putVector3(3, 0, normal); + texCoord.putVector2(0, 0, 0f, 0f); + texCoord.putVector2(1, 0, 1f, 0f); + texCoord.putVector2(2, 0, 1f, 1f); + texCoord.putVector2(3, 0, 0f, 1f); + } + updateBound(); + } + + @Override + protected AttributeModifier modifyPosition() { + return modifyAttribute(BuiltInAttribute.Position); + } + + @Override + protected VersionedResource createStreamingBuffer(MemorySize size) { + throw new UnsupportedOperationException("Streaming buffers not implemented."); + } + + @Override + protected VersionedResource createDynamicBuffer(MemorySize size) { + throw new UnsupportedOperationException("Dynamic buffers not implemented."); + } + + @Override + protected VersionedResource createStaticBuffer(MemorySize size) { + return updateStaticBuffers.add(new SingleCommand<>(new BackedStaticBuffer( + device, size, BufferUsage.Vertex, MemoryProp.DeviceLocal, false))); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/NullAttributeModifier.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/NullAttributeModifier.java new file mode 100644 index 0000000000..0dd0a12cb9 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/NullAttributeModifier.java @@ -0,0 +1,226 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; + +import java.nio.*; + +public class NullAttributeModifier extends AttributeModifier { + + public NullAttributeModifier() { + super(null, null); + } + + @Override + protected AttributeModifier map() { + return this; + } + + @Override + public void close() {} + + @Override + public int capacity() { + return 0; + } + + @Override + public int limit() { + return 0; + } + + @Override + public AttributeModifier limit(int vertex) { + return this; + } + + @Override + public AttributeModifier putByte(int vertex, int component, byte value) { + return this; + } + + @Override + public AttributeModifier putShort(int vertex, int component, short value) { + return this; + } + + @Override + public AttributeModifier putInt(int vertex, int component, int value) { + return this; + } + + @Override + public AttributeModifier putFloat(int vertex, int component, float value) { + return this; + } + + @Override + public AttributeModifier putDouble(int vertex, int component, double value) { + return this; + } + + @Override + public AttributeModifier putLong(int vertex, int component, long value) { + return this; + } + + @Override + public AttributeModifier putVector2(int vertex, int baseComponent, Vector2f value) { + return this; + } + + @Override + public AttributeModifier putVector2(int vertex, int baseComponent, float x, float y) { + return this; + } + + @Override + public AttributeModifier putVector3(int vertex, int baseComponent, Vector3f value) { + return this; + } + + @Override + public AttributeModifier putVector3(int vertex, int baseComponent, float x, float y, float z) { + return this; + } + + @Override + public AttributeModifier putVector4(int vertex, int baseComponent, Vector4f value) { + return putVector4(vertex, baseComponent, value.x, value.y, value.z, value.w); + } + + @Override + public AttributeModifier putVector4(int vertex, int baseComponent, float x, float y, float z, float w) { + return this; + } + + @Override + public AttributeModifier putColor(int vertex, int baseComponent, ColorRGBA value) { + return this; + } + + @Override + public AttributeModifier putBytes(int baseVertex, int baseComponent, byte[] values) { + return this; + } + + @Override + public AttributeModifier putBytes(int baseVertex, int baseComponent, ByteBuffer values) { + return this; + } + + @Override + public AttributeModifier putShorts(int baseVertex, int baseComponent, short[] values) { + return this; + } + + @Override + public AttributeModifier putShorts(int baseVertex, int baseComponent, ShortBuffer values) { + return this; + } + + @Override + public AttributeModifier putInts(int baseVertex, int baseComponent, int[] values) { + return this; + } + + @Override + public AttributeModifier putInts(int baseVertex, int baseComponent, IntBuffer values) { + return this; + } + + @Override + public AttributeModifier putFloats(int baseVertex, int baseComponent, float[] values) { + return this; + } + + @Override + public AttributeModifier putFloats(int baseVertex, int baseComponent, FloatBuffer values) { + return this; + } + + @Override + public AttributeModifier putDoubles(int baseVertex, int baseComponent, double[] values) { + return this; + } + + @Override + public AttributeModifier putDoubles(int baseVertex, int baseComponent, DoubleBuffer values) { + return this; + } + + @Override + public AttributeModifier putLongs(int baseVertex, int baseComponent, long[] values) { + return this; + } + + @Override + public AttributeModifier putLongs(int baseVertex, int baseComponent, LongBuffer values) { + return this; + } + + @Override + public byte getByte(int vertex, int component) { + return 0; + } + + @Override + public short getShort(int vertex, int component) { + return 0; + } + + @Override + public int getInt(int vertex, int component) { + return 0; + } + + @Override + public float getFloat(int vertex, int component) { + return 0f; + } + + @Override + public double getDouble(int vertex, int component) { + return 0.0; + } + + @Override + public long getLong(int vertex, int component) { + return 0L; + } + + @Override + public Vector2f getVector2(int vertex, int baseComponent, Vector2f store) { + if (store == null) { + store = new Vector2f(); + } + return store.set(0f, 0f); + } + + @Override + public Vector3f getVector3(int vertex, int baseComponent, Vector3f store) { + if (store == null) { + store = new Vector3f(); + } + return store.set(0f, 0f, 0f); + } + + @Override + public Vector4f getVector4(int vertex, int baseComponent, Vector4f store) { + if (store == null) { + store = new Vector4f(); + } + return store.set(0f, 0f, 0f, 0f); + } + + @Override + public ColorRGBA getColor(int vertex, int baseComponent, ColorRGBA store) { + if (store == null) { + store = new ColorRGBA(); + } + return store.set(0f, 0f, 0f, 0f); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexAttribute.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexAttribute.java new file mode 100644 index 0000000000..68fa0f2123 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexAttribute.java @@ -0,0 +1,46 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.vulkan.Format; + +public class VertexAttribute { + + public static final String POSITION = "jme_position"; + public static final String NORMALS = "jme_normals"; + public static final String TEXCOORD = "jme_texCoord"; + public static final String COLOR = "jme_color"; + + private final VertexBinding binding; + private final String name; + private final Format format; + private final int location; + private final int offset; + + public VertexAttribute(VertexBinding binding, String name, Format format, int location, int offset) { + this.binding = binding; + this.name = name; + this.format = format; + this.location = location; + this.offset = offset; + } + + public String getName() { + return name; + } + + public VertexBinding getBinding() { + return binding; + } + + public Format getFormat() { + return format; + } + + public int getLocation() { + return location; + } + + public int getOffset() { + return offset; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexBinding.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexBinding.java new file mode 100644 index 0000000000..fbce4738dd --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexBinding.java @@ -0,0 +1,58 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.vulkan.Format; +import com.jme3.vulkan.util.IntEnum; + +import java.util.*; + +public class VertexBinding implements Iterable { + + private final int binding; + private final IntEnum rate; + private final Map attributes = new HashMap<>(); + private int stride; + + public VertexBinding(int binding, IntEnum rate) { + this.binding = binding; + this.rate = rate; + } + + private int findNextAttributeOffset(Format format) { + int offset = 0; + for (VertexAttribute a : attributes.values()) { + offset = Math.max(offset, a.getOffset() + a.getFormat().getTotalBytes()); + } + stride = offset + format.getTotalBytes(); + return offset; + } + + protected void addAttribute(String name, Format format, int location) { + attributes.put(name, new VertexAttribute(this, name, format, location, findNextAttributeOffset(format))); + } + + public int getBindingIndex() { + return binding; + } + + public int getStride() { + return stride; + } + + public IntEnum getRate() { + return rate; + } + + public VertexAttribute getAttribute(String name) { + return attributes.get(name); + } + + public Map getAttributes() { + return Collections.unmodifiableMap(attributes); + } + + @Override + public Iterator iterator() { + return attributes.values().iterator(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexBuffer.java new file mode 100644 index 0000000000..a5c166631b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexBuffer.java @@ -0,0 +1,67 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.vulkan.buffers.*; +import com.jme3.vulkan.frames.VersionedResource; +import org.lwjgl.PointerBuffer; + +import java.nio.*; + +public class VertexBuffer { + + private final VersionedResource resource; + private GpuBuffer buffer; + private int mappers = 0; + private PointerBuffer memory; + + public VertexBuffer(VersionedResource resource) { + this.resource = resource; + } + + public PointerBuffer map() { + if (mappers++ == 0) { + memory = (buffer = resource.get()).map(); + } + // the mapped buffer could only ever not match the frame's current buffer if + // not all mappings were cleared on the previous frame (i.e. mappers != 0) + if (buffer != resource.get()) { + throw new IllegalStateException("Not all mappings were properly unmapped."); + } + return memory; + } + + public void unmap() { + if (--mappers <= 0) { + memory = null; + buffer.unmap(); + } + } + + public ByteBuffer mapBytes() { + return map().getByteBuffer(0, buffer.size().getBytes()); + } + + public ShortBuffer mapShorts() { + return map().getShortBuffer(0, buffer.size().getShorts()); + } + + public IntBuffer mapInts() { + return map().getIntBuffer(0, buffer.size().getInts()); + } + + public FloatBuffer mapFloats() { + return map().getFloatBuffer(0, buffer.size().getFloats()); + } + + public DoubleBuffer mapDoubles() { + return map().getDoubleBuffer(0, buffer.size().getDoubles()); + } + + public LongBuffer mapLongs() { + return map().getLongBuffer(0, buffer.size().getLongs()); + } + + public VersionedResource getResource() { + return resource; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexReader.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexReader.java new file mode 100644 index 0000000000..98bb513efd --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexReader.java @@ -0,0 +1,203 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; + +import java.nio.*; + +public interface VertexReader { + + int capacity(); + + int limit(); + + int components(); + + byte getByte(int vertex, int component); + + short getShort(int vertex, int component); + + int getInt(int vertex, int component); + + float getFloat(int vertex, int component); + + double getDouble(int vertex, int component); + + long getLong(int vertex, int component); + + default Vector2f getVector2(int vertex, int baseComponent, Vector2f store) { + if (store == null) { + store = new Vector2f(); + } + return store.set( + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent )); + } + + default Vector3f getVector3(int vertex, int baseComponent, Vector3f store) { + if (store == null) { + store = new Vector3f(); + } + return store.set( + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent )); + } + + default Vector4f getVector4(int vertex, int baseComponent, Vector4f store) { + if (store == null) { + store = new Vector4f(); + } + return store.set( + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent )); + } + + default ColorRGBA getColor(int vertex, int baseComponent, ColorRGBA store) { + if (store == null) { + store = new ColorRGBA(); + } + return store.set( + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent++), + getFloat(vertex, baseComponent )); + } + + default byte[] getBytes(int baseVertex, int baseComponent, byte[] store) { + for (int i = 0; i < store.length; i++) { + store[i] = getByte(baseVertex, baseComponent); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default ByteBuffer getBytes(int baseVertex, int baseComponent, ByteBuffer store) { + for (int i = 0; i < store.limit(); i++) { + store.put(i, getByte(baseVertex, baseComponent)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default short[] getShorts(int baseVertex, int baseComponent, short[] store) { + for (int i = 0; i < store.length; i++) { + store[i] = getShort(baseVertex, baseComponent); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default ShortBuffer getShorts(int baseVertex, int baseComponent, ShortBuffer store) { + for (int i = 0; i < store.limit(); i++) { + store.put(i, getShort(baseVertex, baseComponent)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default int[] getInts(int baseVertex, int baseComponent, int[] store) { + for (int i = 0; i < store.length; i++) { + store[i] = getInt(baseVertex, baseComponent); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default IntBuffer getInts(int baseVertex, int baseComponent, IntBuffer store) { + for (int i = 0; i < store.limit(); i++) { + store.put(i, getInt(baseVertex, baseComponent)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default float[] getFloats(int baseVertex, int baseComponent, float[] store) { + for (int i = 0; i < store.length; i++) { + store[i] = getFloat(baseVertex, baseComponent); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default FloatBuffer getFloats(int baseVertex, int baseComponent, FloatBuffer store) { + for (int i = 0; i < store.limit(); i++) { + store.put(i, getFloat(baseVertex, baseComponent)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default double[] getDoubles(int baseVertex, int baseComponent, double[] store) { + for (int i = 0; i < store.length; i++) { + store[i] = getDouble(baseVertex, baseComponent); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default DoubleBuffer getDoubles(int baseVertex, int baseComponent, DoubleBuffer store) { + for (int i = 0; i < store.limit(); i++) { + store.put(i, getDouble(baseVertex, baseComponent)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default long[] getLongs(int baseVertex, int baseComponent, long[] store) { + for (int i = 0; i < store.length; i++) { + store[i] = getLong(baseVertex, baseComponent); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + + default LongBuffer getLongs(int baseVertex, int baseComponent, LongBuffer store) { + for (int i = 0; i < store.limit(); i++) { + store.put(i, getLong(baseVertex, baseComponent)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return store; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexWriter.java b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexWriter.java new file mode 100644 index 0000000000..acdc25295f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/mesh/VertexWriter.java @@ -0,0 +1,195 @@ +package com.jme3.vulkan.mesh; + +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; + +import java.nio.*; + +public interface VertexWriter extends VertexReader { + + VertexWriter limit(int vertex); + + VertexWriter putByte(int vertex, int component, byte value); + + VertexWriter putShort(int vertex, int component, short value); + + VertexWriter putInt(int vertex, int component, int value); + + VertexWriter putFloat(int vertex, int component, float value); + + VertexWriter putDouble(int vertex, int component, double value); + + VertexWriter putLong(int vertex, int component, long value); + + default VertexWriter putVector2(int vertex, int baseComponent, float x, float y) { + putFloat(vertex, baseComponent++, x); + putFloat(vertex, baseComponent , y); + return this; + } + + default VertexWriter putVector3(int vertex, int baseComponent, float x, float y, float z) { + putFloat(vertex, baseComponent++, x); + putFloat(vertex, baseComponent++, y); + putFloat(vertex, baseComponent , z); + return this; + } + + default VertexWriter putVector4(int vertex, int baseComponent, float x, float y, float z, float w) { + putFloat(vertex, baseComponent++, x); + putFloat(vertex, baseComponent++, y); + putFloat(vertex, baseComponent++, z); + putFloat(vertex, baseComponent , w); + return this; + } + + default VertexWriter putVector2(int vertex, int baseComponent, Vector2f value) { + return putVector2(vertex, baseComponent, value.x, value.y); + } + + default VertexWriter putVector3(int vertex, int baseComponent, Vector3f value) { + return putVector3(vertex, baseComponent, value.x, value.y, value.z); + } + + default VertexWriter putVector4(int vertex, int baseComponent, Vector4f value) { + return putVector4(vertex, baseComponent, value.x, value.y, value.z, value.w); + } + + default VertexWriter putColor(int vertex, int baseComponent, ColorRGBA value) { + return putVector4(vertex, baseComponent, value.r, value.g, value.b, value.a); + } + + default VertexWriter putBytes(int baseVertex, int baseComponent, byte... values) { + for (byte v : values) { + putByte(baseVertex, baseComponent, v); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putBytes(int baseVertex, int baseComponent, ByteBuffer values) { + for (int i = 0; i < values.limit(); i++) { + putByte(baseVertex, baseComponent, values.get(i)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putShorts(int baseVertex, int baseComponent, short... values) { + for (short v : values) { + putShort(baseVertex, baseComponent, v); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putShorts(int baseVertex, int baseComponent, ShortBuffer values) { + for (int i = 0; i < values.limit(); i++) { + putShort(baseVertex, baseComponent, values.get(i)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putInts(int baseVertex, int baseComponent, int... values) { + for (int v : values) { + putInt(baseVertex, baseComponent, v); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putInts(int baseVertex, int baseComponent, IntBuffer values) { + for (int i = 0; i < values.limit(); i++) { + putInt(baseVertex, baseComponent, values.get(i)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putFloats(int baseVertex, int baseComponent, float... values) { + for (float v : values) { + putFloat(baseVertex, baseComponent, v); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putFloats(int baseVertex, int baseComponent, FloatBuffer values) { + for (int i = 0; i < values.limit(); i++) { + putFloat(baseVertex, baseComponent, values.get(i)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putDoubles(int baseVertex, int baseComponent, double... values) { + for (double v : values) { + putDouble(baseVertex, baseComponent, v); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putDoubles(int baseVertex, int baseComponent, DoubleBuffer values) { + for (int i = 0; i < values.limit(); i++) { + putDouble(baseVertex, baseComponent, values.get(i)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putLongs(int baseVertex, int baseComponent, long... values) { + for (long v : values) { + putLong(baseVertex, baseComponent, v); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + + default VertexWriter putLongs(int baseVertex, int baseComponent, LongBuffer values) { + for (int i = 0; i < values.limit(); i++) { + putLong(baseVertex, baseComponent, values.get(i)); + if (++baseComponent >= components()) { + baseComponent = 0; + baseVertex++; + } + } + return this; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pass/Attachment.java b/jme3-core/src/main/java/com/jme3/vulkan/pass/Attachment.java new file mode 100644 index 0000000000..51be558383 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pass/Attachment.java @@ -0,0 +1,119 @@ +package com.jme3.vulkan.pass; + +import com.jme3.vulkan.Format; +import com.jme3.vulkan.images.VulkanImage; +import org.lwjgl.vulkan.VkAttachmentDescription; + +/** + * Immutable definition for render pass attachments. + */ +public class Attachment { + + private final int position; + private final Format format; + private final int samples; + private VulkanImage.Load load = VulkanImage.Load.Clear; + private VulkanImage.Store store = VulkanImage.Store.Store; + private VulkanImage.Load stencilLoad = VulkanImage.Load.DontCare; + private VulkanImage.Store stencilStore = VulkanImage.Store.DontCare; + private VulkanImage.Layout initialLayout = VulkanImage.Layout.Undefined; + private VulkanImage.Layout finalLayout = VulkanImage.Layout.General; + + protected Attachment(int position, Format format, int samples) { + this.position = position; + this.format = format; + this.samples = samples; + } + + protected Attachment(int position, Attachment base) { + this.position = position; + this.format = base.format; + this.samples = base.samples; + this.load = base.load; + this.store = base.store; + this.stencilLoad = base.stencilLoad; + this.stencilStore = base.stencilStore; + this.initialLayout = base.initialLayout; + this.finalLayout = base.finalLayout; + } + + public AttachmentReference createReference(VulkanImage.Layout layout) { + return new AttachmentReference(this, layout); + } + + public void fillStruct(VkAttachmentDescription struct) { + struct.format(format.getVkEnum()) + .samples(samples) + .loadOp(load.getEnum()) + .storeOp(store.getEnum()) + .stencilLoadOp(stencilLoad.getEnum()) + .stencilStoreOp(stencilStore.getEnum()) + .initialLayout(initialLayout.getEnum()) + .finalLayout(finalLayout.getEnum()); + } + + public void setLoad(VulkanImage.Load load) { + this.load = load; + } + + public void setStencilLoad(VulkanImage.Load stencilLoad) { + this.stencilLoad = stencilLoad; + } + + public void setStore(VulkanImage.Store store) { + this.store = store; + } + + public void setStencilStore(VulkanImage.Store stencilStore) { + this.stencilStore = stencilStore; + } + + public void setInitialLayout(VulkanImage.Layout initialLayout) { + this.initialLayout = initialLayout; + } + + public void setFinalLayout(VulkanImage.Layout finalLayout) { + this.finalLayout = finalLayout; + } + + public int getPosition() { + return position; + } + + public Format getFormat() { + return format; + } + + public int getSamples() { + return samples; + } + + public VulkanImage.Load getLoad() { + return load; + } + + public VulkanImage.Load getStencilLoad() { + return stencilLoad; + } + + public VulkanImage.Store getStore() { + return store; + } + + public VulkanImage.Store getStencilStore() { + return stencilStore; + } + + public VulkanImage.Layout getInitialLayout() { + return initialLayout; + } + + public VulkanImage.Layout getFinalLayout() { + return finalLayout; + } + + public boolean isCompatible(Attachment a) { + return position == a.position && format == a.format && samples == a.samples; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pass/AttachmentReference.java b/jme3-core/src/main/java/com/jme3/vulkan/pass/AttachmentReference.java new file mode 100644 index 0000000000..b45412dd13 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pass/AttachmentReference.java @@ -0,0 +1,49 @@ +package com.jme3.vulkan.pass; + +import com.jme3.vulkan.images.VulkanImage; +import org.lwjgl.vulkan.VK10; +import org.lwjgl.vulkan.VkAttachmentReference; + +/** + * Immutable reference to an {@link Attachment}. + */ +public class AttachmentReference { + + private final Attachment attachment; + private final VulkanImage.Layout layout; + + protected AttachmentReference(Attachment attachment, VulkanImage.Layout layout) { + this.attachment = attachment; + this.layout = layout; + } + + public void fillStruct(VkAttachmentReference struct) { + struct.attachment(getAttachmentPosition()) + .layout(layout.getEnum()); + } + + public Attachment getAttachment() { + return attachment; + } + + public VulkanImage.Layout getLayout() { + return layout; + } + + public int getAttachmentPosition() { + return attachment != null ? attachment.getPosition() : VK10.VK_ATTACHMENT_UNUSED; + } + + public boolean isUnused() { + return attachment == null; + } + + public boolean isCompatible(AttachmentReference ref) { + return isUnused() == ref.isUnused() && (isUnused() || attachment.isCompatible(ref.attachment)) && layout == ref.layout; + } + + public static AttachmentReference unused(VulkanImage.Layout layout) { + return new AttachmentReference(null, layout); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pass/RenderPass.java b/jme3-core/src/main/java/com/jme3/vulkan/pass/RenderPass.java new file mode 100644 index 0000000000..5788f3c21e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pass/RenderPass.java @@ -0,0 +1,251 @@ +package com.jme3.vulkan.pass; + +import com.jme3.util.natives.Native; +import com.jme3.vulkan.Format; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.pipelines.FrameBuffer; +import com.jme3.vulkan.pipelines.PipelineBindPoint; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.nio.LongBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class RenderPass extends AbstractNative { + + private final LogicalDevice device; + private final List attachments = new ArrayList<>(); + private final List subpasses = new ArrayList<>(); + private final List dependencies = new ArrayList<>(); + private boolean built = false; + + public RenderPass(LogicalDevice device) { + this.device = device; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyRenderPass(device.getNativeObject(), object, null); + } + + public void begin(CommandBuffer cmd, FrameBuffer fbo) { + begin(cmd, fbo, true); + } + + public void begin(CommandBuffer cmd, FrameBuffer fbo, boolean inline) { + try (MemoryStack stack = MemoryStack.stackPush()) { + VkClearValue.Buffer clear = VkClearValue.calloc(2, stack); + clear.get(0).color().float32(stack.floats(0f, 0f, 0f, 1f)); + clear.get(1).depthStencil().set(1.0f, 0); + VkRenderPassBeginInfo begin = VkRenderPassBeginInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO) + .renderPass(object) + .framebuffer(fbo.getNativeObject()) + .clearValueCount(clear.limit()) + .pClearValues(clear); + begin.renderArea().offset().set(0, 0); + begin.renderArea().extent().width(fbo.getWidth()).height(fbo.getHeight()); + vkCmdBeginRenderPass(cmd.getBuffer(), begin, inline ? VK_SUBPASS_CONTENTS_INLINE : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + } + } + + public void nextSubpass(CommandBuffer cmd) { + nextSubpass(cmd, true); + } + + public void nextSubpass(CommandBuffer cmd, boolean inline) { + vkCmdNextSubpass(cmd.getBuffer(), inline ? VK_SUBPASS_CONTENTS_INLINE : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + } + + public void end(CommandBuffer cmd) { + vkCmdEndRenderPass(cmd.getBuffer()); + } + + public LogicalDevice getDevice() { + return device; + } + + public boolean isCompatible(RenderPass pass) { + if (this == pass) { + return true; + } + if (attachments.size() != pass.attachments.size()) { + return false; + } + if (subpasses.size() != pass.subpasses.size()) { + return false; + } + if (dependencies.size() != pass.dependencies.size()) { + return false; + } + for (int i = 0; i < attachments.size(); i++) { + if (!attachments.get(i).isCompatible(pass.attachments.get(i))) { + return false; + } + } + for (int i = 0; i < subpasses.size(); i++) { + if (!subpasses.get(i).isCompatible(pass.subpasses.get(i))) { + return false; + } + } + for (int i = 0; i < dependencies.size(); i++) { + if (!dependencies.get(i).isCompatible(pass.dependencies.get(i))) { + return false; + } + } + return true; + } + + public Builder build() { + if (built) { + throw new IllegalStateException("Render pass has already been built or is being built."); + } + built = true; + return new Builder(); + } + + public Builder buildCopyOf(RenderPass base) { + return new Builder(base); + } + + public class Builder extends AbstractNative.Builder { + + public Builder() {} + + public Builder(RenderPass base) { + for (Attachment a : base.attachments) { + attachments.add(new Attachment(attachments.size(), a)); + } + for (Subpass s : base.subpasses) { + subpasses.add(new Subpass(subpasses.size(), s, attachments)); + } + for (SubpassDependency d : base.dependencies) { + dependencies.add(new SubpassDependency(d, subpasses)); + } + } + + @Override + protected void build() { + VkRenderPassCreateInfo create = VkRenderPassCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO); + if (!attachments.isEmpty()) { + VkAttachmentDescription.Buffer buf = VkAttachmentDescription.calloc(attachments.size(), stack); + for (Attachment a : attachments) { + a.fillStruct(buf.get()); + } + create.pAttachments(buf.flip()); + } + if (!subpasses.isEmpty()) { + VkSubpassDescription.Buffer buf = VkSubpassDescription.calloc(subpasses.size(), stack); + for (Subpass s : subpasses) { + s.fillStruct(stack, buf.get()); + } + create.pSubpasses(buf.flip()); + } + if (!dependencies.isEmpty()) { + VkSubpassDependency.Buffer buf = VkSubpassDependency.calloc(dependencies.size(), stack); + for (SubpassDependency d : dependencies) { + d.fillStruct(buf.get()); + } + create.pDependencies(buf.flip()); + } + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateRenderPass(device.getNativeObject(), create, null, idBuf), "Failed to create render pass."); + object = idBuf.get(0); + ref = Native.get().register(RenderPass.this); + device.getNativeReference().addDependent(ref); + } + + public Attachment createAttachment(Format format, int samples) { + Attachment a = new Attachment(attachments.size(), format, samples); + attachments.add(a); + return a; + } + + public Attachment createAttachment(Format format, int samples, Consumer config) { + Attachment a = createAttachment(format, samples); + config.accept(a); + return a; + } + + public Attachment getAttachment(int i) { + return attachments.get(i); + } + + public Attachment getAttachment(int i, Consumer config) { + Attachment a = getAttachment(i); + config.accept(a); + return a; + } + + public List getAttachments() { + return Collections.unmodifiableList(attachments); + } + + public Subpass createSubpass(PipelineBindPoint bindPoint) { + Subpass p = new Subpass(subpasses.size(), bindPoint); + subpasses.add(p); + return p; + } + + public Subpass createSubpass(PipelineBindPoint bindPoint, Consumer config) { + Subpass p = createSubpass(bindPoint); + config.accept(p); + return p; + } + + public Subpass getSubpass(int i) { + return subpasses.get(i); + } + + public Subpass getSubpass(int i, Consumer config) { + Subpass p = getSubpass(i); + config.accept(p); + return p; + } + + public List getSubpasses() { + return Collections.unmodifiableList(subpasses); + } + + public SubpassDependency createDependency(Subpass src, Subpass dst) { + SubpassDependency d = new SubpassDependency(src, dst); + dependencies.add(d); + return d; + } + + public SubpassDependency createDependency(Subpass src, Subpass dst, Consumer config) { + SubpassDependency d = createDependency(src, dst); + config.accept(d); + return d; + } + + public SubpassDependency getDependency(int i) { + return dependencies.get(i); + } + + public SubpassDependency getDependency(int i, Consumer config) { + SubpassDependency d = getDependency(i); + config.accept(d); + return d; + } + + public List getDependencies() { + return Collections.unmodifiableList(dependencies); + } + + public MemoryStack getStack() { + return stack; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pass/Subpass.java b/jme3-core/src/main/java/com/jme3/vulkan/pass/Subpass.java new file mode 100644 index 0000000000..3a3a668e86 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pass/Subpass.java @@ -0,0 +1,195 @@ +package com.jme3.vulkan.pass; + +import com.jme3.vulkan.pipelines.PipelineBindPoint; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkAttachmentReference; +import org.lwjgl.vulkan.VkSubpassDescription; + +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Immutable definition of a subpass within a render pass. + */ +public class Subpass { + + private final int position; + private final PipelineBindPoint bindPoint; + private final List color = new ArrayList<>(); + private final List input = new ArrayList<>(); + private final List resolve = new ArrayList<>(); + private final List preserve = new ArrayList<>(); + private AttachmentReference depthStencil; + + protected Subpass(int position, PipelineBindPoint bindPoint) { + this.position = position; + this.bindPoint = bindPoint; + } + + protected Subpass(int position, Subpass base, List attachments) { + this.position = position; + this.bindPoint = base.bindPoint; + transferRefs(base.color, color, attachments); + transferRefs(base.input, input, attachments); + transferRefs(base.resolve, resolve, attachments); + transferRefs(base.preserve, preserve, attachments); + if (base.depthStencil != null) { + if (!base.depthStencil.isUnused()) { + depthStencil = attachments.get(base.depthStencil.getAttachment().getPosition()) + .createReference(base.depthStencil.getLayout()); + } else { + depthStencil = AttachmentReference.unused(base.depthStencil.getLayout()); + } + } + } + + private void transferRefs(List srcRefs, List dstRefs, List attachments) { + for (AttachmentReference r : srcRefs) { + if (!r.isUnused()) { + dstRefs.add(attachments.get(r.getAttachment().getPosition()).createReference(r.getLayout())); + } else { + dstRefs.add(AttachmentReference.unused(r.getLayout())); + } + } + } + + public void fillStruct(MemoryStack stack, VkSubpassDescription struct) { + struct.pipelineBindPoint(bindPoint.getVkEnum()); + if (!color.isEmpty()) { + struct.colorAttachmentCount(color.size()); + struct.pColorAttachments(getColorReferences(stack)); + } + if (depthStencil != null) { + struct.pDepthStencilAttachment(getDepthStencil(stack)); + } + if (!input.isEmpty()) { + struct.pInputAttachments(getInputReferences(stack)); + } + if (!resolve.isEmpty()) { + struct.pResolveAttachments(getResolveReferences(stack)); + } + if (!preserve.isEmpty()) { + struct.pPreserveAttachments(getPreserveIndices(stack)); + } + } + + public void addColorAttachment(AttachmentReference ref) { + color.add(ref); + } + + public void addInputAttachment(AttachmentReference ref) { + input.add(ref); + } + + public void addResolveAttachment(AttachmentReference ref) { + resolve.add(ref); + } + + public void addPreserveAttachment(AttachmentReference ref) { + resolve.add(ref); + } + + public void setDepthStencilAttachment(AttachmentReference depthStencil) { + this.depthStencil = depthStencil; + } + + public AttachmentReference getDepthStencil() { + return depthStencil; + } + + public List getColor() { + return color; + } + + public List getInput() { + return input; + } + + public List getResolve() { + return resolve; + } + + public List getPreserve() { + return preserve; + } + + public VkAttachmentReference getDepthStencil(MemoryStack stack) { + VkAttachmentReference ref = VkAttachmentReference.calloc(stack); + depthStencil.fillStruct(ref); + return ref; + } + + private VkAttachmentReference.Buffer getReferenceBuffer(MemoryStack stack, Collection refs) { + VkAttachmentReference.Buffer att = VkAttachmentReference.calloc(color.size(), stack); + for (AttachmentReference ref : refs) { + ref.fillStruct(att.get()); + } + return att.flip(); + } + + public VkAttachmentReference.Buffer getColorReferences(MemoryStack stack) { + return getReferenceBuffer(stack, color); + } + + public VkAttachmentReference.Buffer getInputReferences(MemoryStack stack) { + return getReferenceBuffer(stack, input); + } + + public VkAttachmentReference.Buffer getResolveReferences(MemoryStack stack) { + return getReferenceBuffer(stack, resolve); + } + + public IntBuffer getPreserveIndices(MemoryStack stack) { + IntBuffer indices = stack.mallocInt(preserve.size()); + for (AttachmentReference ref : preserve) { + indices.put(ref.getAttachmentPosition()); + } + indices.flip(); + return indices; + } + + public int getPosition() { + return position; + } + + public PipelineBindPoint getBindPoint() { + return bindPoint; + } + + public boolean hasDepthStencil() { + return depthStencil != null; + } + + public boolean isCompatible(Subpass pass) { + return bindPoint == pass.bindPoint + && hasDepthStencil() == pass.hasDepthStencil() + && (!hasDepthStencil() || depthStencil.isCompatible(pass.depthStencil)) + && compareReferenceLists(color, pass.color) + && compareReferenceLists(input, pass.input) + && compareReferenceLists(resolve, pass.resolve) + && compareReferenceLists(preserve, pass.preserve); + } + + private boolean compareReferenceLists(List list1, List list2) { + int lower = Math.min(list1.size(), list2.size()); + int higher = Math.max(list1.size(), list2.size()); + for (int i = 0; i < lower; i++) { + if (!list1.get(i).isCompatible(list2.get(i))) { + return false; + } + } + for (int i = lower; i < higher; i++) { + if (i < list1.size()) { + if (!list1.get(i).isUnused()) { + return false; + } + } else if (!list2.get(i).isUnused()) { + return false; + } + } + return true; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pass/SubpassDependency.java b/jme3-core/src/main/java/com/jme3/vulkan/pass/SubpassDependency.java new file mode 100644 index 0000000000..d0d9b715f2 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pass/SubpassDependency.java @@ -0,0 +1,100 @@ +package com.jme3.vulkan.pass; + +import com.jme3.vulkan.pipelines.Access; +import com.jme3.vulkan.pipelines.PipelineStage; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.vulkan.VK10; +import org.lwjgl.vulkan.VkSubpassDependency; + +import java.util.List; + +/** + * Immutable definition of a render pass dependency. + */ +public class SubpassDependency { + + private final Subpass srcSubpass, dstSubpass; + private Flag srcStageMask, dstStageMask; + private Flag srcAccessMask, dstAccessMask; + + protected SubpassDependency(Subpass srcSubpass, Subpass dstSubpass) { + this.srcSubpass = srcSubpass; + this.dstSubpass = dstSubpass; + } + + protected SubpassDependency(SubpassDependency base, List subpasses) { + srcSubpass = base.srcSubpass != null ? subpasses.get(base.srcSubpass.getPosition()) : null; + dstSubpass = base.dstSubpass != null ? subpasses.get(base.dstSubpass.getPosition()) : null; + this.srcStageMask = base.srcStageMask; + this.srcAccessMask = base.srcAccessMask; + this.dstStageMask = base.dstStageMask; + this.dstAccessMask = base.dstAccessMask; + } + + public void fillStruct(VkSubpassDependency struct) { + struct.srcSubpass(srcSubpass != null ? srcSubpass.getPosition() : VK10.VK_SUBPASS_EXTERNAL) + .dstSubpass(dstSubpass != null ? dstSubpass.getPosition() : VK10.VK_SUBPASS_EXTERNAL) + .srcStageMask(srcStageMask.bits()) + .srcAccessMask(srcAccessMask.bits()) + .dstStageMask(dstStageMask.bits()) + .dstAccessMask(dstAccessMask.bits()); + } + + public void setSrcStageMask(Flag srcStageMask) { + this.srcStageMask = srcStageMask; + } + + public void setSrcAccessMask(Flag srcAccessMask) { + this.srcAccessMask = srcAccessMask; + } + + public void setDstStageMask(Flag dstStageMask) { + this.dstStageMask = dstStageMask; + } + + public void setDstAccessMask(Flag dstAccessMask) { + this.dstAccessMask = dstAccessMask; + } + + public Subpass getSrcSubpass() { + return srcSubpass; + } + + public Subpass getDstSubpass() { + return dstSubpass; + } + + public Flag getSrcStageMask() { + return srcStageMask; + } + + public Flag getSrcAccessMask() { + return srcAccessMask; + } + + public Flag getDstStageMask() { + return dstStageMask; + } + + public Flag getDstAccessMask() { + return dstAccessMask; + } + + public boolean isSourceExternal() { + return srcSubpass == null; + } + + public boolean isDestinationExternal() { + return dstSubpass == null; + } + + public boolean isCompatible(SubpassDependency dependency) { + return srcSubpass.getPosition() == dependency.srcSubpass.getPosition() + && dstSubpass.getPosition() == dependency.dstSubpass.getPosition() + && srcStageMask == dependency.srcStageMask + && srcAccessMask == dependency.srcAccessMask + && dstStageMask == dependency.dstStageMask + && dstAccessMask == dependency.dstAccessMask; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Access.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Access.java new file mode 100644 index 0000000000..3a57db548e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Access.java @@ -0,0 +1,38 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.Flag; + +import static org.lwjgl.vulkan.VK10.*; + +public enum Access implements Flag { + + ColorAttachmentWrite(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), + ColorAttachmentRead(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), + HostWrite(VK_ACCESS_HOST_WRITE_BIT), + HostRead(VK_ACCESS_HOST_READ_BIT), + IndexRead(VK_ACCESS_INDEX_READ_BIT), + DepthStencilAttachmentWrite(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT), + DepthStencilAttachmentRead(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), + IndirectCommandRead(VK_ACCESS_INDIRECT_COMMAND_READ_BIT), + InputAttachmentRead(VK_ACCESS_INPUT_ATTACHMENT_READ_BIT), + MemoryWrite(VK_ACCESS_MEMORY_WRITE_BIT), + MemoryRead(VK_ACCESS_MEMORY_READ_BIT), + ShaderWrite(VK_ACCESS_SHADER_WRITE_BIT), + ShaderRead(VK_ACCESS_SHADER_READ_BIT), + TransferWrite(VK_ACCESS_TRANSFER_WRITE_BIT), + TransferRead(VK_ACCESS_TRANSFER_READ_BIT), + UniformRead(VK_ACCESS_UNIFORM_READ_BIT), + VertexAttributeRead(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); + + private final int vkEnum; + + Access(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int bits() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/CompareOp.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/CompareOp.java new file mode 100644 index 0000000000..d652296fad --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/CompareOp.java @@ -0,0 +1,29 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum CompareOp implements IntEnum { + + LessOrEqual(VK_COMPARE_OP_LESS_OR_EQUAL), + Always(VK_COMPARE_OP_ALWAYS), + Equal(VK_COMPARE_OP_EQUAL), + Greater(VK_COMPARE_OP_GREATER), + Less(VK_COMPARE_OP_LESS), + GreaterOrEqual(VK_COMPARE_OP_GREATER_OR_EQUAL), + Never(VK_COMPARE_OP_NEVER), + NotEqual(VK_COMPARE_OP_NOT_EQUAL); + + private final int vkEnum; + + CompareOp(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/ComputePipeline.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/ComputePipeline.java new file mode 100644 index 0000000000..bd668efda5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/ComputePipeline.java @@ -0,0 +1,46 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.util.natives.Native; +import com.jme3.vulkan.shader.ShaderModule; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkComputePipelineCreateInfo; +import org.lwjgl.vulkan.VkPipelineShaderStageCreateInfo; + +import java.nio.LongBuffer; + +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK10.VK_NULL_HANDLE; + +public class ComputePipeline extends Pipeline { + + private final ShaderModule shader; + + public ComputePipeline(LogicalDevice device, PipelineBindPoint bindPoint, PipelineLayout layout, ShaderModule shader, String entryPoint) { + super(device, bindPoint, layout); + this.shader = shader; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkPipelineShaderStageCreateInfo stage = VkPipelineShaderStageCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) + .stage(VK_SHADER_STAGE_COMPUTE_BIT) + .module(shader.getNativeObject()) + .pName(stack.UTF8(entryPoint)); + VkComputePipelineCreateInfo.Buffer pipeline = VkComputePipelineCreateInfo.calloc(1, stack) + .sType(VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO) + .stage(stage) + .layout(layout.getNativeObject()) + .basePipelineHandle(VK_NULL_HANDLE) + .basePipelineIndex(-1); + LongBuffer idBuf = stack.mallocLong(1); + vkCreateComputePipelines(device.getNativeObject(), VK_NULL_HANDLE, pipeline, null, idBuf); + object = idBuf.get(0); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + + public ShaderModule getShader() { + return shader; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/CullMode.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/CullMode.java new file mode 100644 index 0000000000..22c4fd90a4 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/CullMode.java @@ -0,0 +1,25 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.Flag; + +import static org.lwjgl.vulkan.VK10.*; + +public enum CullMode implements Flag { + + None(VK_CULL_MODE_NONE), + Back(VK_CULL_MODE_BACK_BIT), + Front(VK_CULL_MODE_FRONT_BIT), + FrontAndBack(VK_CULL_MODE_FRONT_AND_BACK); + + private final int bits; + + CullMode(int bits) { + this.bits = bits; + } + + @Override + public int bits() { + return bits; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/FaceWinding.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/FaceWinding.java new file mode 100644 index 0000000000..13d87661ba --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/FaceWinding.java @@ -0,0 +1,23 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum FaceWinding implements IntEnum { + + Clockwise(VK_FRONT_FACE_CLOCKWISE), + CounterClockwise(VK_FRONT_FACE_COUNTER_CLOCKWISE); + + private final int vkEnum; + + FaceWinding(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/FrameBuffer.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/FrameBuffer.java new file mode 100644 index 0000000000..fdbb8c8205 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/FrameBuffer.java @@ -0,0 +1,87 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.images.VulkanImageView; +import com.jme3.vulkan.pass.RenderPass; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkFramebufferCreateInfo; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class FrameBuffer implements Native { + + private final LogicalDevice device; + private final NativeReference ref; + private final int width, height, layers; + private final VulkanImageView[] attachments; + private long id; + + public FrameBuffer(LogicalDevice device, RenderPass compat, int width, int height, int layers, VulkanImageView... attachments) { + this.device = device; + this.width = width; + this.height = height; + this.layers = layers; + this.attachments = attachments; + try (MemoryStack stack = MemoryStack.stackPush()) { + LongBuffer att = stack.mallocLong(attachments.length); + for (int i = 0; i < attachments.length; i++) { + att.put(i, attachments[i].getNativeObject()); + } + VkFramebufferCreateInfo create = VkFramebufferCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO) + .renderPass(compat.getNativeObject()) + .pAttachments(att) + .width(width).height(height) + .layers(layers); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreateFramebuffer(device.getNativeObject(), create, null, idBuf)); + id = idBuf.get(0); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> { + vkDestroyFramebuffer(device.getNativeObject(), id, null); + }; + } + + @Override + public void prematureNativeDestruction() { + id = VK_NULL_HANDLE; + } + + @Override + public NativeReference getNativeReference() { + return ref; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getLayers() { + return layers; + } + + public VulkanImageView[] getAttachments() { + return attachments; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/GraphicsPipeline.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/GraphicsPipeline.java new file mode 100644 index 0000000000..aec10648fc --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/GraphicsPipeline.java @@ -0,0 +1,147 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.util.natives.AbstractNative; +import com.jme3.util.natives.Native; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.pass.RenderPass; +import com.jme3.vulkan.pipelines.states.*; +import com.jme3.vulkan.shader.ShaderModule; +import com.jme3.vulkan.shader.ShaderStage; +import org.lwjgl.vulkan.*; + +import java.nio.LongBuffer; +import java.util.ArrayList; +import java.util.Collection; + +import static com.jme3.renderer.vulkan.VulkanUtils.check; +import static org.lwjgl.vulkan.VK10.*; + +public class GraphicsPipeline extends Pipeline { + + private final RenderPass compat; + private final int subpassIndex; + + public GraphicsPipeline(LogicalDevice device, PipelineLayout layout, RenderPass compat, int subpassIndex) { + super(device, PipelineBindPoint.Graphics, layout); + this.compat = compat; + this.subpassIndex = subpassIndex; + } + + public RenderPass getCompat() { + return compat; + } + + public int getSubpassIndex() { + return subpassIndex; + } + + public Builder build() { + return new Builder(); + } + + public class Builder extends AbstractNative.Builder { + + private final Collection stages = new ArrayList<>(); + private final DynamicState dynamic = new DynamicState(); + private final VertexInputState vertexInput = new VertexInputState(); + private final InputAssemblyState inputAssembly = new InputAssemblyState(); + private final ViewportState viewport = new ViewportState(); + private final DepthStencilState depthStencil = new DepthStencilState(); + private final RasterizationState rasterization = new RasterizationState(); + private final MultisampleState multisample = new MultisampleState(); + private final ColorBlendState colorBlend = new ColorBlendState(); + + @Override + protected void build() { + VkPipelineShaderStageCreateInfo.Buffer stageBuf = VkPipelineShaderStageCreateInfo.calloc(stages.size(), stack); + for (ShaderStageInfo s : stages) { + stageBuf.get().sType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) + .stage(s.stage.bits()) + .module(s.module.getNativeObject()) + .pName(stack.UTF8(s.entryPoint)); + } + stageBuf.flip(); + VkGraphicsPipelineCreateInfo.Buffer pipeline = VkGraphicsPipelineCreateInfo.calloc(1, stack) + .sType(VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO) + .stageCount(stageBuf.limit()) + .pStages(stageBuf) + .pVertexInputState(vertexInput.toStruct(stack)) + .pInputAssemblyState(inputAssembly.toStruct(stack)) + .pViewportState(viewport.toStruct(stack)) + .pDepthStencilState(depthStencil.toStruct(stack)) + .pRasterizationState(rasterization.toStruct(stack)) + .pMultisampleState(multisample.toStruct(stack)) + .pColorBlendState(colorBlend.toStruct(stack)) + .pDynamicState(dynamic.toStruct(stack)) + .layout(layout.getNativeObject()) + .renderPass(compat.getNativeObject()) + .subpass(subpassIndex) + .basePipelineHandle(VK_NULL_HANDLE) + .basePipelineIndex(-1); + System.out.println("render pass: " + compat.getNativeObject()); + LongBuffer idBuf = stack.mallocLong(1); + // todo: look into pipeline caching + check(vkCreateGraphicsPipelines(device.getNativeObject(), VK_NULL_HANDLE, pipeline, null, idBuf), + "Failed to create graphics pipeline"); + object = idBuf.get(0); + ref = Native.get().register(GraphicsPipeline.this); + device.getNativeReference().addDependent(ref); + } + + public void addShader(ShaderModule module, ShaderStage stage) { + addShader(module, stage, DEFAULT_SHADER_ENTRY_POINT); + } + + public void addShader(ShaderModule module, ShaderStage stage, String entryPoint) { + this.stages.add(new ShaderStageInfo(module, stage, entryPoint)); + } + + public DynamicState getDynamicState() { + return dynamic; + } + + public VertexInputState getVertexInput() { + return vertexInput; + } + + public InputAssemblyState getInputAssembly() { + return inputAssembly; + } + + public ViewportState getViewportState() { + return viewport; + } + + public DepthStencilState getDepthStencil() { + return depthStencil; + } + + public RasterizationState getRasterization() { + return rasterization; + } + + public MultisampleState getMultisample() { + return multisample; + } + + public ColorBlendState getColorBlend() { + return colorBlend; + } + + } + + public static class ShaderStageInfo { + + private final ShaderModule module; + private final ShaderStage stage; + private final String entryPoint; + + public ShaderStageInfo(ShaderModule module, ShaderStage stage, String entryPoint) { + this.module = module; + this.stage = stage; + this.entryPoint = entryPoint; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/LogicOp.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/LogicOp.java new file mode 100644 index 0000000000..1feed0881f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/LogicOp.java @@ -0,0 +1,37 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum LogicOp implements IntEnum { + + Copy(VK_LOGIC_OP_COPY), + And(VK_LOGIC_OP_AND), + Or(VK_LOGIC_OP_OR), + None(VK_LOGIC_OP_NO_OP), + Clear(VK_LOGIC_OP_CLEAR), + AndInverted(VK_LOGIC_OP_AND_INVERTED), + AndReverse(VK_LOGIC_OP_AND_REVERSE), + CopyInverted(VK_LOGIC_OP_COPY_INVERTED), + Equivalent(VK_LOGIC_OP_EQUIVALENT), + Invert(VK_LOGIC_OP_INVERT), + Nand(VK_LOGIC_OP_NAND), + Nor(VK_LOGIC_OP_NOR), + OrInverted(VK_LOGIC_OP_OR_INVERTED), + OrReverse(VK_LOGIC_OP_OR_REVERSE), + Set(VK_LOGIC_OP_SET), + Xor(VK_LOGIC_OP_XOR); + + private final int vkEnum; + + LogicOp(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Pipeline.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Pipeline.java new file mode 100644 index 0000000000..10037d5286 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Pipeline.java @@ -0,0 +1,44 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.devices.LogicalDevice; + +import static org.lwjgl.vulkan.VK10.*; + +public abstract class Pipeline extends AbstractNative { + + public static final String DEFAULT_SHADER_ENTRY_POINT = "main"; + + protected final LogicalDevice device; + protected final PipelineBindPoint bindPoint; + protected final PipelineLayout layout; + + public Pipeline(LogicalDevice device, PipelineBindPoint bindPoint, PipelineLayout layout) { + this.device = device; + this.bindPoint = bindPoint; + this.layout = layout; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyPipeline(device.getNativeObject(), object, null); + } + + public void bind(CommandBuffer cmd) { + vkCmdBindPipeline(cmd.getBuffer(), bindPoint.getVkEnum(), object); + } + + public LogicalDevice getDevice() { + return device; + } + + public PipelineBindPoint getBindPoint() { + return bindPoint; + } + + public PipelineLayout getLayout() { + return layout; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineBindPoint.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineBindPoint.java new file mode 100644 index 0000000000..3307e56118 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineBindPoint.java @@ -0,0 +1,20 @@ +package com.jme3.vulkan.pipelines; + +import static org.lwjgl.vulkan.VK10.*; + +public enum PipelineBindPoint { + + Graphics(VK_PIPELINE_BIND_POINT_GRAPHICS), + Compute(VK_PIPELINE_BIND_POINT_COMPUTE); + + private final int vkEnum; + + PipelineBindPoint(int vkEnum) { + this.vkEnum = vkEnum; + } + + public int getVkEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineLayout.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineLayout.java new file mode 100644 index 0000000000..99fb221206 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineLayout.java @@ -0,0 +1,62 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.renderer.vulkan.VulkanUtils; +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.descriptors.DescriptorSetLayout; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkPipelineLayoutCreateInfo; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class PipelineLayout implements Native { + + private final LogicalDevice device; + private final NativeReference ref; + private final DescriptorSetLayout[] layouts; + private final long id; + + public PipelineLayout(LogicalDevice device, DescriptorSetLayout... layouts) { + this.device = device; + this.layouts = layouts; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkPipelineLayoutCreateInfo create = VkPipelineLayoutCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO) + .setLayoutCount(layouts.length) + .pSetLayouts(VulkanUtils.accumulate(stack, layouts)); + LongBuffer idBuf = stack.mallocLong(1); + check(vkCreatePipelineLayout(device.getNativeObject(), create, null, idBuf), + "Failed to create pipeline."); + id = idBuf.get(0); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyPipelineLayout(device.getNativeObject(), id, null); + } + + @Override + public void prematureNativeDestruction() {} + + @Override + public NativeReference getNativeReference() { + return ref; + } + + public DescriptorSetLayout[] getDescriptorSetLayouts() { + return layouts; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineStage.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineStage.java new file mode 100644 index 0000000000..ac93159b84 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PipelineStage.java @@ -0,0 +1,39 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.Flag; + +import static org.lwjgl.vulkan.VK10.*; + +public enum PipelineStage implements Flag { + + TopOfPipe(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT), + ColorAttachmentOutput(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT), + AllCommands(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT), + AllGraphics(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT), + EarlyFragmentTests(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT), + BottomOfPipe(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT), + ComputeShader(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT), + DrawIndirect(VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT), + FragmentShader(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT), + GeometryShader(VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT), + Host(VK_PIPELINE_STAGE_HOST_BIT), + LateFragmentTests(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), + TessellationControlShader(VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT), + TessellationEvalShader(VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT), + Transfer(VK_PIPELINE_STAGE_TRANSFER_BIT), + VertexInput(VK_PIPELINE_STAGE_VERTEX_INPUT_BIT), + VertexShader(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT), + None(0); + + private final int vkEnum; + + PipelineStage(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int bits() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PolygonMode.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PolygonMode.java new file mode 100644 index 0000000000..7146b81878 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/PolygonMode.java @@ -0,0 +1,24 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum PolygonMode implements IntEnum { + + Fill(VK_POLYGON_MODE_FILL), + Line(VK_POLYGON_MODE_LINE), + Point(VK_POLYGON_MODE_POINT); + + private final int vkEnum; + + PolygonMode(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Topology.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Topology.java new file mode 100644 index 0000000000..abc30f15e7 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/Topology.java @@ -0,0 +1,32 @@ +package com.jme3.vulkan.pipelines; + +import com.jme3.vulkan.util.IntEnum; + +import static org.lwjgl.vulkan.VK10.*; + +public enum Topology implements IntEnum { + + LineList(VK_PRIMITIVE_TOPOLOGY_LINE_LIST), + LineStrip(VK_PRIMITIVE_TOPOLOGY_LINE_STRIP), + TriangleList(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST), + PatchList(VK_PRIMITIVE_TOPOLOGY_PATCH_LIST), + PointList(VK_PRIMITIVE_TOPOLOGY_POINT_LIST), + LineListAdjacency(VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY), + LineStripAdjacency(VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY), + TriangleFan(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN), + TriangleListAdjacency(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY), + TriangleStrip(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP), + TriangleStripAdjacency(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY); + + private final int vkEnum; + + Topology(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ColorBlendAttachment.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ColorBlendAttachment.java new file mode 100644 index 0000000000..d7541e84c0 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ColorBlendAttachment.java @@ -0,0 +1,62 @@ +package com.jme3.vulkan.pipelines.states; + +import org.lwjgl.vulkan.VkPipelineColorBlendAttachmentState; + +import static org.lwjgl.vulkan.VK10.*; + +public class ColorBlendAttachment { + + private int colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT + | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + private boolean blend = false; + private int srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + private int dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + private int colorBlendOp = VK_BLEND_OP_ADD; + private int srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + private int dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + private int alphaBlendOp = VK_BLEND_OP_ADD; + + public void writeToStruct(VkPipelineColorBlendAttachmentState struct) { + struct.colorWriteMask(colorWriteMask) + .blendEnable(blend) + .srcColorBlendFactor(srcColorBlendFactor) + .dstColorBlendFactor(dstColorBlendFactor) + .colorBlendOp(colorBlendOp) + .srcAlphaBlendFactor(srcAlphaBlendFactor) + .dstAlphaBlendFactor(dstAlphaBlendFactor) + .alphaBlendOp(alphaBlendOp); + } + + public void setColorWriteMask(int colorWriteMask) { + this.colorWriteMask = colorWriteMask; + } + + public void setBlend(boolean blend) { + this.blend = blend; + } + + public void setSrcColorBlendFactor(int srcColorBlendFactor) { + this.srcColorBlendFactor = srcColorBlendFactor; + } + + public void setDstColorBlendFactor(int dstColorBlendFactor) { + this.dstColorBlendFactor = dstColorBlendFactor; + } + + public void setColorBlendOp(int colorBlendOp) { + this.colorBlendOp = colorBlendOp; + } + + public void setSrcAlphaBlendFactor(int srcAlphaBlendFactor) { + this.srcAlphaBlendFactor = srcAlphaBlendFactor; + } + + public void setDstAlphaBlendFactor(int dstAlphaBlendFactor) { + this.dstAlphaBlendFactor = dstAlphaBlendFactor; + } + + public void setAlphaBlendOp(int alphaBlendOp) { + this.alphaBlendOp = alphaBlendOp; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ColorBlendState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ColorBlendState.java new file mode 100644 index 0000000000..b51e4927cf --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ColorBlendState.java @@ -0,0 +1,46 @@ +package com.jme3.vulkan.pipelines.states; + +import com.jme3.vulkan.pipelines.LogicOp; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkPipelineColorBlendAttachmentState; +import org.lwjgl.vulkan.VkPipelineColorBlendStateCreateInfo; + +import java.util.ArrayList; +import java.util.List; + +import static org.lwjgl.vulkan.VK10.VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + +public class ColorBlendState implements PipelineState { + + private final List attachments = new ArrayList<>(); + private boolean logicEnabled = false; + private IntEnum logic = LogicOp.Copy; + + @Override + public VkPipelineColorBlendStateCreateInfo toStruct(MemoryStack stack) { + VkPipelineColorBlendAttachmentState.Buffer attBuf = VkPipelineColorBlendAttachmentState.calloc(attachments.size(), stack); + for (ColorBlendAttachment a : attachments) { + a.writeToStruct(attBuf.get()); + } + attBuf.flip(); + return VkPipelineColorBlendStateCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO) + .logicOpEnable(logicEnabled) + .logicOp(logic.getEnum()) + .pAttachments(attBuf); + } + + public void addAttachment(ColorBlendAttachment attachment) { + this.attachments.add(attachment); + } + + public void setLogicEnabled(boolean logicEnabled) { + this.logicEnabled = logicEnabled; + } + + public void setLogic(IntEnum logic) { + this.logic = logic; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/DepthStencilState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/DepthStencilState.java new file mode 100644 index 0000000000..52e8bbe192 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/DepthStencilState.java @@ -0,0 +1,48 @@ +package com.jme3.vulkan.pipelines.states; + +import com.jme3.vulkan.pipelines.CompareOp; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VK10; +import org.lwjgl.vulkan.VkPipelineDepthStencilStateCreateInfo; + +public class DepthStencilState implements PipelineState { + + private boolean depthTest = true; + private boolean depthWrite = true; + private boolean depthBoundsTest = false; + private boolean stencilTest = false; + private IntEnum depthCompare = CompareOp.LessOrEqual; + + @Override + public VkPipelineDepthStencilStateCreateInfo toStruct(MemoryStack stack) { + return VkPipelineDepthStencilStateCreateInfo.calloc(stack) + .sType(VK10.VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO) + .depthTestEnable(depthTest) + .depthWriteEnable(depthWrite) + .depthBoundsTestEnable(depthBoundsTest) + .stencilTestEnable(stencilTest) + .depthCompareOp(depthCompare.getEnum()); + } + + public void setDepthTest(boolean depthTest) { + this.depthTest = depthTest; + } + + public void setDepthWrite(boolean depthWrite) { + this.depthWrite = depthWrite; + } + + public void setDepthBoundsTest(boolean depthBoundsTest) { + this.depthBoundsTest = depthBoundsTest; + } + + public void setStencilTest(boolean stencilTest) { + this.stencilTest = stencilTest; + } + + public void setDepthCompare(IntEnum depthCompare) { + this.depthCompare = depthCompare; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/DynamicState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/DynamicState.java new file mode 100644 index 0000000000..a9a56ccd21 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/DynamicState.java @@ -0,0 +1,65 @@ +package com.jme3.vulkan.pipelines.states; + +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkPipelineDynamicStateCreateInfo; + +import java.nio.IntBuffer; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.lwjgl.vulkan.VK10.*; + +public class DynamicState implements PipelineState { + + public enum Type implements IntEnum { + + ViewPort(VK_DYNAMIC_STATE_VIEWPORT), + Scissor(VK_DYNAMIC_STATE_SCISSOR), + BlendConstants(VK_DYNAMIC_STATE_BLEND_CONSTANTS), + DepthBias(VK_DYNAMIC_STATE_DEPTH_BIAS), + DepthBounds(VK_DYNAMIC_STATE_DEPTH_BOUNDS), + LineWidth(VK_DYNAMIC_STATE_LINE_WIDTH), + StencilCompareMask(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK), + StencilReference(VK_DYNAMIC_STATE_STENCIL_REFERENCE), + StencilWriteMask(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); + + private final int vkEnum; + + Type(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + } + + private final Set> states = new HashSet<>(); + + @SafeVarargs + public DynamicState(IntEnum... types) { + addTypes(types); + } + + @Override + public VkPipelineDynamicStateCreateInfo toStruct(MemoryStack stack) { + IntBuffer stateBuf = stack.mallocInt(states.size()); + for (IntEnum t : states) { + stateBuf.put(t.getEnum()); + } + stateBuf.flip(); + return VkPipelineDynamicStateCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO) + .pDynamicStates(stateBuf); + } + + @SafeVarargs + public final void addTypes(IntEnum... types) { + states.addAll(Arrays.asList(types)); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/InputAssemblyState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/InputAssemblyState.java new file mode 100644 index 0000000000..3be8212b6b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/InputAssemblyState.java @@ -0,0 +1,30 @@ +package com.jme3.vulkan.pipelines.states; + +import com.jme3.vulkan.pipelines.Topology; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VK10; +import org.lwjgl.vulkan.VkPipelineInputAssemblyStateCreateInfo; + +public class InputAssemblyState implements PipelineState { + + private IntEnum topology = Topology.TriangleList; + private boolean primitiveRestart = false; + + @Override + public VkPipelineInputAssemblyStateCreateInfo toStruct(MemoryStack stack) { + return VkPipelineInputAssemblyStateCreateInfo.calloc(stack) + .sType(VK10.VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO) + .topology(topology.getEnum()) + .primitiveRestartEnable(primitiveRestart); + } + + public void setTopology(IntEnum topology) { + this.topology = topology; + } + + public void setPrimitiveRestart(boolean primitiveRestart) { + this.primitiveRestart = primitiveRestart; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/MultisampleState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/MultisampleState.java new file mode 100644 index 0000000000..e6f069dc8b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/MultisampleState.java @@ -0,0 +1,29 @@ +package com.jme3.vulkan.pipelines.states; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkPipelineMultisampleStateCreateInfo; + +import static org.lwjgl.vulkan.VK10.*; + +public class MultisampleState implements PipelineState { + + private int rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + private boolean sampleShading = false; + + @Override + public VkPipelineMultisampleStateCreateInfo toStruct(MemoryStack stack) { + return VkPipelineMultisampleStateCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO) + .sampleShadingEnable(sampleShading) + .rasterizationSamples(rasterizationSamples); + } + + public void setRasterizationSamples(int rasterizationSamples) { + this.rasterizationSamples = rasterizationSamples; + } + + public void setSampleShading(boolean sampleShading) { + this.sampleShading = sampleShading; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/PipelineState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/PipelineState.java new file mode 100644 index 0000000000..aade269037 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/PipelineState.java @@ -0,0 +1,10 @@ +package com.jme3.vulkan.pipelines.states; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.Struct; + +public interface PipelineState { + + T toStruct(MemoryStack stack); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/RasterizationState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/RasterizationState.java new file mode 100644 index 0000000000..91a1052863 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/RasterizationState.java @@ -0,0 +1,64 @@ +package com.jme3.vulkan.pipelines.states; + +import com.jme3.vulkan.pipelines.CullMode; +import com.jme3.vulkan.pipelines.FaceWinding; +import com.jme3.vulkan.pipelines.PolygonMode; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkPipelineRasterizationStateCreateInfo; + +import static org.lwjgl.vulkan.VK10.*; + +public class RasterizationState implements PipelineState { + + private IntEnum polygonMode = PolygonMode.Fill; + private Flag cullMode = CullMode.Back; + private IntEnum faceWinding = FaceWinding.Clockwise; + private float lineWidth = 1f; + private boolean depthClamp = false; + private boolean rasterizerDiscard = false; + private boolean depthBias = false; + + @Override + public VkPipelineRasterizationStateCreateInfo toStruct(MemoryStack stack) { + return VkPipelineRasterizationStateCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO) + .depthClampEnable(depthClamp) + .rasterizerDiscardEnable(rasterizerDiscard) + .polygonMode(polygonMode.getEnum()) + .lineWidth(lineWidth) + .cullMode(cullMode.bits()) + .frontFace(faceWinding.getEnum()) + .depthBiasEnable(depthBias); + } + + public void setPolygonMode(IntEnum polygonMode) { + this.polygonMode = polygonMode; + } + + public void setCullMode(Flag cullMode) { + this.cullMode = cullMode; + } + + public void setFaceWinding(IntEnum faceWinding) { + this.faceWinding = faceWinding; + } + + public void setLineWidth(float lineWidth) { + this.lineWidth = lineWidth; + } + + public void setDepthClamp(boolean depthClamp) { + this.depthClamp = depthClamp; + } + + public void setRasterizerDiscard(boolean rasterizerDiscard) { + this.rasterizerDiscard = rasterizerDiscard; + } + + public void setDepthBias(boolean depthBias) { + this.depthBias = depthBias; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/VertexInputState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/VertexInputState.java new file mode 100644 index 0000000000..393662cf13 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/VertexInputState.java @@ -0,0 +1,27 @@ +package com.jme3.vulkan.pipelines.states; + +import com.jme3.vulkan.mesh.MeshDescription; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VK10; +import org.lwjgl.vulkan.VkPipelineVertexInputStateCreateInfo; + +import java.util.Objects; + +public class VertexInputState implements PipelineState { + + private MeshDescription mesh; + + @Override + public VkPipelineVertexInputStateCreateInfo toStruct(MemoryStack stack) { + Objects.requireNonNull(mesh, "Mesh description is not defined."); + return VkPipelineVertexInputStateCreateInfo.calloc(stack) + .sType(VK10.VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO) + .pVertexBindingDescriptions(mesh.getBindingInfo(stack)) + .pVertexAttributeDescriptions(mesh.getAttributeInfo(stack)); + } + + public void setMesh(MeshDescription mesh) { + this.mesh = mesh; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ViewportState.java b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ViewportState.java new file mode 100644 index 0000000000..9bd2243978 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/pipelines/states/ViewportState.java @@ -0,0 +1,87 @@ +package com.jme3.vulkan.pipelines.states; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkPipelineViewportStateCreateInfo; +import org.lwjgl.vulkan.VkRect2D; +import org.lwjgl.vulkan.VkViewport; + +import java.util.ArrayList; +import java.util.List; + +import static org.lwjgl.vulkan.VK10.VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + +public class ViewportState implements PipelineState { + + private final List viewports = new ArrayList<>(); + private final List scissors = new ArrayList<>(); + + @Override + public VkPipelineViewportStateCreateInfo toStruct(MemoryStack stack) { + VkViewport.Buffer vpBuf = VkViewport.calloc(viewports.size(), stack); + for (ViewportInfo v : viewports) { + vpBuf.get().x(v.x).y(v.y).width(v.w).height(v.h).minDepth(v.min).maxDepth(v.max); + } + vpBuf.flip(); + VkRect2D.Buffer scissorBuf = VkRect2D.calloc(scissors.size(), stack); + for (ScissorInfo s : scissors) { + VkRect2D e = scissorBuf.get(); + e.offset().set(s.x, s.y); + e.extent().set(s.w, s.h); + } + scissorBuf.flip(); + return VkPipelineViewportStateCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO) + .pViewports(vpBuf) + .pScissors(scissorBuf); + } + + public void addViewport() { + addViewport(0f, 0f, 128f, 128f); + } + + public void addViewport(float x, float y, float w, float h) { + addViewport(x, y, w, h, 0f, 1f); + } + + public void addViewport(float x, float y, float w, float h, float minDepth, float maxDepth) { + viewports.add(new ViewportInfo(x, y, w, h, minDepth, maxDepth)); + } + + public void addScissor() { + addScissor(0, 0, 128, 128); + } + + public void addScissor(int x, int y, int w, int h) { + scissors.add(new ScissorInfo(x, y, w, h)); + } + + private static class ViewportInfo { + + public final float x, y, w, h; + public final float min, max; + + public ViewportInfo(float x, float y, float w, float h, float min, float max) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.min = min; + this.max = max; + } + + } + + private static class ScissorInfo { + + public final int x, y, w, h; + + public ScissorInfo(int x, int y, int w, int h) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/shader/ShaderModule.java b/jme3-core/src/main/java/com/jme3/vulkan/shader/ShaderModule.java new file mode 100644 index 0000000000..b8f17bd62f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/shader/ShaderModule.java @@ -0,0 +1,54 @@ +package com.jme3.vulkan.shader; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.vulkan.VkShaderModuleCreateInfo; + +import java.nio.ByteBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class ShaderModule implements Native { + + private final LogicalDevice device; + private final NativeReference ref; + private long id; + + public ShaderModule(LogicalDevice device, ByteBuffer code) { + this.device = device; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkShaderModuleCreateInfo create = VkShaderModuleCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO) + .pCode(code); + id = getLong(stack, ptr -> check(vkCreateShaderModule(device.getNativeObject(), create, null, ptr), + "Failed to create shader module.")); + } + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyShaderModule(device.getNativeObject(), id, null); + } + + @Override + public void prematureNativeDestruction() { + id = MemoryUtil.NULL; + } + + @Override + public NativeReference getNativeReference() { + return ref; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/shader/ShaderStage.java b/jme3-core/src/main/java/com/jme3/vulkan/shader/ShaderStage.java new file mode 100644 index 0000000000..332c80497c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/shader/ShaderStage.java @@ -0,0 +1,29 @@ +package com.jme3.vulkan.shader; + +import com.jme3.vulkan.util.Flag; + +import static org.lwjgl.vulkan.VK10.*; + +public enum ShaderStage implements Flag { + + All(VK_SHADER_STAGE_ALL), + AllGraphics(VK_SHADER_STAGE_ALL_GRAPHICS), + Vertex(VK_SHADER_STAGE_VERTEX_BIT), + Geometry(VK_SHADER_STAGE_GEOMETRY_BIT), + TessellationEval(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), + TessellationControl(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), + Fragment(VK_SHADER_STAGE_FRAGMENT_BIT), + Compute(VK_SHADER_STAGE_COMPUTE_BIT); + + private final int vkEnum; + + ShaderStage(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int bits() { + return vkEnum; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/shader/UniformTestStruct.java b/jme3-core/src/main/java/com/jme3/vulkan/shader/UniformTestStruct.java new file mode 100644 index 0000000000..55a851d9c0 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/shader/UniformTestStruct.java @@ -0,0 +1,103 @@ +package com.jme3.vulkan.shader; + +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.system.NativeResource; +import org.lwjgl.system.Struct; +import org.lwjgl.system.StructBuffer; + +import java.nio.ByteBuffer; + +public class UniformTestStruct extends Struct { + + public static final int SIZEOF; + public static final int ALIGNOF; + + public static final int X, Y, Z, W; + + static { + Layout layout = __struct( + __member(Float.BYTES), + __member(Float.BYTES), + __member(Float.BYTES), + __member(Float.BYTES) + ); + SIZEOF = layout.getSize(); + ALIGNOF = layout.getAlignment(); + X = layout.offsetof(0); + Y = layout.offsetof(1); + Z = layout.offsetof(2); + W = layout.offsetof(3); + } + + public UniformTestStruct(ByteBuffer container) { + this(MemoryUtil.memAddress(container), __checkContainer(container, SIZEOF)); + } + + protected UniformTestStruct(long address, ByteBuffer container) { + super(address, container); + } + + @Override + protected UniformTestStruct create(long address, ByteBuffer container) { + return new UniformTestStruct(address, container); + } + + @Override + public int sizeof() { + return SIZEOF; + } + + public float x() { + return nx(address()); + } + + public void x(float x) { + nx(address(), x); + } + + public static float nx(long struct) { + return MemoryUtil.memGetFloat(struct + X); + } + + public static void nx(long struct, float x) { + MemoryUtil.memPutFloat(struct + X, x); + } + + public static UniformTestStruct calloc() { + return new UniformTestStruct(MemoryUtil.nmemCallocChecked(1, SIZEOF), null); + } + + public static UniformTestStruct create(long address) { + return new UniformTestStruct(address, null); + } + + public static class Buffer extends StructBuffer implements NativeResource { + + private static final UniformTestStruct FACTORY = new UniformTestStruct(-1L, null); + + protected Buffer(ByteBuffer container, int remaining) { + super(container, remaining); + } + + protected Buffer(long address, ByteBuffer container, int mark, int position, int limit, int capacity) { + super(address, container, mark, position, limit, capacity); + } + + @Override + protected UniformTestStruct getElementFactory() { + return null; + } + + @Override + protected Buffer self() { + return this; + } + + @Override + protected Buffer create(long address, ByteBuffer container, int mark, int position, int limit, int capacity) { + return new Buffer(address, container, mark, position, limit, capacity); + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/struct/MappedStruct.java b/jme3-core/src/main/java/com/jme3/vulkan/struct/MappedStruct.java new file mode 100644 index 0000000000..e67accae37 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/struct/MappedStruct.java @@ -0,0 +1,11 @@ +package com.jme3.vulkan.struct; + +import com.jme3.vulkan.buffers.GpuBuffer; + +public interface MappedStruct extends GpuBuffer { + + void set(String name, Object value); + + T get(String name); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/struct/Structure.java b/jme3-core/src/main/java/com/jme3/vulkan/struct/Structure.java new file mode 100644 index 0000000000..72facf4e0c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/struct/Structure.java @@ -0,0 +1,66 @@ +package com.jme3.vulkan.struct; + +import com.jme3.vulkan.memory.MemorySize; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.Struct; + +import java.nio.ByteBuffer; + +public class Structure extends Struct implements MappedStruct { + + public Structure(long address, ByteBuffer container) { + super(address, container); + Layout layout = __struct( + __member(4), + __member(4), + __member(4) + ); + layout.offsetof(0); + } + + @Override + public void set(String name, Object value) { + + } + + @Override + protected Structure create(long address, ByteBuffer container) { + return null; + } + + @Override + public int sizeof() { + return 0; + } + + @Override + public T get(String name) { + return null; + } + + @Override + public PointerBuffer map(int offset, int size) { + return null; + } + + @Override + public void unmap() { + + } + + @Override + public void freeMemory() { + + } + + @Override + public MemorySize size() { + return null; + } + + @Override + public long getId() { + return 0; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/surface/Surface.java b/jme3-core/src/main/java/com/jme3/vulkan/surface/Surface.java new file mode 100644 index 0000000000..957204752f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/surface/Surface.java @@ -0,0 +1,78 @@ +package com.jme3.vulkan.surface; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.VulkanInstance; +import com.jme3.vulkan.devices.DeviceFilter; +import com.jme3.vulkan.devices.PhysicalDevice; +import org.lwjgl.glfw.GLFWVulkan; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.lwjgl.vulkan.KHRSurface; + +import java.nio.IntBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; + +public class Surface implements Native, DeviceFilter { + + private final VulkanInstance instance; + private final NativeReference ref; + private final long window; + private long id; + + public Surface(VulkanInstance instance, long window) { + this.instance = instance; + this.window = window; + try (MemoryStack stack = MemoryStack.stackPush()) { + id = getLong(stack, ptr -> check(GLFWVulkan.glfwCreateWindowSurface( + instance.getNativeObject(), window, null, ptr), + "Failed to create surface for GLFW window.")); + ref = Native.get().register(this); + instance.getNativeReference().addDependent(ref); + } + } + + @Override + public Float evaluateDevice(PhysicalDevice device) { + try (MemoryStack stack = MemoryStack.stackPush()) { + IntBuffer count = stack.mallocInt(1); + KHRSurface.vkGetPhysicalDeviceSurfaceFormatsKHR(device.getDeviceHandle(), id, count, null); + if (count.get(0) == 0) { + System.out.println("Reject device by surface support (formats)"); + return null; + } + KHRSurface.vkGetPhysicalDeviceSurfacePresentModesKHR(device.getDeviceHandle(), id, count, null); + if (count.get(0) == 0) { + System.out.println("Reject device by surface support (present modes)"); + return null; + } + return 0f; + } + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> KHRSurface.vkDestroySurfaceKHR(instance.getNativeObject(), id, null); + } + + @Override + public void prematureNativeDestruction() { + id = MemoryUtil.NULL; + } + + @Override + public NativeReference getNativeReference() { + return ref; + } + + public long getWindowHandle() { + return window; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/surface/Swapchain.java b/jme3-core/src/main/java/com/jme3/vulkan/surface/Swapchain.java new file mode 100644 index 0000000000..492ed9b05c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/surface/Swapchain.java @@ -0,0 +1,415 @@ +package com.jme3.vulkan.surface; + +import com.jme3.texture.ImageView; +import com.jme3.util.natives.AbstractNative; +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.*; +import com.jme3.vulkan.commands.Queue; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.images.GpuImage; +import com.jme3.vulkan.images.ImageUsage; +import com.jme3.vulkan.images.VulkanImageView; +import com.jme3.vulkan.images.VulkanImage; +import com.jme3.vulkan.pipelines.FrameBuffer; +import com.jme3.vulkan.pass.RenderPass; +import com.jme3.vulkan.sync.Fence; +import com.jme3.vulkan.sync.Semaphore; +import com.jme3.vulkan.sync.SyncGroup; +import com.jme3.vulkan.util.Extent2; +import com.jme3.vulkan.util.Flag; +import com.jme3.vulkan.util.IntEnum; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class Swapchain extends AbstractNative { + + public enum PresentMode implements IntEnum { + + FirstInFirstOut(KHRSurface.VK_PRESENT_MODE_FIFO_KHR), + FirstInFirstOutRelaxed(KHRSurface.VK_PRESENT_MODE_FIFO_RELAXED_KHR), + Immediate(KHRSurface.VK_PRESENT_MODE_IMMEDIATE_KHR), + Mailbox(KHRSurface.VK_PRESENT_MODE_MAILBOX_KHR); + + private final int vkEnum; + + PresentMode(int vkEnum) { + this.vkEnum = vkEnum; + } + + @Override + public int getEnum() { + return vkEnum; + } + + } + + private final LogicalDevice device; + private final Surface surface; + private final List images = new ArrayList<>(); + private Consumer builder; + private Extent2 extent; + private Format format; + private int imageLayers = 1; + private Flag imageUsage = ImageUsage.ColorAttachment; + + public Swapchain(LogicalDevice device, Surface surface) { + this.device = device; + this.surface = surface; + this.object = VK_NULL_HANDLE; + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + surface.getNativeReference().addDependent(ref); + } + + @Override + public Runnable createNativeDestroyer() { + return () -> KHRSwapchain.vkDestroySwapchainKHR(device.getNativeObject(), object, null); + } + + public void createFrameBuffers(RenderPass compat, VulkanImageView depthStencil) { + for (PresentImage img : images) { + img.createFrameBuffer(compat, depthStencil); + } + } + + public PresentImage acquireNextImage(SwapchainUpdater updater, Semaphore semaphore, Fence fence, long timeoutMillis) { + try (MemoryStack stack = MemoryStack.stackPush()) { + IntBuffer i = stack.mallocInt(1); + int code = KHRSwapchain.vkAcquireNextImageKHR(device.getNativeObject(), object, + TimeUnit.MILLISECONDS.toNanos(timeoutMillis), Native.getId(semaphore), Native.getId(fence), i); + if (updater.swapchainOutOfDate(this, code)) { + return null; + } + return images.get(i.get(0)); + } + } + + public void present(Queue presentQueue, PresentImage image, SyncGroup sync) { + int imageIndex = images.indexOf(image); + if (imageIndex < 0) { + throw new IllegalArgumentException("Image does not belong to this swapchain."); + } + try (MemoryStack stack = MemoryStack.stackPush()) { + VkPresentInfoKHR info = VkPresentInfoKHR.calloc(stack) + .sType(KHRSwapchain.VK_STRUCTURE_TYPE_PRESENT_INFO_KHR) + .swapchainCount(1) + .pSwapchains(stack.longs(object)) + .pImageIndices(stack.ints(imageIndex)); + if (sync.containsWaits()) { + info.pWaitSemaphores(sync.toWaitBuffer(stack)); + } + check(KHRSwapchain.vkQueuePresentKHR(presentQueue.getQueue(), info)); + } + } + + public void build(Consumer builder) { + if (builder == null) { + throw new NullPointerException("Builder function cannot be null."); + } + try (Builder b = new Builder()) { + (this.builder = builder).accept(b); + } + } + + public void update() { + build(builder); + } + + public LogicalDevice getDevice() { + return device; + } + + public Surface getSurface() { + return surface; + } + + public List getImages() { + return Collections.unmodifiableList(images); + } + + public Extent2 getExtent() { + return extent; + } + + public Format getFormat() { + return format; + } + + public int getImageLayers() { + return imageLayers; + } + + public Flag getImageUsage() { + return imageUsage; + } + + public class PresentImage implements VulkanImage { + + private final LogicalDevice device; + private final long id; + private final VulkanImageView colorView; + private FrameBuffer frameBuffer; + + private PresentImage(LogicalDevice device, long id) { + this.device = device; + this.id = id; + colorView = new VulkanImageView(this, ImageView.Type.TwoDemensional); + try (VulkanImageView.Builder v = colorView.build()) { + v.setLayerCount(imageLayers); + } + } + + @Override + public LogicalDevice getDevice() { + return device; + } + + @Override + public long getId() { + return id; + } + + @Override + public IntEnum getType() { + return GpuImage.Type.TwoDemensional; + } + + @Override + public int getWidth() { + return extent.x; + } + + @Override + public int getHeight() { + return extent.y; + } + + @Override + public int getDepth() { + return 1; // swapchain images are always 2D + } + + @Override + public int getMipmaps() { + return 1; // swapchain images always have only 1 mipmap + } + + @Override + public int getLayers() { + return imageLayers; + } + + @Override + public Flag getUsage() { + return imageUsage; + } + + @Override + public Format getFormat() { + return format; + } + + @Override + public VulkanImage.Tiling getTiling() { + return VulkanImage.Tiling.Optimal; + } + + @Override + public IntEnum getSharingMode() { + return SharingMode.Exclusive; + } + + @Override + public void addNativeDependent(NativeReference ref) { + Swapchain.this.ref.addDependent(ref); + } + + public void createFrameBuffer(RenderPass compat, VulkanImageView depthStencil) { + this.frameBuffer = new FrameBuffer(getDevice(), compat, extent.x, extent.y, 1, colorView, depthStencil); + } + + public FrameBuffer getFrameBuffer() { + return frameBuffer; + } + + } + + public class Builder extends AbstractNative.Builder { + + private final VkSurfaceCapabilitiesKHR caps; + private final VkSurfaceFormatKHR.Buffer formats; + private final IntBuffer modes; + private final Collection queues = new ArrayList<>(); + + private VkSurfaceFormatKHR selectedFormat; + private VkExtent2D selectedExtent; + private IntEnum selectedMode; + private Integer selectedImageCount; + + private Swapchain base; + + public Builder() { + caps = VkSurfaceCapabilitiesKHR.malloc(stack); + KHRSurface.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.getPhysicalDevice().getDeviceHandle(), surface.getNativeObject(), caps); + formats = enumerateBuffer(stack, n -> VkSurfaceFormatKHR.malloc(n, stack), (count, buffer) + -> KHRSurface.vkGetPhysicalDeviceSurfaceFormatsKHR(device.getPhysicalDevice().getDeviceHandle(), + surface.getNativeObject(), count, buffer)); + modes = enumerateBuffer(stack, stack::mallocInt, (count, buffer) -> + KHRSurface.vkGetPhysicalDeviceSurfacePresentModesKHR(device.getPhysicalDevice().getDeviceHandle(), + surface.getNativeObject(), count, buffer)); + if (formats == null || modes == null) { + throw new UnsupportedOperationException("Swapchains are not supported by the device."); + } + } + + @Override + protected void build() { + if (selectedFormat == null) { + throw new IllegalStateException("Format not selected."); + } + if (selectedMode == null) { + throw new IllegalStateException("Mode not selected."); + } + if (selectedExtent == null) { + selectExtentByWindow(); + } + if (selectedImageCount == null) { + throw new IllegalStateException("Image count not selected."); + } + if (object != VK_NULL_HANDLE) { + createNativeDestroyer().run(); + object = VK_NULL_HANDLE; + } + VkSurfaceCapabilitiesKHR caps = VkSurfaceCapabilitiesKHR.calloc(stack); + KHRSurface.vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + device.getPhysicalDevice().getDeviceHandle(), surface.getNativeObject(), caps); + format = Format.byVkEnum(selectedFormat.format()); + extent = new Extent2(selectedExtent); + VkSwapchainCreateInfoKHR create = VkSwapchainCreateInfoKHR.calloc(stack) + .sType(KHRSwapchain.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR) + .surface(surface.getNativeObject()) + .minImageCount(selectedImageCount) + .imageFormat(format.getVkEnum()) + .imageColorSpace(selectedFormat.colorSpace()) + .imageExtent(selectedExtent) + .imageArrayLayers(imageLayers) + .imageUsage(imageUsage.bits()) + .preTransform(caps.currentTransform()) + .compositeAlpha(KHRSurface.VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) + .presentMode(selectedMode.getEnum()) + .clipped(true); + if (base != null) { + create.oldSwapchain(base.getNativeObject()); + } else { + create.oldSwapchain(VK_NULL_HANDLE); + } + if (queues.size() > 1) { + IntBuffer concurrent = stack.mallocInt(queues.size()); + for (Queue q : queues) { + concurrent.put(q.getFamilyIndex()); + } + concurrent.flip(); + create.imageSharingMode(VK_SHARING_MODE_CONCURRENT) + .queueFamilyIndexCount(queues.size()) + .pQueueFamilyIndices(concurrent); + } else { + create.imageSharingMode(VK_SHARING_MODE_EXCLUSIVE); + } + LongBuffer ptr = stack.mallocLong(1); + check(KHRSwapchain.vkCreateSwapchainKHR(device.getNativeObject(), create, null, ptr), + "Failed to create swapchain."); + object = ptr.get(0); + System.out.println("swapchain handle: " + object); + LongBuffer imgs = enumerateBuffer(stack, stack::mallocLong, (c, b) -> + check(KHRSwapchain.vkGetSwapchainImagesKHR(device.getNativeObject(), object, c, b), + "Failed to get swapchain images.")); + Objects.requireNonNull(imgs, "Swapchain contains no images."); + for (int i = 0; i < imgs.limit(); i++) { + images.add(new PresentImage(device, imgs.get(i))); + } + ref.refresh(); + } + + public void setBaseSwapchain(Swapchain base) { + this.base = base; + } + + public void addQueue(Queue queue) { + queues.add(queue); + } + + public VkSurfaceFormatKHR selectFormat(int... preferredFormats) { + for (VkSurfaceFormatKHR f : formats) { + for (int i = 0; i < preferredFormats.length; i += 2) { + if (f.format() == preferredFormats[i] && f.colorSpace() == preferredFormats[i + 1]) { + return (selectedFormat = f); + } + } + } + return (selectedFormat = formats.get(0)); + } + + @SafeVarargs + public final IntEnum selectMode(IntEnum... preferredModes) { + for (IntEnum m : preferredModes) { + for (int i = 0; i < modes.limit(); i++) { + if (modes.get(i) == m.getEnum()) { + return (selectedMode = m); + } + } + } + return (selectedMode = PresentMode.FirstInFirstOut); + } + + public VkExtent2D selectExtentByWindow() { + if (caps.currentExtent().width() != UINT32_MAX) { + return (selectedExtent = caps.currentExtent()); + } + IntBuffer width = stack.mallocInt(1); + IntBuffer height = stack.mallocInt(1); + GLFW.glfwGetFramebufferSize(surface.getWindowHandle(), width, height); + selectedExtent = VkExtent2D.malloc(stack); + selectedExtent.width(Math.min(Math.max(width.get(0), caps.minImageExtent().width()), caps.maxImageExtent().width())); + selectedExtent.height(Math.min(Math.max(width.get(0), caps.minImageExtent().height()), caps.maxImageExtent().height())); + return selectedExtent; + } + + public int selectImageCount(int preferredCount) { + if (preferredCount < caps.minImageCount()) { + preferredCount = caps.minImageCount(); + } else if (caps.maxImageCount() > 0 && preferredCount > caps.maxImageCount()) { + preferredCount = caps.maxImageCount(); + } + return (selectedImageCount = preferredCount); + } + + public void setImageLayers(int layers) { + Swapchain.this.imageLayers = layers; + } + + public void setImageUsage(Flag usage) { + Swapchain.this.imageUsage = usage; + } + + public int getMinImageCount() { + return caps.minImageCount(); + } + + public int getMaxImageCount() { + return caps.maxImageCount(); + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/surface/SwapchainUpdater.java b/jme3-core/src/main/java/com/jme3/vulkan/surface/SwapchainUpdater.java new file mode 100644 index 0000000000..42f019a6b6 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/surface/SwapchainUpdater.java @@ -0,0 +1,7 @@ +package com.jme3.vulkan.surface; + +public interface SwapchainUpdater { + + boolean swapchainOutOfDate(Swapchain swapchain, int imageAcquireCode); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/sync/Fence.java b/jme3-core/src/main/java/com/jme3/vulkan/sync/Fence.java new file mode 100644 index 0000000000..cbf49f57c8 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/sync/Fence.java @@ -0,0 +1,88 @@ +package com.jme3.vulkan.sync; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkFenceCreateInfo; + +import java.util.concurrent.TimeUnit; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.system.MemoryUtil.NULL; +import static org.lwjgl.vulkan.VK10.*; + +public class Fence implements Native { + + private final LogicalDevice device; + private final NativeReference ref; + private long id; + + public Fence(LogicalDevice device) { + this(device, false); + } + + public Fence(LogicalDevice device, boolean signal) { + this.device = device; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkFenceCreateInfo create = VkFenceCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_FENCE_CREATE_INFO) + .flags(signal ? VK_FENCE_CREATE_SIGNALED_BIT : 0); + id = getLong(stack, ptr -> check(vkCreateFence(device.getNativeObject(), create, null, ptr), + "Failed to create fence.")); + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroyFence(device.getNativeObject(), nonNull(id), null); + } + + @Override + public void prematureNativeDestruction() { + id = NULL; + } + + @Override + public NativeReference getNativeReference() { + return ref; + } + + public String toString() { + return "Fence[" + !isBlocking() + "]"; + } + + public void block(long timeoutMillis) { + check(vkWaitForFences(device.getNativeObject(), id, true, TimeUnit.MILLISECONDS.toNanos(timeoutMillis)), + "Fence wait expired."); + } + + public void blockThenReset(long timeoutMillis) { + block(timeoutMillis); + reset(); + } + + public void reset() { + vkResetFences(device.getNativeObject(), id); + } + + public SyncGroup toGroup() { + return new SyncGroup(this); + } + + public boolean isBlocking() { + return vkGetFenceStatus(device.getNativeObject(), id) != VK_SUCCESS; + } + + public long getId() { + return id; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/sync/Semaphore.java b/jme3-core/src/main/java/com/jme3/vulkan/sync/Semaphore.java new file mode 100644 index 0000000000..a8bc0c3572 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/sync/Semaphore.java @@ -0,0 +1,79 @@ +package com.jme3.vulkan.sync; + +import com.jme3.util.natives.Native; +import com.jme3.util.natives.AbstractNative; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.pipelines.PipelineStage; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkSemaphoreCreateInfo; + +import java.nio.LongBuffer; + +import static com.jme3.renderer.vulkan.VulkanUtils.*; +import static org.lwjgl.vulkan.VK10.*; + +public class Semaphore extends AbstractNative { + + public static final Semaphore[] EMPTY = new Semaphore[0]; + + private final LogicalDevice device; + private Flag dstStageMask; + + public Semaphore(LogicalDevice device) { + this(device, PipelineStage.None); + } + + public Semaphore(LogicalDevice device, Flag dstStageMask) { + this.device = device; + this.dstStageMask = dstStageMask; + try (MemoryStack stack = MemoryStack.stackPush()) { + VkSemaphoreCreateInfo create = VkSemaphoreCreateInfo.calloc(stack) + .sType(VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO); + object = getLong(stack, ptr -> check(vkCreateSemaphore(device.getNativeObject(), create, null, ptr), + "Failed to create semaphore.")); + ref = Native.get().register(this); + device.getNativeReference().addDependent(ref); + } + } + + @Override + public Runnable createNativeDestroyer() { + return () -> vkDestroySemaphore(device.getNativeObject(), nonNull(object), null); + } + + public void setDstStageMask(Flag dstStageMask) { + this.dstStageMask = dstStageMask; + } + + public void addDstStage(Flag stageBit) { + this.dstStageMask = this.dstStageMask.add(stageBit); + } + + public void removeDstStageBit(Flag stageBit) { + this.dstStageMask = this.dstStageMask.remove(stageBit); + } + + public Flag getDstStageMask() { + return dstStageMask; + } + + public SyncGroup toGroupWait() { + return new SyncGroup(this, EMPTY); + } + + public SyncGroup toGroupSignal() { + return new SyncGroup(EMPTY, this); + } + + @Deprecated + public long getId() { + return object; + } + + @Deprecated + public LongBuffer toBuffer(MemoryStack stack) { + return stack.longs(object); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/sync/SyncGroup.java b/jme3-core/src/main/java/com/jme3/vulkan/sync/SyncGroup.java new file mode 100644 index 0000000000..597b73db07 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/sync/SyncGroup.java @@ -0,0 +1,166 @@ +package com.jme3.vulkan.sync; + +import com.jme3.vulkan.devices.LogicalDevice; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VK10; + +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.util.Objects; + +public class SyncGroup { + + public static final SyncGroup ASYNC = new SyncGroup(); + + private static Semaphore[] toArray(Semaphore s) { + return s != null ? new Semaphore[] {s} : Semaphore.EMPTY; + } + + private Semaphore[] waits; + private Semaphore[] signals; + private Fence fence; + + public SyncGroup() { + this(Semaphore.EMPTY, Semaphore.EMPTY, null); + } + + public SyncGroup(Fence fence) { + this(Semaphore.EMPTY, Semaphore.EMPTY, fence); + } + + public SyncGroup(Semaphore wait, Semaphore signal) { + this(toArray(wait), toArray(signal), null); + } + + public SyncGroup(Semaphore wait, Semaphore[] signals) { + this(toArray(wait), signals, null); + } + + public SyncGroup(Semaphore[] waits, Semaphore signal) { + this(waits, toArray(signal), null); + } + + public SyncGroup(Semaphore[] waits, Semaphore[] signals) { + this(waits, signals, null); + } + + public SyncGroup(Semaphore wait, Semaphore signal, Fence fence) { + this(toArray(wait), toArray(signal), fence); + } + + public SyncGroup(Semaphore wait, Semaphore[] signals, Fence fence) { + this(toArray(wait), signals, fence); + } + + public SyncGroup(Semaphore[] waits, Semaphore signal, Fence fence) { + this(waits, toArray(signal), fence); + } + + public SyncGroup(Semaphore[] waits, Semaphore[] signals, Fence fence) { + this.waits = Objects.requireNonNull(waits); + this.signals = Objects.requireNonNull(signals); + this.fence = fence; + } + + public void setWaits(Semaphore... waits) { + this.waits = Objects.requireNonNull(waits); + } + + public void setWaits(SyncGroup sync) { + this.waits = sync.waits; + } + + public Semaphore[] getWaits() { + return waits; + } + + public void setSignals(Semaphore... signals) { + this.signals = Objects.requireNonNull(signals); + } + + public void setSignals(SyncGroup sync) { + this.signals = sync.signals; + } + + public Semaphore[] getSignals() { + return signals; + } + + public void setFence(Fence fence) { + this.fence = fence; + } + + public void setFence(SyncGroup sync) { + this.fence = sync.fence; + } + + public Fence getFence() { + return fence; + } + + public Fence getOrCreateFence(LogicalDevice device) { + return getOrCreateFence(device, false); + } + + public Fence getOrCreateFence(LogicalDevice device, boolean signal) { + if (fence == null) { + fence = new Fence(device, signal); + } + return fence; + } + + public boolean containsWaits() { + return waits.length > 0; + } + + public boolean containsSignals() { + return signals.length > 0; + } + + public boolean containsFence() { + return fence != null; + } + + public LongBuffer toWaitBuffer(MemoryStack stack) { + LongBuffer buf = stack.mallocLong(waits.length); + for (Semaphore w : waits) { + buf.put(w.getNativeObject()); + } + buf.flip(); + return buf; + } + + public IntBuffer toDstStageBuffer(MemoryStack stack) { + IntBuffer buf = stack.mallocInt(waits.length); + for (Semaphore s : waits) { + if (s.getDstStageMask().isEmpty()) { + throw new IllegalStateException("Wait semaphore destination stage mask cannot be empty."); + } + buf.put(s.getDstStageMask().bits()); + } + buf.flip(); + return buf; + } + + public LongBuffer toSignalBuffer(MemoryStack stack) { + LongBuffer buf = stack.mallocLong(signals.length); + for (Semaphore s : signals) { + buf.put(s.getNativeObject()); + } + buf.flip(); + return buf; + } + + public long getFenceHandle() { + return fence != null ? fence.getNativeObject() : VK10.VK_NULL_HANDLE; + } + + public static SyncGroup wait(Semaphore... waits) { + return new SyncGroup(waits, Semaphore.EMPTY); + } + + public static SyncGroup signal(Semaphore... signals) { + return new SyncGroup(Semaphore.EMPTY, signals); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/sync/TaskQueue.java b/jme3-core/src/main/java/com/jme3/vulkan/sync/TaskQueue.java new file mode 100644 index 0000000000..69505c663a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/sync/TaskQueue.java @@ -0,0 +1,9 @@ +package com.jme3.vulkan.sync; + +import java.util.concurrent.Future; + +public interface TaskQueue { + + void submit(Future task); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/update/BasicCommandBatch.java b/jme3-core/src/main/java/com/jme3/vulkan/update/BasicCommandBatch.java new file mode 100644 index 0000000000..f2bc404267 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/update/BasicCommandBatch.java @@ -0,0 +1,39 @@ +package com.jme3.vulkan.update; + +import com.jme3.vulkan.commands.CommandBuffer; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class BasicCommandBatch implements CommandBatch { + + private final List> commands = new ArrayList<>(); + + @Override + public boolean run(CommandBuffer cmd, int frame) { + boolean run = false; + for (Iterator> it = commands.iterator(); it.hasNext();) { + Command c = it.next().get(); + if (c == null) { + it.remove(); + } else { + run = c.run(cmd, frame) || run; + } + } + return run; + } + + @Override + public T add(T command) { + commands.add(new WeakReference<>(command)); + return command; + } + + @Override + public void remove(Command command) { + commands.removeIf(ref -> ref.get() == command); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/update/Command.java b/jme3-core/src/main/java/com/jme3/vulkan/update/Command.java new file mode 100644 index 0000000000..b138d771b2 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/update/Command.java @@ -0,0 +1,9 @@ +package com.jme3.vulkan.update; + +import com.jme3.vulkan.commands.CommandBuffer; + +public interface Command { + + boolean run(CommandBuffer cmd, int frame); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/update/CommandBatch.java b/jme3-core/src/main/java/com/jme3/vulkan/update/CommandBatch.java new file mode 100644 index 0000000000..2e0152c161 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/update/CommandBatch.java @@ -0,0 +1,9 @@ +package com.jme3.vulkan.update; + +public interface CommandBatch extends Command { + + T add(T command); + + void remove(Command command); + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/update/CommandRunner.java b/jme3-core/src/main/java/com/jme3/vulkan/update/CommandRunner.java new file mode 100644 index 0000000000..428f4f8836 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/update/CommandRunner.java @@ -0,0 +1,62 @@ +package com.jme3.vulkan.update; + +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.frames.UpdateFrameManager; +import com.jme3.vulkan.sync.Fence; +import com.jme3.vulkan.sync.SyncGroup; + +import java.util.Objects; + +public class CommandRunner { + + private final LogicalDevice device; + private final UpdateFrameManager frames; + private final CommandBuffer buffer; + private CommandBatch commands; + private Fence prevRunFence; + + public CommandRunner(LogicalDevice device, UpdateFrameManager frames, CommandBuffer buffer) { + this(device, frames, buffer, null); + } + + public CommandRunner(LogicalDevice device, UpdateFrameManager frames, CommandBuffer buffer, CommandBatch commands) { + this.device = device; + this.frames = frames; + this.buffer = buffer; + } + + public void run(SyncGroup sync) { + if (prevRunFence != null) { + prevRunFence.block(5000); + } + buffer.resetAndBegin(); + if (Objects.requireNonNull(commands).run(buffer, frames.getCurrentFrame())) { + prevRunFence = sync.getOrCreateFence(device); + } else { + prevRunFence = null; + } + buffer.endAndSubmit(sync); + } + + public void setCommands(CommandBatch commands) { + this.commands = commands; + } + + public LogicalDevice getDevice() { + return device; + } + + public UpdateFrameManager getFrames() { + return frames; + } + + public CommandBuffer getBuffer() { + return buffer; + } + + public CommandBatch getCommands() { + return commands; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/util/Extent2.java b/jme3-core/src/main/java/com/jme3/vulkan/util/Extent2.java new file mode 100644 index 0000000000..f3b99e53eb --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/util/Extent2.java @@ -0,0 +1,58 @@ +package com.jme3.vulkan.util; + +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkExtent2D; + +public final class Extent2 { + + public int x, y; + + public Extent2() { + this(0, 0); + } + + public Extent2(int x, int y) { + this.x = x; + this.y = y; + } + + public Extent2(VkExtent2D vk) { + this.x = vk.width(); + this.y = vk.height(); + } + + public Extent2 set(int x, int y) { + this.x = x; + this.y = y; + return this; + } + + public Extent2 set(VkExtent2D vk) { + this.x = vk.width(); + this.y = vk.height(); + return this; + } + + public Extent2 setX(int x) { + this.x = x; + return this; + } + + public Extent2 setY(int y) { + this.y = y; + return this; + } + + public VkExtent2D toStruct(MemoryStack stack) { + return VkExtent2D.malloc(stack).set(x, y); + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/util/Flag.java b/jme3-core/src/main/java/com/jme3/vulkan/util/Flag.java new file mode 100644 index 0000000000..849f8e3096 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/util/Flag.java @@ -0,0 +1,90 @@ +package com.jme3.vulkan.util; + +public interface Flag { + + int bits(); + + default Flag add(Flag flag) { + return new FlagImpl<>(bits() | flag.bits()); + } + + default Flag add(Flag... flags) { + int result = bits(); + for (Flag f : flags) { + result |= f.bits(); + } + return new FlagImpl<>(result); + } + + default Flag remove(Flag flag) { + return new FlagImpl<>(bits() & ~flag.bits()); + } + + default Flag remove(Flag... flags) { + int result = bits(); + for (Flag f : flags) { + result &= ~f.bits(); + } + return new FlagImpl<>(result); + } + + default boolean contains(Flag flag) { + int bits = flag.bits(); + return (bits() & bits) == bits; + } + + default boolean containsAny(Flag flag) { + return (bits() & flag.bits()) > 0; + } + + default boolean isEmpty() { + return bits() == 0; + } + + default boolean is(Flag flag) { + return bits() == flag.bits(); + } + + static Flag of(int bits) { + return new FlagImpl<>(bits); + } + + static Flag empty() { + return of(0); + } + + @SafeVarargs + static Flag of(Flag... flags) { + return new FlagImpl<>(flags); + } + + @SafeVarargs + static int bitsOf(Flag... flags) { + int result = 0; + for (Flag f : flags) { + result |= f.bits(); + } + return result; + } + + class FlagImpl implements Flag { + + private final int bits; + + public FlagImpl(int bits) { + this.bits = bits; + } + + @SafeVarargs + public FlagImpl(Flag... flags) { + this.bits = bitsOf(flags); + } + + @Override + public int bits() { + return bits; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/util/FloatBufferModifier.java b/jme3-core/src/main/java/com/jme3/vulkan/util/FloatBufferModifier.java new file mode 100644 index 0000000000..4cae3cb808 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/util/FloatBufferModifier.java @@ -0,0 +1,127 @@ +package com.jme3.vulkan.util; + +import com.jme3.vulkan.mesh.VertexReader; +import com.jme3.vulkan.mesh.VertexWriter; + +import java.nio.FloatBuffer; + +public class FloatBufferModifier implements VertexReader, VertexWriter { + + private final FloatBuffer buffer; + private final int components; + + public FloatBufferModifier(FloatBuffer buffer, int components) { + this.buffer = buffer; + this.components = components; + } + + public int vertexToPosition(int vertex, int component) { + return vertex * components + component; + } + + @Override + public int capacity() { + return buffer.capacity() / components; + } + + @Override + public int limit() { + return buffer.limit() / components; + } + + @Override + public int components() { + return components; + } + + @Override + public VertexWriter limit(int vertex) { + buffer.limit(vertexToPosition(vertex, 0)); + return this; + } + + @Override + public VertexWriter putByte(int vertex, int component, byte value) { + buffer.put(vertexToPosition(vertex, component), value); + return this; + } + + @Override + public VertexWriter putShort(int vertex, int component, short value) { + buffer.put(vertexToPosition(vertex, component), value); + return this; + } + + @Override + public VertexWriter putInt(int vertex, int component, int value) { + buffer.put(vertexToPosition(vertex, component), value); + return this; + } + + @Override + public VertexWriter putFloat(int vertex, int component, float value) { + buffer.put(vertexToPosition(vertex, component), value); + return this; + } + + @Override + public VertexWriter putDouble(int vertex, int component, double value) { + buffer.put(vertexToPosition(vertex, component), (float)value); + return this; + } + + @Override + public VertexWriter putLong(int vertex, int component, long value) { + buffer.put(vertexToPosition(vertex, component), value); + return this; + } + + @Override + public VertexWriter putFloats(int baseVertex, int baseComponent, float... values) { + int p = buffer.position(); + buffer.position(vertexToPosition(baseVertex, baseComponent)); + buffer.put(values); + buffer.position(p); + return this; + } + + @Override + public VertexWriter putFloats(int baseVertex, int baseComponent, FloatBuffer values) { + int p = buffer.position(); + buffer.position(vertexToPosition(baseVertex, baseComponent)); + buffer.put(values); + buffer.position(p); + return this; + } + + @Override + public byte getByte(int vertex, int component) { + return (byte)buffer.get(vertexToPosition(vertex, component)); + } + + @Override + public short getShort(int vertex, int component) { + return (short)buffer.get(vertexToPosition(vertex, component)); + } + + @Override + public int getInt(int vertex, int component) { + return (int)buffer.get(vertexToPosition(vertex, component)); + } + + @Override + public float getFloat(int vertex, int component) { + return buffer.get(vertexToPosition(vertex, component)); + } + + @Override + public double getDouble(int vertex, int component) { + return buffer.get(vertexToPosition(vertex, component)); + } + + @Override + public long getLong(int vertex, int component) { + return (long)buffer.get(vertexToPosition(vertex, component)); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/util/IntEnum.java b/jme3-core/src/main/java/com/jme3/vulkan/util/IntEnum.java new file mode 100644 index 0000000000..5fd0f276ad --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/util/IntEnum.java @@ -0,0 +1,38 @@ +package com.jme3.vulkan.util; + +public interface IntEnum { + + int getEnum(); + + default boolean is(IntEnum intEnum) { + return intEnum != null && is(intEnum.getEnum()); + } + + default boolean is(int intEnum) { + return getEnum() == intEnum; + } + + static IntEnum get(IntEnum intEnum, IntEnum defEnum) { + return intEnum != null ? intEnum : defEnum; + } + + static IntEnum of(int libEnum) { + return new EnumImpl<>(libEnum); + } + + class EnumImpl implements IntEnum { + + private final int intEnum; + + public EnumImpl(int intEnum) { + this.intEnum = intEnum; + } + + @Override + public int getEnum() { + return intEnum; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/vulkan/util/RenderStateToVulkan.java b/jme3-core/src/main/java/com/jme3/vulkan/util/RenderStateToVulkan.java new file mode 100644 index 0000000000..b0988ab6a5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/vulkan/util/RenderStateToVulkan.java @@ -0,0 +1,84 @@ +package com.jme3.vulkan.util; + +import com.jme3.material.RenderState.*; +import static org.lwjgl.vulkan.VK10.*; + +public class RenderStateToVulkan { + + private static RuntimeException unrecognized(Object state) { + return new UnsupportedOperationException("Unrecognized: " + state); + } + + public static int depthFunc(TestFunction func) { + switch (func) { + case Always: return VK_COMPARE_OP_ALWAYS; + case Equal: return VK_COMPARE_OP_EQUAL; + case Greater: return VK_COMPARE_OP_GREATER; + case Less: return VK_COMPARE_OP_LESS; + case LessOrEqual: return VK_COMPARE_OP_LESS_OR_EQUAL; + case GreaterOrEqual: return VK_COMPARE_OP_GREATER_OR_EQUAL; + case Never: return VK_COMPARE_OP_NEVER; + case NotEqual: return VK_COMPARE_OP_NOT_EQUAL; + default: throw unrecognized(func); + } + } + + public static int blendEquation(BlendEquation eq) { + switch (eq) { + case Add: return VK_BLEND_OP_ADD; + case Subtract: return VK_BLEND_OP_SUBTRACT; + case ReverseSubtract: return VK_BLEND_OP_REVERSE_SUBTRACT; + case Min: return VK_BLEND_OP_MIN; + case Max: return VK_BLEND_OP_MAX; + default: throw unrecognized(eq); + } + } + + public static int blendEquationAlpha(BlendEquationAlpha eqA, BlendEquation eq) { + switch (eqA) { + case InheritColor: return blendEquation(eq); + case Add: return VK_BLEND_OP_ADD; + case Subtract: return VK_BLEND_OP_SUBTRACT; + case ReverseSubtract: return VK_BLEND_OP_REVERSE_SUBTRACT; + case Min: return VK_BLEND_OP_MIN; + case Max: return VK_BLEND_OP_MAX; + default: throw unrecognized(eqA); + } + } + + public static int blendFunc(BlendFunc func) { + switch (func) { + case Zero: return VK_BLEND_FACTOR_ZERO; + case One: return VK_BLEND_FACTOR_ONE; + case Src_Color: return VK_BLEND_FACTOR_SRC_COLOR; + case One_Minus_Src_Color: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + case Dst_Color: return VK_BLEND_FACTOR_DST_COLOR; + case One_Minus_Dst_Color: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + case Src_Alpha: return VK_BLEND_FACTOR_SRC_ALPHA; + case One_Minus_Src_Alpha: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + case Dst_Alpha: return VK_BLEND_FACTOR_DST_ALPHA; + case One_Minus_Dst_Alpha: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + case Src_Alpha_Saturate: return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; + default: throw unrecognized(func); + } + } + + public static int faceCull(FaceCullMode mode) { + switch (mode) { + case Off: return VK_CULL_MODE_NONE; + case Front: return VK_CULL_MODE_FRONT_BIT; + case Back: return VK_CULL_MODE_BACK_BIT; + case FrontAndBack: return VK_CULL_MODE_FRONT_AND_BACK; + default: throw unrecognized(mode); + } + } + + public static int wireframe(boolean wireframe, int def) { + return wireframe ? VK_POLYGON_MODE_LINE : def; + } + + public static int wireframe(boolean wireframe) { + return wireframe(wireframe, VK_POLYGON_MODE_FILL); + } + +} diff --git a/jme3-core/src/plugins/java/com/jme3/font/plugins/BitmapFontLoader.java b/jme3-core/src/plugins/java/com/jme3/font/plugins/BitmapFontLoader.java index b81253601c..0968b00332 100644 --- a/jme3-core/src/plugins/java/com/jme3/font/plugins/BitmapFontLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/font/plugins/BitmapFontLoader.java @@ -38,7 +38,7 @@ import com.jme3.material.Material; import com.jme3.material.MaterialDef; import com.jme3.material.RenderState.BlendMode; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -86,7 +86,7 @@ private BitmapFont load(AssetManager assetManager, String folder, InputStream in } }else if (tokens[0].equals("page")){ int index = -1; - Texture tex = null; + GlTexture tex = null; for (int i = 1; i < tokens.length; i++){ String token = tokens[i]; @@ -100,8 +100,8 @@ private BitmapFont load(AssetManager assetManager, String folder, InputStream in TextureKey key = new TextureKey(folder + file, true); key.setGenerateMips(false); tex = assetManager.loadTexture(key); - tex.setMagFilter(Texture.MagFilter.Bilinear); - tex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + tex.setMagFilter(GlTexture.MagFilter.Bilinear); + tex.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); } } // set page diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java index e874ed555c..819ccd1476 100644 --- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java @@ -43,7 +43,7 @@ import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.shader.*; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ColorSpace; import com.jme3.util.PlaceholderAssets; @@ -211,7 +211,7 @@ private boolean isTexturePathDeclaredTheTraditionalWay(final List textureValues = tokenizeTextureValue(value); final List textureOptionValues = parseTextureOptions(textureValues); @@ -267,17 +267,17 @@ private Texture parseTextureType(final VarType type, final String value) { switch (type) { case Texture3D: - textureKey.setTextureTypeHint(Texture.Type.ThreeDimensional); + textureKey.setTextureTypeHint(GlTexture.Type.ThreeDimensional); break; case TextureArray: - textureKey.setTextureTypeHint(Texture.Type.TwoDimensionalArray); + textureKey.setTextureTypeHint(GlTexture.Type.TwoDimensionalArray); break; case TextureCubeMap: - textureKey.setTextureTypeHint(Texture.Type.CubeMap); + textureKey.setTextureTypeHint(GlTexture.Type.CubeMap); break; } - Texture texture; + GlTexture texture; try { texture = assetManager.loadTexture(textureKey); @@ -403,7 +403,7 @@ private void readParam(String statement) throws IOException{ defaultValObj = readValue(type, defaultVal); } if(type.isTextureType()){ - materialDef.addMaterialParamTexture(type, name, colorSpace,(Texture)defaultValObj); + materialDef.addMaterialParamTexture(type, name, colorSpace,(GlTexture)defaultValObj); }else{ materialDef.addMaterialParam(type, name, defaultValObj); } @@ -426,7 +426,7 @@ private void readValueParam(String statement) throws IOException{ Object valueObj = readValue(p.getVarType(), split[1]); if (p.getVarType().isTextureType()){ - material.setTextureParam(name, p.getVarType(), (Texture) valueObj); + material.setTextureParam(name, p.getVarType(), (GlTexture) valueObj); }else{ material.setParam(name, p.getVarType(), valueObj); } @@ -857,60 +857,60 @@ protected void initNodesLoader() { private enum TextureOption { /** - * Applies a {@link com.jme3.texture.Texture.MinFilter} to the texture. + * Applies a {@link GlTexture.MinFilter} to the texture. */ Min { @Override public void applyToTextureKey(final String option, final TextureKey textureKey) { - Texture.MinFilter minFilter = Texture.MinFilter.valueOf(option); + GlTexture.MinFilter minFilter = GlTexture.MinFilter.valueOf(option); textureKey.setGenerateMips(minFilter.usesMipMapLevels()); } @Override - public void applyToTexture(final String option, final Texture texture) { - texture.setMinFilter(Texture.MinFilter.valueOf(option)); + public void applyToTexture(final String option, final GlTexture texture) { + texture.setMinFilter(GlTexture.MinFilter.valueOf(option)); } }, /** - * Applies a {@link com.jme3.texture.Texture.MagFilter} to the texture. + * Applies a {@link GlTexture.MagFilter} to the texture. */ Mag { @Override - public void applyToTexture(final String option, final Texture texture) { - texture.setMagFilter(Texture.MagFilter.valueOf(option)); + public void applyToTexture(final String option, final GlTexture texture) { + texture.setMagFilter(GlTexture.MagFilter.valueOf(option)); } }, /** - * Applies a {@link com.jme3.texture.Texture.WrapMode} to the texture. This also supports {@link com.jme3.texture.Texture.WrapAxis} + * Applies a {@link GlTexture.WrapMode} to the texture. This also supports {@link GlTexture.WrapAxis} * by adding "_AXIS" to the texture option. For instance if you wanted to repeat on the S (horizontal) axis, you * would use
WrapRepeat_S
as a texture option. */ Wrap { @Override - public void applyToTexture(final String option, final Texture texture) { + public void applyToTexture(final String option, final GlTexture texture) { final int separatorPosition = option.indexOf("_"); if (separatorPosition >= option.length() - 2) { final String axis = option.substring(separatorPosition + 1); final String mode = option.substring(0, separatorPosition); - final Texture.WrapAxis wrapAxis = Texture.WrapAxis.valueOf(axis); - texture.setWrap(wrapAxis, Texture.WrapMode.valueOf(mode)); + final GlTexture.WrapAxis wrapAxis = GlTexture.WrapAxis.valueOf(axis); + texture.setWrap(wrapAxis, GlTexture.WrapMode.valueOf(mode)); } else { - texture.setWrap(Texture.WrapMode.valueOf(option)); + texture.setWrap(GlTexture.WrapMode.valueOf(option)); } } }, /** - * Applies a {@link com.jme3.texture.Texture.WrapMode#Repeat} to the texture. This is simply an alias for + * Applies a {@link GlTexture.WrapMode#Repeat} to the texture. This is simply an alias for * WrapRepeat, please use WrapRepeat instead if possible as this may become deprecated later on. */ Repeat { @Override - public void applyToTexture(final String option, final Texture texture) { + public void applyToTexture(final String option, final GlTexture texture) { Wrap.applyToTexture("Repeat", texture); } }, @@ -929,7 +929,7 @@ public String getOptionValue(final String option) { return option.substring(name().length()); } - public void applyToTexture(final String option, final Texture texture) { + public void applyToTexture(final String option, final GlTexture texture) { } public void applyToTextureKey(final String option, final TextureKey textureKey) { @@ -964,7 +964,7 @@ public void applyToTextureKey(final TextureKey textureKey) { textureOption.applyToTextureKey(value, textureKey); } - public void applyToTexture(final Texture texture) { + public void applyToTexture(final GlTexture texture) { textureOption.applyToTexture(value, texture); } } diff --git a/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java b/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java index ac186c1606..8853bd0721 100644 --- a/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/scene/plugins/MTLLoader.java @@ -36,8 +36,8 @@ import com.jme3.material.MaterialList; import com.jme3.material.RenderState.BlendMode; import com.jme3.math.ColorRGBA; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.PlaceholderAssets; import java.io.File; @@ -60,7 +60,7 @@ public class MTLLoader implements AssetLoader { protected String folderName; protected AssetKey key; - protected Texture diffuseMap, normalMap, specularMap, alphaMap; + protected GlTexture diffuseMap, normalMap, specularMap, alphaMap; protected ColorRGBA ambient = new ColorRGBA(); protected ColorRGBA diffuse = new ColorRGBA(); protected ColorRGBA specular = new ColorRGBA(); @@ -167,7 +167,7 @@ protected void startMaterial(String name){ matName = name; } - protected Texture loadTexture(String path){ + protected GlTexture loadTexture(String path){ String[] split = path.trim().split("\\p{javaWhitespace}+"); // will crash if path is an empty string @@ -176,7 +176,7 @@ protected Texture loadTexture(String path){ String name = new File(path).getName(); TextureKey texKey = new TextureKey(folderName + name); texKey.setGenerateMips(true); - Texture texture; + GlTexture texture; try { texture = assetManager.loadTexture(texKey); texture.setWrap(WrapMode.Repeat); diff --git a/jme3-core/src/plugins/java/com/jme3/scene/plugins/OBJLoader.java b/jme3-core/src/plugins/java/com/jme3/scene/plugins/OBJLoader.java index cd2b4a29e8..21ea84d298 100644 --- a/jme3-core/src/plugins/java/com/jme3/scene/plugins/OBJLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/scene/plugins/OBJLoader.java @@ -38,7 +38,7 @@ import com.jme3.math.Vector3f; import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.scene.*; -import com.jme3.scene.Mesh.Mode; +import com.jme3.scene.GlMesh.Mode; import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.mesh.IndexBuffer; import com.jme3.scene.mesh.IndexIntBuffer; diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java index 6ea0f8d45d..a6b0cd7a8e 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/DDSLoader.java @@ -34,9 +34,9 @@ import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import com.jme3.util.LittleEndien; @@ -125,20 +125,20 @@ public Object load(AssetInfo info) throws IOException { in = new LittleEndien(stream); loadHeader(); if (texture3D) { - textureKey.setTextureTypeHint(Texture.Type.ThreeDimensional); + textureKey.setTextureTypeHint(GlTexture.Type.ThreeDimensional); } else if (depth > 1) { - textureKey.setTextureTypeHint(Texture.Type.CubeMap); + textureKey.setTextureTypeHint(GlTexture.Type.CubeMap); } ArrayList data = readData(textureKey.isFlipY()); - return new Image(pixelFormat, width, height, depth, data, sizes, ColorSpace.sRGB); + return new GlImage(pixelFormat, width, height, depth, data, sizes, ColorSpace.sRGB); } } - public Image load(InputStream stream) throws IOException { + public GlImage load(InputStream stream) throws IOException { in = new LittleEndien(stream); loadHeader(); ArrayList data = readData(false); - return new Image(pixelFormat, width, height, depth, data, sizes, ColorSpace.sRGB); + return new GlImage(pixelFormat, width, height, depth, data, sizes, ColorSpace.sRGB); } private void loadDX10Header() throws IOException { @@ -178,16 +178,16 @@ private void setPixelFormat(int dxgiFormat) throws IOException { pixelFormat = Format.DXT5; break; case DXGIFormat.DXGI_FORMAT_BC4_UNORM: - pixelFormat = Image.Format.RGTC1; + pixelFormat = GlImage.Format.RGTC1; break; case DXGIFormat.DXGI_FORMAT_BC4_SNORM: pixelFormat = Format.SIGNED_RGTC1; break; case DXGIFormat.DXGI_FORMAT_BC5_UNORM: - pixelFormat = Image.Format.RGTC2; + pixelFormat = GlImage.Format.RGTC2; break; case DXGIFormat.DXGI_FORMAT_BC5_SNORM: - pixelFormat = Image.Format.SIGNED_RGTC2; + pixelFormat = GlImage.Format.SIGNED_RGTC2; break; case DXGIFormat.DXGI_FORMAT_BC6H_UF16: pixelFormat = Format.BC6H_UF16; @@ -298,26 +298,26 @@ private void readPixelFormat() throws IOException { case PF_DXT1: bpp = 4; if (is(pfFlags, DDPF_ALPHAPIXELS)) { - pixelFormat = Image.Format.DXT1A; + pixelFormat = GlImage.Format.DXT1A; } else { - pixelFormat = Image.Format.DXT1; + pixelFormat = GlImage.Format.DXT1; } break; case PF_DXT3: bpp = 8; - pixelFormat = Image.Format.DXT3; + pixelFormat = GlImage.Format.DXT3; break; case PF_DXT5: bpp = 8; - pixelFormat = Image.Format.DXT5; + pixelFormat = GlImage.Format.DXT5; break; case PF_ATI1: bpp = 4; - pixelFormat = Image.Format.RGTC1; + pixelFormat = GlImage.Format.RGTC1; break; case PF_ATI2: bpp = 8; - pixelFormat = Image.Format.RGTC2; + pixelFormat = GlImage.Format.RGTC2; break; case PF_DX10: compressed = false; @@ -329,7 +329,7 @@ private void readPixelFormat() throws IOException { case 113: compressed = false; bpp = 64; - pixelFormat = Image.Format.RGBA16F; + pixelFormat = GlImage.Format.RGBA16F; break; case 111: compressed = false; diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/DXTFlipper.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/DXTFlipper.java index 10a02df4a3..6293c70985 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/DXTFlipper.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/DXTFlipper.java @@ -32,7 +32,7 @@ package com.jme3.texture.plugins; import com.jme3.math.FastMath; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ETCFlipper.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ETCFlipper.java index 0809a5f7bb..889ad55c1a 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ETCFlipper.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ETCFlipper.java @@ -3,7 +3,7 @@ import java.nio.ByteBuffer; import java.util.logging.Logger; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; /** * A place-holder for future implementation of ETC texture flipping. diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/HDRLoader.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/HDRLoader.java index 183049f9ec..b498df6ea6 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/HDRLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/HDRLoader.java @@ -35,8 +35,8 @@ import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; import com.jme3.math.FastMath; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import java.io.IOException; @@ -215,7 +215,7 @@ private void decodeScanline(InputStream in, int width) throws IOException{ } } - public Image load(InputStream in, boolean flipY) throws IOException{ + public GlImage load(InputStream in, boolean flipY) throws IOException{ float gamma = -1f; float exposure = -1f; @@ -305,7 +305,7 @@ public Image load(InputStream in, boolean flipY) throws IOException{ dataStore.rewind(); //HDR files color data is actually stored in linear space. - return new Image(pixelFormat, width, height, dataStore, ColorSpace.Linear); + return new GlImage(pixelFormat, width, height, dataStore, ColorSpace.Linear); } @Override @@ -317,7 +317,7 @@ public Object load(AssetInfo info) throws IOException { InputStream in = null; try { in = info.openStream(); - Image img = load(in, flip); + GlImage img = load(in, flip); return img; } finally { if (in != null){ diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ImageFlipper.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ImageFlipper.java index 0d5f39d84b..dfc788b9c4 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ImageFlipper.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ImageFlipper.java @@ -31,7 +31,7 @@ */ package com.jme3.texture.plugins; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; @@ -50,8 +50,8 @@ public class ImageFlipper { private ImageFlipper() { } - public static void flipImage(Image img, int index){ - if (img.getFormat().isCompressed()) + public static void flipImage(GlImage img, int index){ + if (img.getGlFormat().isCompressed()) throw new UnsupportedOperationException("Flipping compressed " + "images is unsupported."); @@ -60,7 +60,7 @@ public static void flipImage(Image img, int index){ int halfH = h / 2; // bytes per pixel - int bpp = img.getFormat().getBitsPerPixel() / 8; + int bpp = img.getGlFormat().getBitsPerPixel() / 8; int scanline = w * bpp; ByteBuffer data = img.getData(index); diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/PFMLoader.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/PFMLoader.java index 859d06fc77..dde12fcef3 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/PFMLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/PFMLoader.java @@ -34,8 +34,8 @@ import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import java.io.IOException; @@ -73,7 +73,7 @@ private void flipScanline(byte[] scanline){ } } - private Image load(InputStream in, boolean needYFlip) throws IOException{ + private GlImage load(InputStream in, boolean needYFlip) throws IOException{ Format format = null; String fmtStr = readString(in); @@ -130,7 +130,7 @@ private Image load(InputStream in, boolean needYFlip) throws IOException{ } imageData.rewind(); - return new Image(format, width, height, imageData, null, ColorSpace.Linear); + return new GlImage(format, width, height, imageData, null, ColorSpace.Linear); } @Override diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java index 13bf130977..edcad585fc 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java @@ -35,8 +35,8 @@ import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; import com.jme3.math.FastMath; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import com.jme3.util.BufferUtils; import java.io.BufferedInputStream; import java.io.DataInputStream; @@ -81,7 +81,7 @@ public Object load(AssetInfo info) throws IOException { InputStream in = null; try { in = info.openStream(); - Image img = load(in, flip); + GlImage img = load(in, flip); return img; } finally { if (in != null) { @@ -104,7 +104,7 @@ public Object load(AssetInfo info) throws IOException { * image, either as a RGB888 or RGBA8888 * @throws java.io.IOException if an I/O error occurs */ - public static Image load(InputStream in, boolean flip) throws IOException { + public static GlImage load(InputStream in, boolean flip) throws IOException { boolean flipH = false; // open a stream to the file @@ -470,7 +470,7 @@ public static Image load(InputStream in, boolean flip) throws IOException { scratch.put(rawData); scratch.rewind(); // Create the Image object - Image textureImage = new Image(); + GlImage textureImage = new GlImage(); textureImage.setFormat(format); textureImage.setWidth(width); textureImage.setHeight(height); diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXLoader.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXLoader.java index 9cd78b35a3..259a263487 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXLoader.java @@ -37,7 +37,7 @@ import com.jme3.renderer.Caps; import com.jme3.renderer.opengl.GLImageFormat; import com.jme3.renderer.opengl.GLImageFormats; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import com.jme3.util.LittleEndien; @@ -80,7 +80,7 @@ public Object load(AssetInfo info) throws IOException { InputStream in = null; try { in = info.openStream(); - Image img = load(in); + GlImage img = load(in); return img; } finally { if (in != null) { @@ -89,7 +89,7 @@ public Object load(AssetInfo info) throws IOException { } } - private Image load(InputStream stream) { + private GlImage load(InputStream stream) { byte[] fileId = new byte[12]; @@ -149,7 +149,7 @@ private Image load(InputStream stream) { int nbSlices = Math.max(numberOfFaces,numberOfArrayElements); - Image.Format imgFormat = getImageFormat(glFormat, glInternalFormat, glType); + GlImage.Format imgFormat = getImageFormat(glFormat, glInternalFormat, glType); log.log(Level.FINE, "img format {0}", imgFormat.toString()); @@ -159,7 +159,7 @@ private Image load(InputStream stream) { int[] mipMapSizes = new int[numberOfMipmapLevels]; - Image image = createImage(nbSlices, byteBuffersSize, imgFormat, pixelWidth, pixelHeight, pixelDepth); + GlImage image = createImage(nbSlices, byteBuffersSize, imgFormat, pixelWidth, pixelHeight, pixelDepth); byte[] pixelData = new byte[bytePerPixel]; @@ -258,12 +258,12 @@ private int computeBuffersSize(int numberOfMipmapLevels, int pixelWidth, int pix * @param depth * @return */ - private Image createImage(int nbSlices, int byteBuffersSize, Image.Format imgFormat, int pixelWidth, int pixelHeight, int depth) { + private GlImage createImage(int nbSlices, int byteBuffersSize, GlImage.Format imgFormat, int pixelWidth, int pixelHeight, int depth) { ArrayList imageData = new ArrayList<>(nbSlices); for (int i = 0; i < nbSlices; i++) { imageData.add(BufferUtils.createByteBuffer(byteBuffersSize)); } - Image image = new Image(imgFormat, pixelWidth, pixelHeight, depth, imageData, ColorSpace.sRGB); + GlImage image = new GlImage(imgFormat, pixelWidth, pixelHeight, depth, imageData, ColorSpace.sRGB); return image; } @@ -334,7 +334,7 @@ private boolean checkFileIdentifier(byte[] b) { * @param glType * @return */ - private Image.Format getImageFormat(int glFormat, int glInternalFormat, int glType) { + private GlImage.Format getImageFormat(int glFormat, int glInternalFormat, int glType) { EnumSet caps = EnumSet.allOf(Caps.class); GLImageFormat[][] formats = GLImageFormats.getFormatsForCaps(caps); for (GLImageFormat[] format : formats) { @@ -343,7 +343,7 @@ private Image.Format getImageFormat(int glFormat, int glInternalFormat, int glTy if (glImgFormat != null) { if (glImgFormat.format == glFormat && glImgFormat.dataType == glType) { if (glFormat == glInternalFormat || glImgFormat.internalFormat == glInternalFormat) { - return Image.Format.values()[j]; + return GlImage.Format.values()[j]; } } } diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXWriter.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXWriter.java index 116ec05df2..1d4366f79f 100644 --- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXWriter.java +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ktx/KTXWriter.java @@ -34,8 +34,8 @@ import com.jme3.renderer.Caps; import com.jme3.renderer.opengl.GLImageFormat; import com.jme3.renderer.opengl.GLImageFormats; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.Texture3D; import com.jme3.texture.TextureArray; @@ -83,7 +83,7 @@ public KTXWriter(String path) { * @param image the image to write * @param fileName the name of the file to write */ - public void write(Image image, String fileName) { + public void write(GlImage image, String fileName) { write(image, Texture2D.class, fileName); } @@ -97,7 +97,7 @@ public void write(Image image, String fileName) { * @param textureType the texture type * @param fileName the name of the file to write */ - public void write(Image image, Class textureType, String fileName) { + public void write(GlImage image, Class textureType, String fileName) { FileOutputStream outs = null; try { @@ -110,7 +110,7 @@ public void write(Image image, Class textureType, String file out.write(fileIdentifier); //endianness out.writeInt(0x04030201); - GLImageFormat format = getGlFormat(image.getFormat()); + GLImageFormat format = getGlFormat(image.getGlFormat()); //glType out.writeInt(format.dataType); //glTypeSize @@ -181,7 +181,7 @@ public void write(Image image, Class textureType, String file if (image.hasMipmaps()) { imageSize = image.getMipMapSizes()[mipLevel]; } else { - imageSize = width * height * image.getFormat().getBitsPerPixel() / 8; + imageSize = width * height * image.getGlFormat().getBitsPerPixel() / 8; } out.writeInt(imageSize); @@ -263,7 +263,7 @@ private byte[] getByteBufferArray(ByteBuffer byteBuffer, int size) { * @param format * @return */ - private GLImageFormat getGlFormat(Image.Format format) { + private GLImageFormat getGlFormat(GlImage.Format format) { EnumSet caps = EnumSet.allOf(Caps.class); GLImageFormat[][] formats = GLImageFormats.getFormatsForCaps(caps); return formats[0][format.ordinal()]; diff --git a/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java index 9b572e8e93..a11db8906b 100644 --- a/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java +++ b/jme3-core/src/test/java/com/jme3/material/MaterialMatParamTest.java @@ -50,8 +50,8 @@ import com.jme3.shader.DefineList; import com.jme3.system.NullRenderer; import com.jme3.system.TestUtil; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import java.util.ArrayList; import static org.junit.Assert.assertEquals; @@ -445,7 +445,7 @@ public void setShader(Shader shader) { } @Override - public void setTexture(int unit, Texture texture) { + public void setTexture(int unit, GlTexture texture) { MaterialMatParamTest.this.usedTextures[unit] = texture; } }; @@ -453,7 +453,7 @@ public void setTexture(int unit, Texture texture) { private boolean evaluated = false; private Shader usedShader = null; - private final Texture[] usedTextures = new Texture[32]; + private final GlTexture[] usedTextures = new GlTexture[32]; private void inputMp(MatParam... params) { if (evaluated) { @@ -530,7 +530,7 @@ private void evaluateTechniqueDef() { Assert.assertTrue(evaluated); } - private void outTextures(Texture... textures) { + private void outTextures(GlTexture... textures) { for (int i = 0; i < usedTextures.length; i++) { if (i < textures.length) { Assert.assertSame(textures[i], usedTextures[i]); diff --git a/jme3-core/src/test/java/com/jme3/material/MaterialTest.java b/jme3-core/src/test/java/com/jme3/material/MaterialTest.java index 6edd3ed34a..8b5eaf7407 100644 --- a/jme3-core/src/test/java/com/jme3/material/MaterialTest.java +++ b/jme3-core/src/test/java/com/jme3/material/MaterialTest.java @@ -39,9 +39,9 @@ import com.jme3.shader.VarType; import com.jme3.system.NullRenderer; import com.jme3.system.TestUtil; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.Texture2D; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; @@ -130,8 +130,8 @@ public void testSelectNamedTechnique_GLSL150Cap() { @Test public void testForcedColorSpace(){ - Image img=new Image(Format.RGBA8,2,2,BufferUtils.createByteBuffer(16),null,ColorSpace.sRGB); - Image img2=new Image(Format.RGBA8,2,2,BufferUtils.createByteBuffer(16),null,ColorSpace.sRGB); + GlImage img=new GlImage(Format.RGBA8,2,2,BufferUtils.createByteBuffer(16),null,ColorSpace.sRGB); + GlImage img2=new GlImage(Format.RGBA8,2,2,BufferUtils.createByteBuffer(16),null,ColorSpace.sRGB); Texture2D tx=new Texture2D(img); Texture2D tx2=new Texture2D(img2); diff --git a/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java b/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java index 7126d94fa8..5af7845993 100644 --- a/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java +++ b/jme3-core/src/test/java/com/jme3/material/plugins/J3MLoaderTest.java @@ -9,7 +9,7 @@ import com.jme3.material.MaterialDef; import com.jme3.renderer.Caps; import com.jme3.shader.VarType; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.io.IOException; import java.util.EnumSet; import org.junit.Before; @@ -84,8 +84,8 @@ public void multipleSameNamedTechniques_shouldBeSupported() throws IOException { public void oldStyleTextureParameters_shouldBeSupported() throws Exception { when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/texture-parameters-oldstyle.j3m")); - final Texture textureOldStyle = Mockito.mock(Texture.class); - final Texture textureOldStyleUsingQuotes = Mockito.mock(Texture.class); + final GlTexture textureOldStyle = Mockito.mock(GlTexture.class); + final GlTexture textureOldStyleUsingQuotes = Mockito.mock(GlTexture.class); final TextureKey textureKeyUsingQuotes = setupMockForTexture("OldStyleUsingQuotes", "old style using quotes/texture.png", true, true, textureOldStyleUsingQuotes); final TextureKey textureKeyOldStyle = setupMockForTexture("OldStyle", "old style/texture.png", true, true, textureOldStyle); @@ -94,22 +94,22 @@ public void oldStyleTextureParameters_shouldBeSupported() throws Exception { verify(assetManager).loadTexture(textureKeyUsingQuotes); verify(assetManager).loadTexture(textureKeyOldStyle); - verify(textureOldStyle).setWrap(Texture.WrapMode.Repeat); - verify(textureOldStyleUsingQuotes).setWrap(Texture.WrapMode.Repeat); + verify(textureOldStyle).setWrap(GlTexture.WrapMode.Repeat); + verify(textureOldStyleUsingQuotes).setWrap(GlTexture.WrapMode.Repeat); } @Test public void newStyleTextureParameters_shouldBeSupported() throws Exception { when(assetInfo.openStream()).thenReturn(J3MLoader.class.getResourceAsStream("/texture-parameters-newstyle.j3m")); - final Texture textureNoParameters = Mockito.mock(Texture.class); - final Texture textureFlip = Mockito.mock(Texture.class); - final Texture textureRepeat = Mockito.mock(Texture.class); - final Texture textureRepeatAxis = Mockito.mock(Texture.class); - final Texture textureMin = Mockito.mock(Texture.class); - final Texture textureMag = Mockito.mock(Texture.class); - final Texture textureCombined = Mockito.mock(Texture.class); - final Texture textureLooksLikeOldStyle = Mockito.mock(Texture.class); + final GlTexture textureNoParameters = Mockito.mock(GlTexture.class); + final GlTexture textureFlip = Mockito.mock(GlTexture.class); + final GlTexture textureRepeat = Mockito.mock(GlTexture.class); + final GlTexture textureRepeatAxis = Mockito.mock(GlTexture.class); + final GlTexture textureMin = Mockito.mock(GlTexture.class); + final GlTexture textureMag = Mockito.mock(GlTexture.class); + final GlTexture textureCombined = Mockito.mock(GlTexture.class); + final GlTexture textureLooksLikeOldStyle = Mockito.mock(GlTexture.class); final TextureKey textureKeyNoParameters = setupMockForTexture("Empty", "empty.png", false, true, textureNoParameters); final TextureKey textureKeyFlip = setupMockForTexture("Flip", "flip.png", true, true, textureFlip); @@ -125,17 +125,17 @@ public void newStyleTextureParameters_shouldBeSupported() throws Exception { verify(assetManager).loadTexture(textureKeyNoParameters); verify(assetManager).loadTexture(textureKeyFlip); - verify(textureRepeat).setWrap(Texture.WrapMode.Repeat); - verify(textureRepeatAxis).setWrap(Texture.WrapAxis.T, Texture.WrapMode.Repeat); - verify(textureMin).setMinFilter(Texture.MinFilter.Trilinear); - verify(textureMag).setMagFilter(Texture.MagFilter.Bilinear); + verify(textureRepeat).setWrap(GlTexture.WrapMode.Repeat); + verify(textureRepeatAxis).setWrap(GlTexture.WrapAxis.T, GlTexture.WrapMode.Repeat); + verify(textureMin).setMinFilter(GlTexture.MinFilter.Trilinear); + verify(textureMag).setMagFilter(GlTexture.MagFilter.Bilinear); - verify(textureCombined).setMagFilter(Texture.MagFilter.Nearest); - verify(textureCombined).setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - verify(textureCombined).setWrap(Texture.WrapMode.Repeat); + verify(textureCombined).setMagFilter(GlTexture.MagFilter.Nearest); + verify(textureCombined).setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); + verify(textureCombined).setWrap(GlTexture.WrapMode.Repeat); } - private TextureKey setupMockForTexture(final String paramName, final String path, final boolean flipY, boolean generateMips, final Texture texture) { + private TextureKey setupMockForTexture(final String paramName, final String path, final boolean flipY, boolean generateMips, final GlTexture texture) { when(materialDef.getMaterialParam(paramName)).thenReturn(new MatParamTexture(VarType.Texture2D, paramName, texture, null)); final TextureKey textureKey = new TextureKey(path, flipY); diff --git a/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java b/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java index 929281819e..ae99460114 100644 --- a/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java +++ b/jme3-core/src/test/java/com/jme3/renderer/OpaqueComparatorTest.java @@ -41,9 +41,9 @@ import com.jme3.scene.Mesh; import com.jme3.scene.shape.Box; import com.jme3.system.TestUtil; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; @@ -188,9 +188,9 @@ public void testNoSortByParam() { testSort(sameMat1, sameMat2); } - private Texture createTexture(String name) { + private GlTexture createTexture(String name) { ByteBuffer bb = BufferUtils.createByteBuffer(3); - Image image = new Image(Format.RGB8, 1, 1, bb, ColorSpace.sRGB); + GlImage image = new GlImage(Format.RGB8, 1, 1, bb, ColorSpace.sRGB); Texture2D texture = new Texture2D(image); texture.setName(name); return texture; @@ -202,13 +202,13 @@ public void testSortByTexture() { Material texture2Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); Material texture3Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - Texture tex1 = createTexture("A"); + GlTexture tex1 = createTexture("A"); tex1.getImage().setId(1); - Texture tex2 = createTexture("B"); + GlTexture tex2 = createTexture("B"); tex2.getImage().setId(2); - Texture tex3 = createTexture("C"); + GlTexture tex3 = createTexture("C"); tex3.getImage().setId(3); texture1Mat.setName("TexA"); @@ -261,11 +261,11 @@ public void testSortByAll() { Material matBase1 = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); Material matBase2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - Texture texBase = createTexture("BASE"); + GlTexture texBase = createTexture("BASE"); texBase.getImage().setId(1); - Texture tex1 = createTexture("1"); + GlTexture tex1 = createTexture("1"); tex1.getImage().setId(2); - Texture tex2 = createTexture("2"); + GlTexture tex2 = createTexture("2"); tex2.getImage().setId(3); matBase1.setName("BASE"); diff --git a/jme3-core/src/test/java/com/jme3/scene/plugins/OBJLoaderTest.java b/jme3-core/src/test/java/com/jme3/scene/plugins/OBJLoaderTest.java index 8fadbedae5..5e60407c15 100644 --- a/jme3-core/src/test/java/com/jme3/scene/plugins/OBJLoaderTest.java +++ b/jme3-core/src/test/java/com/jme3/scene/plugins/OBJLoaderTest.java @@ -39,7 +39,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.system.TestUtil; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import org.junit.Before; import org.junit.Test; @@ -100,7 +100,7 @@ private static String toDiffFriendlyString(String indent, Spatial spatial) { public static class PngLoaderStub implements AssetLoader { @Override public Object load(final AssetInfo assetInfo) { - return new Image(); + return new GlImage(); } } } \ No newline at end of file diff --git a/jme3-core/src/test/java/com/jme3/texture/TestIssue2250.java b/jme3-core/src/test/java/com/jme3/texture/TestIssue2250.java index 51d9e9e007..0fde872f09 100644 --- a/jme3-core/src/test/java/com/jme3/texture/TestIssue2250.java +++ b/jme3-core/src/test/java/com/jme3/texture/TestIssue2250.java @@ -54,8 +54,8 @@ public void testIssue2250WithData() { int height = 8; int numBytes = 4 * width * height; ByteBuffer data = BufferUtils.createByteBuffer(numBytes); - Image image1 = new Image( - Image.Format.RGBA8, width, height, data, ColorSpace.Linear); + GlImage image1 = new GlImage( + GlImage.Format.RGBA8, width, height, data, ColorSpace.Linear); image1.setMultiSamples(1); } @@ -71,7 +71,7 @@ public void testIssue2250WithMips() { int[] mipMapSizes = {256, 64, 16, 4}; ArrayList data = new ArrayList<>(); - Image image2 = new Image(Image.Format.RGBA8, width, height, depth, data, + GlImage image2 = new GlImage(GlImage.Format.RGBA8, width, height, depth, data, mipMapSizes, ColorSpace.Linear); image2.setMultiSamples(1); diff --git a/jme3-core/src/test/java/com/jme3/texture/TextureArrayTest.java b/jme3-core/src/test/java/com/jme3/texture/TextureArrayTest.java index bd861b9879..095d94e9cb 100644 --- a/jme3-core/src/test/java/com/jme3/texture/TextureArrayTest.java +++ b/jme3-core/src/test/java/com/jme3/texture/TextureArrayTest.java @@ -36,8 +36,8 @@ import com.jme3.asset.AssetManager; import com.jme3.asset.DesktopAssetManager; import com.jme3.export.binary.BinaryExporter; -import com.jme3.texture.Texture.WrapAxis; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture.WrapAxis; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; @@ -51,7 +51,7 @@ public class TextureArrayTest { @Test public void testExportWrapMode() { - List images = new ArrayList<>(); + List images = new ArrayList<>(); images.add(createImage()); images.add(createImage()); TextureArray tex3 = new TextureArray(images); @@ -62,12 +62,12 @@ public void testExportWrapMode() { assertEquals(tex3.getWrap(WrapAxis.T), tex4.getWrap(WrapAxis.T)); } - private Image createImage() { + private GlImage createImage() { int width = 8; int height = 8; int numBytes = 4 * width * height; ByteBuffer data = BufferUtils.createByteBuffer(numBytes); - return new Image(Image.Format.RGBA8, width, height, data, ColorSpace.Linear); + return new GlImage(GlImage.Format.RGBA8, width, height, data, ColorSpace.Linear); } } diff --git a/jme3-core/src/tools/java/jme3tools/optimize/GeometryBatchFactory.java b/jme3-core/src/tools/java/jme3tools/optimize/GeometryBatchFactory.java index 98ccf9c35b..d6d83d27cb 100644 --- a/jme3-core/src/tools/java/jme3tools/optimize/GeometryBatchFactory.java +++ b/jme3-core/src/tools/java/jme3tools/optimize/GeometryBatchFactory.java @@ -5,7 +5,7 @@ import com.jme3.math.Transform; import com.jme3.math.Vector3f; import com.jme3.scene.*; -import com.jme3.scene.Mesh.Mode; +import com.jme3.scene.GlMesh.Mode; import com.jme3.scene.VertexBuffer.Format; import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Usage; diff --git a/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java b/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java index 9447b2d956..7b7cf956f7 100644 --- a/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java +++ b/jme3-core/src/tools/java/jme3tools/optimize/TextureAtlas.java @@ -41,9 +41,9 @@ import com.jme3.scene.Spatial; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; @@ -143,9 +143,9 @@ public TextureAtlas(int width, int height) { * @return false if the atlas is full. */ public boolean addGeometry(Geometry geometry) { - Texture diffuse = getMaterialTexture(geometry, "DiffuseMap"); - Texture normal = getMaterialTexture(geometry, "NormalMap"); - Texture specular = getMaterialTexture(geometry, "SpecularMap"); + GlTexture diffuse = getMaterialTexture(geometry, "DiffuseMap"); + GlTexture normal = getMaterialTexture(geometry, "NormalMap"); + GlTexture specular = getMaterialTexture(geometry, "SpecularMap"); if (diffuse == null) { diffuse = getMaterialTexture(geometry, "ColorMap"); @@ -173,7 +173,7 @@ public boolean addGeometry(Geometry geometry) { * @param mapName A freely chosen map name that can be later retrieved as a Texture. The first map name supplied will be the master map. * @return false if the atlas is full. */ - public boolean addTexture(Texture texture, String mapName) { + public boolean addTexture(GlTexture texture, String mapName) { if (texture == null) { throw new IllegalStateException("Texture cannot be null!"); } @@ -191,7 +191,7 @@ public boolean addTexture(Texture texture, String mapName) { * @param mapName A freely chosen map name that can be later retrieved as a Texture. * @param masterTexture The master texture for determining the location, it has to exist in tha master map. */ - public void addTexture(Texture texture, String mapName, Texture masterTexture) { + public void addTexture(GlTexture texture, String mapName, GlTexture masterTexture) { String sourceTextureName = textureName(masterTexture); if (sourceTextureName == null) { throw new IllegalStateException("Supplied master map texture has no asset key name!"); @@ -206,7 +206,7 @@ public void addTexture(Texture texture, String mapName, Texture masterTexture) { * @param mapName A freely chosen map name that can be later retrieved as a Texture. * @param sourceTextureName Name of the master map used for the location. */ - public void addTexture(Texture texture, String mapName, String sourceTextureName) { + public void addTexture(GlTexture texture, String mapName, String sourceTextureName) { if (texture == null) { throw new IllegalStateException("Texture cannot be null!"); } @@ -218,7 +218,7 @@ public void addTexture(Texture texture, String mapName, String sourceTextureName } } - private String textureName(Texture texture) { + private String textureName(GlTexture texture) { if (texture == null) { return null; } @@ -230,7 +230,7 @@ private String textureName(Texture texture) { } } - private boolean addImage(Image image, String name, String mapName, String sourceTextureName) { + private boolean addImage(GlImage image, String name, String mapName, String sourceTextureName) { if (rootMapName == null) { rootMapName = mapName; } @@ -270,7 +270,7 @@ private boolean addImage(Image image, String name, String mapName, String source return true; } - private void drawImage(Image source, int x, int y, String mapName) { + private void drawImage(GlImage source, int x, int y, String mapName) { if (images == null) { images = new HashMap(); } @@ -286,41 +286,41 @@ private void drawImage(Image source, int x, int y, String mapName) { ByteBuffer sourceData = source.getData(0); int height = source.getHeight(); int width = source.getWidth(); - Image newImage = null; + GlImage newImage = null; for (int yPos = 0; yPos < height; yPos++) { for (int xPos = 0; xPos < width; xPos++) { int i = ((xPos + x) + (yPos + y) * atlasWidth) * 4; - if (source.getFormat() == Format.ABGR8) { + if (source.getGlFormat() == Format.ABGR8) { int j = (xPos + yPos * width) * 4; image[i] = sourceData.get(j); //a image[i + 1] = sourceData.get(j + 1); //b image[i + 2] = sourceData.get(j + 2); //g image[i + 3] = sourceData.get(j + 3); //r - } else if (source.getFormat() == Format.BGR8) { + } else if (source.getGlFormat() == Format.BGR8) { int j = (xPos + yPos * width) * 3; image[i] = 1; //a image[i + 1] = sourceData.get(j); //b image[i + 2] = sourceData.get(j + 1); //g image[i + 3] = sourceData.get(j + 2); //r - } else if (source.getFormat() == Format.RGB8) { + } else if (source.getGlFormat() == Format.RGB8) { int j = (xPos + yPos * width) * 3; image[i] = 1; //a image[i + 1] = sourceData.get(j + 2); //b image[i + 2] = sourceData.get(j + 1); //g image[i + 3] = sourceData.get(j); //r - } else if (source.getFormat() == Format.RGBA8) { + } else if (source.getGlFormat() == Format.RGBA8) { int j = (xPos + yPos * width) * 4; image[i] = sourceData.get(j + 3); //a image[i + 1] = sourceData.get(j + 2); //b image[i + 2] = sourceData.get(j + 1); //g image[i + 3] = sourceData.get(j); //r - } else if (source.getFormat() == Format.Luminance8) { + } else if (source.getGlFormat() == Format.Luminance8) { int j = (xPos + yPos * width) * 1; image[i] = 1; //a image[i + 1] = sourceData.get(j); //b image[i + 2] = sourceData.get(j); //g image[i + 3] = sourceData.get(j); //r - } else if (source.getFormat() == Format.Luminance8Alpha8) { + } else if (source.getGlFormat() == Format.Luminance8Alpha8) { int j = (xPos + yPos * width) * 2; image[i] = sourceData.get(j + 1); //a image[i + 1] = sourceData.get(j); //b @@ -339,10 +339,10 @@ private void drawImage(Image source, int x, int y, String mapName) { image[i + 2] = sourceData.get(j + 2); //g image[i + 3] = sourceData.get(j + 3); //r }else{ - throw new UnsupportedOperationException("Cannot draw or convert textures with format " + source.getFormat()); + throw new UnsupportedOperationException("Cannot draw or convert textures with format " + source.getGlFormat()); } } else { - throw new UnsupportedOperationException("Cannot draw textures with format " + source.getFormat()); + throw new UnsupportedOperationException("Cannot draw textures with format " + source.getGlFormat()); } } } @@ -350,15 +350,15 @@ private void drawImage(Image source, int x, int y, String mapName) { } @SuppressWarnings("unchecked") - private Image convertImageToAwt(Image source) { + private GlImage convertImageToAwt(GlImage source) { //use awt dependent classes without actual dependency via reflection try { Class clazz = Class.forName("jme3tools.converters.ImageToAwt"); if (clazz == null) { return null; } - Image newImage = new Image(format, source.getWidth(), source.getHeight(), BufferUtils.createByteBuffer(source.getWidth() * source.getHeight() * 4), null, ColorSpace.Linear); - clazz.getMethod("convert", Image.class, Image.class).invoke(clazz.getDeclaredConstructor().newInstance(), source, newImage); + GlImage newImage = new GlImage(format, source.getWidth(), source.getHeight(), BufferUtils.createByteBuffer(source.getWidth() * source.getHeight() * 4), null, ColorSpace.Linear); + clazz.getMethod("convert", GlImage.class, GlImage.class).invoke(clazz.getDeclaredConstructor().newInstance(), source, newImage); return newImage; } catch (InstantiationException | IllegalAccessException @@ -376,7 +376,7 @@ private Image convertImageToAwt(Image source) { * @param texture The texture to retrieve the TextureAtlasTile for. * @return the atlas tile */ - public TextureAtlasTile getAtlasTile(Texture texture) { + public TextureAtlasTile getAtlasTile(GlTexture texture) { String sourceTextureName = textureName(texture); if (sourceTextureName != null) { return getAtlasTile(sourceTextureName); @@ -399,17 +399,17 @@ private TextureAtlasTile getAtlasTile(String assetName) { * @param mapName the desired name * @return the atlas texture */ - public Texture getAtlasTexture(String mapName) { + public GlTexture getAtlasTexture(String mapName) { if (images == null) { return null; } byte[] image = images.get(mapName); if (image != null) { //TODO check if color space shouldn't be sRGB - Texture2D tex = new Texture2D(new Image(format, atlasWidth, atlasHeight, BufferUtils.createByteBuffer(image), null, ColorSpace.Linear)); - tex.setMagFilter(Texture.MagFilter.Bilinear); - tex.setMinFilter(Texture.MinFilter.BilinearNearestMipMap); - tex.setWrap(Texture.WrapMode.EdgeClamp); + Texture2D tex = new Texture2D(new GlImage(format, atlasWidth, atlasHeight, BufferUtils.createByteBuffer(image), null, ColorSpace.Linear)); + tex.setMagFilter(GlTexture.MagFilter.Bilinear); + tex.setMinFilter(GlTexture.MinFilter.BilinearNearestMipMap); + tex.setWrap(GlTexture.WrapMode.EdgeClamp); return tex; } return null; @@ -444,7 +444,7 @@ public boolean applyCoords(Geometry geom, int offset, Mesh outMesh) { throw new IllegalStateException("Geometry mesh has no texture coordinate buffer."); } - Texture tex = getMaterialTexture(geom, "DiffuseMap"); + GlTexture tex = getMaterialTexture(geom, "DiffuseMap"); if (tex == null) { tex = getMaterialTexture(geom, "ColorMap"); @@ -507,9 +507,9 @@ public static Geometry makeAtlasBatch(Spatial spat, AssetManager mgr, int atlasS geom.setMesh(mesh); Material mat = new Material(mgr, "Common/MatDefs/Light/Lighting.j3md"); - Texture diffuseMap = atlas.getAtlasTexture("DiffuseMap"); - Texture normalMap = atlas.getAtlasTexture("NormalMap"); - Texture specularMap = atlas.getAtlasTexture("SpecularMap"); + GlTexture diffuseMap = atlas.getAtlasTexture("DiffuseMap"); + GlTexture normalMap = atlas.getAtlasTexture("NormalMap"); + GlTexture specularMap = atlas.getAtlasTexture("SpecularMap"); if (diffuseMap != null) { mat.setTexture("DiffuseMap", diffuseMap); } @@ -547,13 +547,13 @@ private static void applyAtlasCoords(List geometries, Mesh outMesh, Te } } - private static Texture getMaterialTexture(Geometry geometry, String mapName) { + private static GlTexture getMaterialTexture(Geometry geometry, String mapName) { Material mat = geometry.getMaterial(); if (mat == null || mat.getParam(mapName) == null || !(mat.getParam(mapName) instanceof MatParamTexture)) { return null; } MatParamTexture param = (MatParamTexture) mat.getParam(mapName); - Texture texture = param.getTextureValue(); + GlTexture texture = param.getTextureValue(); if (texture == null) { return null; } @@ -581,7 +581,7 @@ public boolean isLeaf() { } // Algorithm from http://www.blackpawn.com/texts/lightmaps/ - public Node insert(Image image) { + public Node insert(GlImage image) { if (!isLeaf()) { Node newNode = child[0].insert(image); diff --git a/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java b/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java index 7e1d55b3e3..0824f2d7a7 100644 --- a/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java +++ b/jme3-desktop/src/main/java/com/jme3/app/state/VideoRecorderAppState.java @@ -41,7 +41,7 @@ import com.jme3.renderer.queue.RenderQueue; import com.jme3.system.Timer; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.util.BufferUtils; import com.jme3.util.Screenshots; import java.awt.image.BufferedImage; @@ -231,7 +231,7 @@ public void addImage(Renderer renderer, FrameBuffer out) { final WorkItem item = freeItems.take(); usedItems.add(item); item.buffer.clear(); - renderer.readFrameBufferWithFormat(out, item.buffer, Image.Format.BGRA8); + renderer.readFrameBufferWithFormat(out, item.buffer, GlImage.Format.BGRA8); executor.submit(new Callable() { @Override diff --git a/jme3-desktop/src/main/java/com/jme3/system/AWTComponentRenderer.java b/jme3-desktop/src/main/java/com/jme3/system/AWTComponentRenderer.java index bfb0e85e31..2b61aedd91 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/AWTComponentRenderer.java +++ b/jme3-desktop/src/main/java/com/jme3/system/AWTComponentRenderer.java @@ -51,7 +51,7 @@ import com.jme3.renderer.Renderer; import com.jme3.system.AWTFrameProcessor.TransferMode; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.util.BufferUtils; @@ -186,8 +186,8 @@ public AWTComponentRenderer(Component destination, TransferMode transferMode, Fr this.frameBuffer = frameBuffer; } else { this.frameBuffer = new FrameBuffer(width, height, 1); - this.frameBuffer.setDepthBuffer(Image.Format.Depth); - this.frameBuffer.setColorBuffer(Image.Format.RGBA8); + this.frameBuffer.setDepthBuffer(GlImage.Format.Depth); + this.frameBuffer.setColorBuffer(GlImage.Format.RGBA8); this.frameBuffer.setSrgb(true); } @@ -270,7 +270,7 @@ public void copyFrameBufferToImage(RenderManager renderManager) { frameByteBuffer.clear(); final Renderer renderer = renderManager.getRenderer(); - renderer.readFrameBufferWithFormat(frameBuffer, frameByteBuffer, Image.Format.RGBA8); + renderer.readFrameBufferWithFormat(frameBuffer, frameByteBuffer, GlImage.Format.RGBA8); } finally { if (!frameState.compareAndSet(RUNNING_STATE, WAITING_STATE)) { diff --git a/jme3-desktop/src/main/java/com/jme3/system/AWTFrameProcessor.java b/jme3-desktop/src/main/java/com/jme3/system/AWTFrameProcessor.java index 111e856973..b0fda11ed0 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/AWTFrameProcessor.java +++ b/jme3-desktop/src/main/java/com/jme3/system/AWTFrameProcessor.java @@ -49,7 +49,7 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; /** * A frame processor that enables to render JMonkey frame buffer onto an AWT component. @@ -620,8 +620,8 @@ protected void reshapeCurrentViewPort(int width, int height) { if (found) { FrameBuffer frameBuffer = new FrameBuffer(width, height, 1); - frameBuffer.setDepthBuffer(Image.Format.Depth); - frameBuffer.setColorBuffer(Image.Format.RGBA8); + frameBuffer.setDepthBuffer(GlImage.Format.Depth); + frameBuffer.setColorBuffer(GlImage.Format.RGBA8); frameBuffer.setSrgb(true); viewPort.setOutputFrameBuffer(frameBuffer); diff --git a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java index 81c197a3c5..2c28833e0e 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java +++ b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java @@ -37,7 +37,7 @@ import com.jme3.audio.openal.ALC; import com.jme3.audio.openal.EFX; import com.jme3.system.JmeContext.Type; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.image.ColorSpace; import com.jme3.util.res.Resources; @@ -102,7 +102,7 @@ private static BufferedImage ensureOpaque(BufferedImage original) { @Override public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException { - BufferedImage awtImage = ImageToAwt.convert(new Image(Image.Format.RGBA8, width, height, imageData.duplicate(), ColorSpace.Linear), false, true, 0); + BufferedImage awtImage = ImageToAwt.convert(new GlImage(GlImage.Format.RGBA8, width, height, imageData.duplicate(), ColorSpace.Linear), false, true, 0); awtImage = verticalFlip(awtImage); ImageWriter writer = ImageIO.getImageWritersByFormatName(format).next(); diff --git a/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java b/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java index a234775bdb..0d874ea5db 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java +++ b/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanel.java @@ -37,6 +37,7 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.texture.FrameBuffer; +import com.jme3.texture.GlImage; import com.jme3.util.BufferUtils; import com.jme3.util.Screenshots; import java.awt.*; @@ -243,8 +244,8 @@ private void reshapeInThread(int width, int height) { } fb = new FrameBuffer(width, height, 1); - fb.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(com.jme3.texture.Image.Format.Depth)); - fb.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(com.jme3.texture.Image.Format.RGB8)); + fb.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(GlImage.Format.Depth)); + fb.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(GlImage.Format.RGB8)); fb.setSrgb(srgb); if (attachAsMain) { diff --git a/jme3-desktop/src/main/java/com/jme3/texture/plugins/AWTLoader.java b/jme3-desktop/src/main/java/com/jme3/texture/plugins/AWTLoader.java index 926e7305af..fadd628fef 100644 --- a/jme3-desktop/src/main/java/com/jme3/texture/plugins/AWTLoader.java +++ b/jme3-desktop/src/main/java/com/jme3/texture/plugins/AWTLoader.java @@ -35,8 +35,8 @@ import com.jme3.asset.AssetLoadException; import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import com.jme3.util.BufferUtils; import java.awt.Transparency; import java.awt.color.ColorSpace; @@ -101,7 +101,7 @@ private void flipImage(short[] img, int width, int height, int bpp){ } } - public Image load(BufferedImage img, boolean flipY){ + public GlImage load(BufferedImage img, boolean flipY){ int width = img.getWidth(); int height = img.getHeight(); @@ -113,7 +113,7 @@ public Image load(BufferedImage img, boolean flipY){ ByteBuffer data1 = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*4); data1.put(dataBuf1); - return new Image(Format.ABGR8, width, height, data1, null, com.jme3.texture.image.ColorSpace.sRGB); + return new GlImage(Format.ABGR8, width, height, data1, null, com.jme3.texture.image.ColorSpace.sRGB); case BufferedImage.TYPE_3BYTE_BGR: // most common in JPEG images byte[] dataBuf2 = (byte[]) extractImageData(img); if (flipY) @@ -121,14 +121,14 @@ public Image load(BufferedImage img, boolean flipY){ ByteBuffer data2 = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*3); data2.put(dataBuf2); - return new Image(Format.BGR8, width, height, data2, null, com.jme3.texture.image.ColorSpace.sRGB); + return new GlImage(Format.BGR8, width, height, data2, null, com.jme3.texture.image.ColorSpace.sRGB); case BufferedImage.TYPE_BYTE_GRAY: // grayscale fonts byte[] dataBuf3 = (byte[]) extractImageData(img); if (flipY) flipImage(dataBuf3, width, height, 8); ByteBuffer data3 = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()); data3.put(dataBuf3); - return new Image(Format.Luminance8, width, height, data3, null, com.jme3.texture.image.ColorSpace.sRGB); + return new GlImage(Format.Luminance8, width, height, data3, null, com.jme3.texture.image.ColorSpace.sRGB); default: break; } @@ -151,7 +151,7 @@ public Image load(BufferedImage img, boolean flipY){ } } data.flip(); - return new Image(Format.RGB8, width, height, data, null, com.jme3.texture.image.ColorSpace.sRGB); + return new GlImage(Format.RGB8, width, height, data, null, com.jme3.texture.image.ColorSpace.sRGB); }else{ ByteBuffer data = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*4); // alpha @@ -171,11 +171,11 @@ public Image load(BufferedImage img, boolean flipY){ } } data.flip(); - return new Image(Format.RGBA8, width, height, data, null, com.jme3.texture.image.ColorSpace.sRGB); + return new GlImage(Format.RGBA8, width, height, data, null, com.jme3.texture.image.ColorSpace.sRGB); } } - public Image load(InputStream in, boolean flipY) throws IOException{ + public GlImage load(InputStream in, boolean flipY) throws IOException{ ImageIO.setUseCache(false); BufferedImage img = ImageIO.read(in); if (img == null){ @@ -190,7 +190,7 @@ public Object load(AssetInfo info) throws IOException { boolean flip = ((TextureKey) info.getKey()).isFlipY(); try (InputStream in = info.openStream(); BufferedInputStream bin = new BufferedInputStream(in)) { - Image img = load(bin, flip); + GlImage img = load(bin, flip); if (img == null){ throw new AssetLoadException("The given image cannot be loaded " + info.getKey()); } diff --git a/jme3-desktop/src/main/java/jme3tools/converters/ImageToAwt.java b/jme3-desktop/src/main/java/jme3tools/converters/ImageToAwt.java index 82f03a410d..ad556493f9 100644 --- a/jme3-desktop/src/main/java/jme3tools/converters/ImageToAwt.java +++ b/jme3-desktop/src/main/java/jme3tools/converters/ImageToAwt.java @@ -31,8 +31,8 @@ */ package jme3tools.converters; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.plugins.AWTLoader; import com.jme3.util.BufferUtils; import java.awt.Transparency; @@ -279,8 +279,8 @@ public static void convert(BufferedImage image, Format format, ByteBuffer buf) { private static final double LOG2 = Math.log(2); - public static void createData(Image image, boolean mipmaps){ - int bpp = image.getFormat().getBitsPerPixel(); + public static void createData(GlImage image, boolean mipmaps){ + int bpp = image.getGlFormat().getBitsPerPixel(); int w = image.getWidth(); int h = image.getHeight(); if (!mipmaps){ @@ -309,9 +309,9 @@ public static void createData(Image image, boolean mipmaps){ * @param input the input image (not null, unaffected) * @param output the output image (not null, modified) */ - public static void convert(Image input, Image output){ - DecodeParams inParams = params.get(input.getFormat()); - DecodeParams outParams = params.get(output.getFormat()); + public static void convert(GlImage input, GlImage output){ + DecodeParams inParams = params.get(input.getGlFormat()); + DecodeParams outParams = params.get(output.getGlFormat()); if (inParams == null || outParams == null) throw new UnsupportedOperationException(); @@ -375,9 +375,9 @@ public static void convert(Image input, Image output){ } } - public static BufferedImage convert(Image image, boolean do16bit, boolean fullAlpha, int mipLevel){ - Format format = image.getFormat(); - DecodeParams p = params.get(image.getFormat()); + public static BufferedImage convert(GlImage image, boolean do16bit, boolean fullAlpha, int mipLevel){ + Format format = image.getGlFormat(); + DecodeParams p = params.get(image.getGlFormat()); if (p == null) throw new UnsupportedOperationException(); diff --git a/jme3-desktop/src/main/java/jme3tools/converters/MipMapGenerator.java b/jme3-desktop/src/main/java/jme3tools/converters/MipMapGenerator.java index 24378647e6..1f6abe9c0f 100644 --- a/jme3-desktop/src/main/java/jme3tools/converters/MipMapGenerator.java +++ b/jme3-desktop/src/main/java/jme3tools/converters/MipMapGenerator.java @@ -32,8 +32,8 @@ package jme3tools.converters; import com.jme3.math.FastMath; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.plugins.AWTLoader; import com.jme3.util.BufferUtils; import java.awt.Graphics2D; @@ -64,7 +64,7 @@ private static BufferedImage scaleDown(BufferedImage sourceImage, int targetWidt return targetImage; } - public static void resizeToPowerOf2(Image image){ + public static void resizeToPowerOf2(GlImage image){ BufferedImage original = ImageToAwt.convert(image, false, true, 0); int potWidth = FastMath.nearestPowerOfTwo(image.getWidth()); int potHeight = FastMath.nearestPowerOfTwo(image.getHeight()); @@ -73,17 +73,17 @@ public static void resizeToPowerOf2(Image image){ BufferedImage scaled = scaleDown(original, potSize, potSize); AWTLoader loader = new AWTLoader(); - Image output = loader.load(scaled, false); + GlImage output = loader.load(scaled, false); image.setWidth(potSize); image.setHeight(potSize); image.setDepth(0); image.setData(output.getData(0)); - image.setFormat(output.getFormat()); + image.setFormat(output.getGlFormat()); image.setMipMapSizes(null); } - public static void generateMipMaps(Image image){ + public static void generateMipMaps(GlImage image){ BufferedImage original = ImageToAwt.convert(image, false, true, 0); int width = original.getWidth(); int height = original.getHeight(); @@ -96,8 +96,8 @@ public static void generateMipMaps(Image image){ Format format = null; while (height >= 1 || width >= 1){ - Image converted = loader.load(current, false); - format = converted.getFormat(); + GlImage converted = loader.load(current, false); + format = converted.getGlFormat(); output.add(converted.getData(0)); totalSize += converted.getData(0).capacity(); diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/BloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/BloomFilter.java index 1ad0a967c8..5103e20817 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/BloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/BloomFilter.java @@ -43,7 +43,7 @@ import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import java.io.IOException; import java.util.ArrayList; diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/CartoonEdgeFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/CartoonEdgeFilter.java index ab04279633..daaa8be176 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/CartoonEdgeFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/CartoonEdgeFilter.java @@ -45,7 +45,7 @@ import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; /** * Applies a cartoon-style edge detection filter to all objects in the scene. diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java index 3ccbf03ff9..08e1a68edb 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/SoftBloomFilter.java @@ -43,8 +43,8 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import java.io.IOException; import java.util.logging.Logger; import java.util.logging.Level; @@ -77,7 +77,7 @@ public class SoftBloomFilter extends Filter { private int height; private Pass[] downsamplingPasses; private Pass[] upsamplingPasses; - private final Image.Format format = Image.Format.RGBA16F; + private final GlImage.Format format = GlImage.Format.RGBA16F; private boolean initialized = false; private int numSamplingPasses = 5; private float glowFactor = 0.05f; @@ -120,7 +120,7 @@ public void beforeRender() { downsampleMat.setVector2("TexelSize", initTexelSize); } }; - initialPass.init(renderer, w, h, format, Image.Format.Depth, 1, downsampleMat); + initialPass.init(renderer, w, h, format, GlImage.Format.Depth, 1, downsampleMat); postRenderPasses.add(initialPass); downsamplingPasses[0] = initialPass; for (int i = 1; i < downsamplingPasses.length; i++) { @@ -134,9 +134,9 @@ public void beforeRender() { downsampleMat.setVector2("TexelSize", texelSize); } }; - pass.init(renderer, w, h, format, Image.Format.Depth, 1, downsampleMat); + pass.init(renderer, w, h, format, GlImage.Format.Depth, 1, downsampleMat); if (bilinearFiltering) { - pass.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + pass.getRenderedTexture().setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); } postRenderPasses.add(pass); downsamplingPasses[i] = pass; @@ -160,9 +160,9 @@ public void beforeRender() { upsampleMat.setVector2("TexelSize", texelSize); } }; - pass.init(renderer, w, h, format, Image.Format.Depth, 1, upsampleMat); + pass.init(renderer, w, h, format, GlImage.Format.Depth, 1, upsampleMat); if (bilinearFiltering) { - pass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); + pass.getRenderedTexture().setMagFilter(GlTexture.MagFilter.Bilinear); } postRenderPasses.add(pass); upsamplingPasses[i] = pass; @@ -249,16 +249,16 @@ public void setBilinearFiltering(boolean bilinearFiltering) { if (initialized) { for (Pass p : downsamplingPasses) { if (this.bilinearFiltering) { - p.getRenderedTexture().setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + p.getRenderedTexture().setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); } else { - p.getRenderedTexture().setMinFilter(Texture.MinFilter.NearestNoMipMaps); + p.getRenderedTexture().setMinFilter(GlTexture.MinFilter.NearestNoMipMaps); } } for (Pass p : upsamplingPasses) { if (this.bilinearFiltering) { - p.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear); + p.getRenderedTexture().setMagFilter(GlTexture.MagFilter.Bilinear); } else { - p.getRenderedTexture().setMagFilter(Texture.MagFilter.Nearest); + p.getRenderedTexture().setMagFilter(GlTexture.MagFilter.Nearest); } } } diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/TranslucentBucketFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/TranslucentBucketFilter.java index 1519dec4cd..9863444c50 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/TranslucentBucketFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/TranslucentBucketFilter.java @@ -43,7 +43,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import java.util.logging.Level; import java.util.logging.Logger; @@ -58,7 +58,7 @@ public final class TranslucentBucketFilter extends Filter { private final static Logger logger = Logger.getLogger(TranslucentBucketFilter.class.getName()); private RenderManager renderManager; private boolean enabledSoftParticles = false; - private Texture depthTexture; + private GlTexture depthTexture; private ViewPort viewPort; public TranslucentBucketFilter() { @@ -99,7 +99,7 @@ private void initSoftParticles(ViewPort vp, boolean enabledSP) { } @Override - protected void setDepthTexture(Texture depthTexture) { + protected void setDepthTexture(GlTexture depthTexture) { this.depthTexture = depthTexture; if (enabledSoftParticles && depthTexture != null) { initSoftParticles(viewPort, true); diff --git a/jme3-effects/src/main/java/com/jme3/post/ssao/SSAOFilter.java b/jme3-effects/src/main/java/com/jme3/post/ssao/SSAOFilter.java index 58a12570d0..4adb9ac11c 100644 --- a/jme3-effects/src/main/java/com/jme3/post/ssao/SSAOFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/ssao/SSAOFilter.java @@ -45,8 +45,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.shader.VarType; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import java.io.IOException; import java.util.ArrayList; @@ -146,8 +146,8 @@ protected void initFilter(AssetManager assetManager, RenderManager renderManager //ssao Pass ssaoMat = new Material(assetManager, "Common/MatDefs/SSAO/ssao.j3md"); ssaoMat.setTexture("Normals", normalPass.getRenderedTexture()); - Texture random = assetManager.loadTexture("Common/MatDefs/SSAO/Textures/random.png"); - random.setWrap(Texture.WrapMode.Repeat); + GlTexture random = assetManager.loadTexture("Common/MatDefs/SSAO/Textures/random.png"); + random.setWrap(GlTexture.WrapMode.Repeat); ssaoMat.setTexture("RandomMap", random); Pass ssaoPass = new Pass("SSAO pass") { diff --git a/jme3-effects/src/main/java/com/jme3/water/SimpleWaterProcessor.java b/jme3-effects/src/main/java/com/jme3/water/SimpleWaterProcessor.java index 3bc5e7ca79..e1763daa49 100644 --- a/jme3-effects/src/main/java/com/jme3/water/SimpleWaterProcessor.java +++ b/jme3-effects/src/main/java/com/jme3/water/SimpleWaterProcessor.java @@ -43,8 +43,8 @@ import com.jme3.scene.shape.Quad; import com.jme3.texture.*; import com.jme3.texture.FrameBuffer.FrameBufferTarget; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.ui.Picture; /** @@ -255,11 +255,11 @@ protected void createTextures() { reflectionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8); refractionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8); - reflectionTexture.setMinFilter(Texture.MinFilter.Trilinear); - reflectionTexture.setMagFilter(Texture.MagFilter.Bilinear); + reflectionTexture.setMinFilter(GlTexture.MinFilter.Trilinear); + reflectionTexture.setMagFilter(GlTexture.MagFilter.Bilinear); - refractionTexture.setMinFilter(Texture.MinFilter.Trilinear); - refractionTexture.setMagFilter(Texture.MagFilter.Bilinear); + refractionTexture.setMinFilter(GlTexture.MinFilter.Trilinear); + refractionTexture.setMagFilter(GlTexture.MagFilter.Bilinear); depthTexture = new Texture2D(renderWidth, renderHeight, Format.Depth); } diff --git a/jme3-effects/src/main/java/com/jme3/water/WaterFilter.java b/jme3-effects/src/main/java/com/jme3/water/WaterFilter.java index 0d84b23674..a264d4204e 100644 --- a/jme3-effects/src/main/java/com/jme3/water/WaterFilter.java +++ b/jme3-effects/src/main/java/com/jme3/water/WaterFilter.java @@ -49,8 +49,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.clone.Cloner; import com.jme3.util.clone.JmeCloneable; diff --git a/jme3-examples/build.gradle b/jme3-examples/build.gradle index 4f5d41b501..75d4e8c098 100644 --- a/jme3-examples/build.gradle +++ b/jme3-examples/build.gradle @@ -19,8 +19,8 @@ dependencies { implementation project(':jme3-effects') implementation project(':jme3-jbullet') implementation project(':jme3-jogg') - implementation project(':jme3-lwjgl') -// implementation project(':jme3-lwjgl3') +// implementation project(':jme3-lwjgl') + implementation project(':jme3-lwjgl3') implementation project(':jme3-networking') implementation project(':jme3-niftygui') implementation project(':jme3-plugins') diff --git a/jme3-examples/src/main/java/jme3test/app/TestUseAfterFree.java b/jme3-examples/src/main/java/jme3test/app/TestUseAfterFree.java index b241d78087..0406fa42c1 100644 --- a/jme3-examples/src/main/java/jme3test/app/TestUseAfterFree.java +++ b/jme3-examples/src/main/java/jme3test/app/TestUseAfterFree.java @@ -35,7 +35,7 @@ import com.jme3.material.Material; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.BufferUtils; /** @@ -49,7 +49,7 @@ public class TestUseAfterFree extends SimpleApplication { private float time = 0; private Material mat; - private Texture deletedTex; + private GlTexture deletedTex; public static void main(String[] args) { TestUseAfterFree app = new TestUseAfterFree(); diff --git a/jme3-examples/src/main/java/jme3test/asset/TestUrlLoading.java b/jme3-examples/src/main/java/jme3test/asset/TestUrlLoading.java index 563eb4c7c7..21982d5fc0 100644 --- a/jme3-examples/src/main/java/jme3test/asset/TestUrlLoading.java +++ b/jme3-examples/src/main/java/jme3test/asset/TestUrlLoading.java @@ -39,7 +39,7 @@ import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * Load an image and display it from the internet using the UrlLocator. @@ -64,7 +64,7 @@ public void simpleInitApp() { UrlLocator.class); TextureKey key = new TextureKey("mucha-window.png", false); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); + GlTexture tex = assetManager.loadTexture(key); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", tex); diff --git a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java index 5f0e603fb5..d823553ee6 100644 --- a/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java +++ b/jme3-examples/src/main/java/jme3test/batching/TestBatchNodeTower.java @@ -57,8 +57,8 @@ import com.jme3.shadow.EdgeFilteringMode; import com.jme3.system.AppSettings; import com.jme3.system.NanoTimer; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import jme3test.bullet.BombControl; /** @@ -208,19 +208,19 @@ public void initMaterial() { mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); + GlTexture tex = assetManager.loadTexture(key); mat.setTexture("ColorMap", tex); mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); key2.setGenerateMips(true); - Texture tex2 = assetManager.loadTexture(key2); + GlTexture tex2 = assetManager.loadTexture(key2); mat2.setTexture("ColorMap", tex2); mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); key3.setGenerateMips(true); - Texture tex3 = assetManager.loadTexture(key3); + GlTexture tex3 = assetManager.loadTexture(key3); tex3.setWrap(WrapMode.Repeat); mat3.setTexture("ColorMap", tex3); } diff --git a/jme3-examples/src/main/java/jme3test/bullet/PhysicsTestHelper.java b/jme3-examples/src/main/java/jme3test/bullet/PhysicsTestHelper.java index 59d02d64c8..7b9d44944e 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/PhysicsTestHelper.java +++ b/jme3-examples/src/main/java/jme3test/bullet/PhysicsTestHelper.java @@ -55,7 +55,7 @@ import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; import com.jme3.scene.shape.Sphere.TextureMode; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.BufferUtils; /** @@ -237,7 +237,7 @@ public void onAction(String name, boolean keyPressed, float tpf) { Material mat2 = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); key2.setGenerateMips(true); - Texture tex2 = app.getAssetManager().loadTexture(key2); + GlTexture tex2 = app.getAssetManager().loadTexture(key2); mat2.setTexture("ColorMap", tex2); if (name.equals("shoot") && !keyPressed) { Geometry bulletGeometry = new Geometry("bullet", bullet); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java b/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java index 8c1c712603..aa507c4d26 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestAttachDriver.java @@ -51,7 +51,7 @@ import com.jme3.scene.Node; import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Cylinder; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * Tests attaching/detaching nodes via joints @@ -107,8 +107,8 @@ public void setupFloor() { Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Interface/Logo/Monkey.jpg", true); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); - tex.setMinFilter(Texture.MinFilter.Trilinear); + GlTexture tex = assetManager.loadTexture(key); + tex.setMinFilter(GlTexture.MinFilter.Trilinear); mat.setTexture("ColorMap", tex); Box floor = new Box(100, 1f, 100); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java b/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java index 538ec8b31c..e6c120c186 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java @@ -61,7 +61,7 @@ import com.jme3.scene.Node; import com.jme3.scene.shape.Sphere; import com.jme3.scene.shape.Sphere.TextureMode; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * @author normenhansen @@ -218,7 +218,7 @@ private void initMaterial() { "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); key2.setGenerateMips(true); - Texture tex2 = assetManager.loadTexture(key2); + GlTexture tex2 = assetManager.loadTexture(key2); matBullet.setTexture("ColorMap", tex2); } diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java b/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java index a607878185..3e7a31c234 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestBrickTower.java @@ -49,8 +49,8 @@ import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; import com.jme3.scene.shape.Sphere.TextureMode; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; /** * @@ -177,19 +177,19 @@ public void initMaterial() { mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); + GlTexture tex = assetManager.loadTexture(key); mat.setTexture("ColorMap", tex); mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); key2.setGenerateMips(true); - Texture tex2 = assetManager.loadTexture(key2); + GlTexture tex2 = assetManager.loadTexture(key2); mat2.setTexture("ColorMap", tex2); mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); key3.setGenerateMips(true); - Texture tex3 = assetManager.loadTexture(key3); + GlTexture tex3 = assetManager.loadTexture(key3); tex3.setWrap(WrapMode.Repeat); mat3.setTexture("ColorMap", tex3); } diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java b/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java index d0cbdb2bba..eeb0fbd537 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestBrickWall.java @@ -52,8 +52,8 @@ import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; import com.jme3.scene.shape.Sphere.TextureMode; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; /** * @@ -161,19 +161,19 @@ public void initMaterial() { mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); + GlTexture tex = assetManager.loadTexture(key); mat.setTexture("ColorMap", tex); mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); key2.setGenerateMips(true); - Texture tex2 = assetManager.loadTexture(key2); + GlTexture tex2 = assetManager.loadTexture(key2); mat2.setTexture("ColorMap", tex2); mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); key3.setGenerateMips(true); - Texture tex3 = assetManager.loadTexture(key3); + GlTexture tex3 = assetManager.loadTexture(key3); tex3.setWrap(WrapMode.Repeat); mat3.setTexture("ColorMap", tex3); } diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestHoveringTank.java b/jme3-examples/src/main/java/jme3test/bullet/TestHoveringTank.java index 3127ec4a68..ec712e30f9 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestHoveringTank.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestHoveringTank.java @@ -57,8 +57,8 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; import java.util.ArrayList; @@ -255,24 +255,24 @@ private void createTerrain() { matRock.setBoolean("useTriPlanarMapping", false); matRock.setBoolean("WardIso", true); matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap", grass); matRock.setFloat("DiffuseMap_0_scale", 64); - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_1", dirt); matRock.setFloat("DiffuseMap_1_scale", 16); - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_2", rock); matRock.setFloat("DiffuseMap_2_scale", 128); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMap0.setWrap(WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMap1.setWrap(WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMap2.setWrap(WrapMode.Repeat); matRock.setTexture("NormalMap", normalMap0); matRock.setTexture("NormalMap_1", normalMap1); diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java index b457e3b15b..0a903c0c44 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java @@ -54,7 +54,7 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.shape.Box; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * @author normenhansen @@ -197,7 +197,7 @@ private void initWall(float bLength, float bWidth, float bHeight) { Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); + GlTexture tex = assetManager.loadTexture(key); mat2.setTexture("ColorMap", tex); float startpt = bLength / 4f; diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java index 61f08d25f2..5b2ffe6024 100644 --- a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java +++ b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java @@ -70,8 +70,8 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.SkyFactory; import java.util.ArrayList; @@ -243,24 +243,24 @@ private void createTerrain() { matRock.setBoolean("useTriPlanarMapping", false); matRock.setBoolean("WardIso", true); matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap", grass); matRock.setFloat("DiffuseMap_0_scale", 64); - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_1", dirt); matRock.setFloat("DiffuseMap_1_scale", 16); - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_2", rock); matRock.setFloat("DiffuseMap_2_scale", 128); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMap0.setWrap(WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMap1.setWrap(WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMap2.setWrap(WrapMode.Repeat); matRock.setTexture("NormalMap", normalMap0); matRock.setTexture("NormalMap_1", normalMap1); diff --git a/jme3-examples/src/main/java/jme3test/conversion/TestMipMapGen.java b/jme3-examples/src/main/java/jme3test/conversion/TestMipMapGen.java index 6110469ee0..cc8dbf0df5 100644 --- a/jme3-examples/src/main/java/jme3test/conversion/TestMipMapGen.java +++ b/jme3-examples/src/main/java/jme3test/conversion/TestMipMapGen.java @@ -37,8 +37,8 @@ import com.jme3.material.Material; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.util.MipMapGenerator; public class TestMipMapGen extends SimpleApplication { @@ -66,11 +66,11 @@ public void simpleInitApp() { Geometry quad1 = new Geometry("Textured Quad", quadMesh); Geometry quad2 = new Geometry("Textured Quad 2", quadMesh); - Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.png"); - tex.setMinFilter(Texture.MinFilter.Trilinear); + GlTexture tex = assetManager.loadTexture("Interface/Logo/Monkey.png"); + tex.setMinFilter(GlTexture.MinFilter.Trilinear); - Texture texCustomMip = tex.clone(); - Image imageCustomMip = texCustomMip.getImage().clone(); + GlTexture texCustomMip = tex.clone(); + GlImage imageCustomMip = texCustomMip.getImage().clone(); MipMapGenerator.generateMipMaps(imageCustomMip); texCustomMip.setImage(imageCustomMip); diff --git a/jme3-examples/src/main/java/jme3test/effect/TestEverything.java b/jme3-examples/src/main/java/jme3test/effect/TestEverything.java index bb5ab62a1a..98bc400680 100644 --- a/jme3-examples/src/main/java/jme3test/effect/TestEverything.java +++ b/jme3-examples/src/main/java/jme3test/effect/TestEverything.java @@ -46,7 +46,7 @@ import com.jme3.scene.Spatial.CullHint; import com.jme3.scene.shape.Box; import com.jme3.shadow.DirectionalLightShadowRenderer; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.SkyFactory; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; @@ -81,7 +81,7 @@ public void setupBasicShadow(){ } public void setupSkyBox(){ - Texture envMap; + GlTexture envMap; if (renderer.getCaps().contains(Caps.FloatTexture)){ envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.hdr"); }else{ diff --git a/jme3-examples/src/main/java/jme3test/effect/TestIssue1773.java b/jme3-examples/src/main/java/jme3test/effect/TestIssue1773.java index b466815dfb..ef5f1be8ad 100644 --- a/jme3-examples/src/main/java/jme3test/effect/TestIssue1773.java +++ b/jme3-examples/src/main/java/jme3test/effect/TestIssue1773.java @@ -62,7 +62,7 @@ import com.jme3.scene.shape.Torus; import com.jme3.shadow.DirectionalLightShadowFilter; import com.jme3.system.AppSettings; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.util.Arrays; /** @@ -249,8 +249,8 @@ private void setupGround() { quad.scaleTextureCoordinates(new Vector2f(2, 2)); Geometry floor = new Geometry("Floor", quad); Material mat = new Material(assetManager, Materials.LIGHTING); - Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); - tex.setWrap(Texture.WrapMode.Repeat); + GlTexture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + tex.setWrap(GlTexture.WrapMode.Repeat); mat.setTexture("DiffuseMap", tex); floor.setMaterial(mat); floor.rotate(-FastMath.HALF_PI, 0, 0); diff --git a/jme3-examples/src/main/java/jme3test/gui/TestBitmapFontLayout.java b/jme3-examples/src/main/java/jme3test/gui/TestBitmapFontLayout.java index 6d2ad6f37b..b7826e590a 100644 --- a/jme3-examples/src/main/java/jme3test/gui/TestBitmapFontLayout.java +++ b/jme3-examples/src/main/java/jme3test/gui/TestBitmapFontLayout.java @@ -61,8 +61,8 @@ import com.jme3.scene.*; import com.jme3.scene.debug.WireBox; import com.jme3.scene.shape.*; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.plugins.AWTLoader; @@ -109,7 +109,7 @@ public static Font loadTtf( String resource ) { } } - private Texture renderAwtFont( TestConfig test, int width, int height, BitmapFont bitmapFont ) { + private GlTexture renderAwtFont(TestConfig test, int width, int height, BitmapFont bitmapFont ) { BitmapCharacterSet charset = bitmapFont.getCharSet(); @@ -152,7 +152,7 @@ private Texture renderAwtFont( TestConfig test, int width, int height, BitmapFon g2.dispose(); - Image jmeImage = new AWTLoader().load(image, true); + GlImage jmeImage = new AWTLoader().load(image, true); return new Texture2D(jmeImage); } @@ -243,7 +243,7 @@ private Node createVisual( TestConfig test ) { int width = Math.round(x2 - Math.min(0, x1)); int height = Math.round(y2 - Math.min(0, y1)); - Texture awtText = renderAwtFont(test, width, height, bitmapFont); + GlTexture awtText = renderAwtFont(test, width, height, bitmapFont); Quad quad = new Quad(width, height); geom = new Geometry(test.name + " awt1", quad); geom.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); diff --git a/jme3-examples/src/main/java/jme3test/gui/TestSoftwareMouse.java b/jme3-examples/src/main/java/jme3test/gui/TestSoftwareMouse.java index e1baf0b5c7..e620766e76 100644 --- a/jme3-examples/src/main/java/jme3test/gui/TestSoftwareMouse.java +++ b/jme3-examples/src/main/java/jme3test/gui/TestSoftwareMouse.java @@ -38,7 +38,7 @@ import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.system.AppSettings; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; @@ -99,7 +99,7 @@ public void simpleInitApp() { flyCam.setEnabled(false); // inputManager.setCursorVisible(false); - Texture tex = assetManager.loadTexture("Interface/Logo/Cursor.png"); + GlTexture tex = assetManager.loadTexture("Interface/Logo/Cursor.png"); cursor = new Picture("cursor"); cursor.setTexture(assetManager, (Texture2D) tex, true); diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloMaterial.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloMaterial.java index a9e4b4f28a..6ad829dbb1 100644 --- a/jme3-examples/src/main/java/jme3test/helloworld/HelloMaterial.java +++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloMaterial.java @@ -42,7 +42,7 @@ import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; /** Sample 6 - how to give an object's surface a material and texture. @@ -62,7 +62,7 @@ public void simpleInitApp() { Geometry cube1Geo = new Geometry("My Textured Box", cube1Mesh); cube1Geo.setLocalTranslation(new Vector3f(-3f,1.1f,0f)); Material cube1Mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - Texture cube1Tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + GlTexture cube1Tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); cube1Mat.setTexture("ColorMap", cube1Tex); cube1Geo.setMaterial(cube1Mat); rootNode.attachChild(cube1Geo); diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloPhysics.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloPhysics.java index ec566e3909..e88f9fe7c3 100644 --- a/jme3-examples/src/main/java/jme3test/helloworld/HelloPhysics.java +++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloPhysics.java @@ -47,8 +47,8 @@ import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; import com.jme3.scene.shape.Sphere.TextureMode; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; /** * Example 12 - how to give objects physical properties, so they bounce and fall. @@ -132,19 +132,19 @@ public void initMaterials() { wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg"); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); + GlTexture tex = assetManager.loadTexture(key); wall_mat.setTexture("ColorMap", tex); stone_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG"); key2.setGenerateMips(true); - Texture tex2 = assetManager.loadTexture(key2); + GlTexture tex2 = assetManager.loadTexture(key2); stone_mat.setTexture("ColorMap", tex2); floor_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg"); key3.setGenerateMips(true); - Texture tex3 = assetManager.loadTexture(key3); + GlTexture tex3 = assetManager.loadTexture(key3); tex3.setWrap(WrapMode.Repeat); floor_mat.setTexture("ColorMap", tex3); } diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrain.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrain.java index f6032faf36..c14b6e18ab 100644 --- a/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrain.java +++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrain.java @@ -39,8 +39,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; public class HelloTerrain extends SimpleApplication { @@ -62,21 +62,21 @@ public void simpleInitApp() { "Textures/Terrain/splat/alphamap.png")); /* 1.2) Add GRASS texture into the red layer (Tex1). */ - Texture grass = assetManager.loadTexture( + GlTexture grass = assetManager.loadTexture( "Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); mat_terrain.setTexture("Tex1", grass); mat_terrain.setFloat("Tex1Scale", 64f); /* 1.3) Add DIRT texture into the green layer (Tex2) */ - Texture dirt = assetManager.loadTexture( + GlTexture dirt = assetManager.loadTexture( "Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); mat_terrain.setTexture("Tex2", dirt); mat_terrain.setFloat("Tex2Scale", 32f); /* 1.4) Add ROAD texture into the blue layer (Tex3) */ - Texture rock = assetManager.loadTexture( + GlTexture rock = assetManager.loadTexture( "Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); mat_terrain.setTexture("Tex3", rock); @@ -84,7 +84,7 @@ public void simpleInitApp() { /* 2.a Create a custom height map from an image */ AbstractHeightMap heightmap = null; - Texture heightMapImage = assetManager.loadTexture( + GlTexture heightMapImage = assetManager.loadTexture( "Textures/Terrain/splat/mountains512.png"); heightmap = new ImageBasedHeightMap(heightMapImage.getImage()); diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrainCollision.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrainCollision.java index 739a93ff76..ecdffc4718 100644 --- a/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrainCollision.java +++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloTerrainCollision.java @@ -47,8 +47,8 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import java.util.ArrayList; import java.util.List; @@ -92,21 +92,21 @@ public void simpleInitApp() { "Textures/Terrain/splat/alphamap.png")); /* 1.2) Add GRASS texture into the red layer (Tex1). */ - Texture grass = assetManager.loadTexture( + GlTexture grass = assetManager.loadTexture( "Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); mat_terrain.setTexture("Tex1", grass); mat_terrain.setFloat("Tex1Scale", 64f); /* 1.3) Add DIRT texture into the green layer (Tex2) */ - Texture dirt = assetManager.loadTexture( + GlTexture dirt = assetManager.loadTexture( "Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); mat_terrain.setTexture("Tex2", dirt); mat_terrain.setFloat("Tex2Scale", 32f); /* 1.4) Add ROAD texture into the blue layer (Tex3) */ - Texture rock = assetManager.loadTexture( + GlTexture rock = assetManager.loadTexture( "Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); mat_terrain.setTexture("Tex3", rock); @@ -114,7 +114,7 @@ public void simpleInitApp() { /* 2. Create the height map */ AbstractHeightMap heightmap = null; - Texture heightMapImage = assetManager.loadTexture( + GlTexture heightMapImage = assetManager.loadTexture( "Textures/Terrain/splat/mountains512.png"); heightmap = new ImageBasedHeightMap(heightMapImage.getImage()); heightmap.load(); diff --git a/jme3-examples/src/main/java/jme3test/light/TestConeVSFrustum.java b/jme3-examples/src/main/java/jme3test/light/TestConeVSFrustum.java index 0f2605839c..3985e23536 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestConeVSFrustum.java +++ b/jme3-examples/src/main/java/jme3test/light/TestConeVSFrustum.java @@ -55,7 +55,7 @@ import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Cylinder; import com.jme3.shadow.ShadowUtil; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.TempVars; public class TestConeVSFrustum extends SimpleApplication { @@ -221,7 +221,7 @@ public void onAction(String name, boolean isPressed, float tpf) { Box boxMesh = new Box(1f, 1f, 1f); Geometry boxGeo = new Geometry("A Textured Box", boxMesh); Material boxMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - Texture monkeyTex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + GlTexture monkeyTex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); boxMat.setTexture("ColorMap", monkeyTex); boxGeo.setMaterial(boxMat); System.err.println("light " + spotLight.getPosition()); diff --git a/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java b/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java index 0c6f437305..1e3e7acd37 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java +++ b/jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java @@ -54,8 +54,8 @@ import com.jme3.shadow.DirectionalLightShadowFilter; import com.jme3.shadow.DirectionalLightShadowRenderer; import com.jme3.shadow.EdgeFilteringMode; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; @@ -134,7 +134,7 @@ public void loadScene() { matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matGroundL.setTexture("DiffuseMap", grass); diff --git a/jme3-examples/src/main/java/jme3test/light/TestEnvironmentMapping.java b/jme3-examples/src/main/java/jme3test/light/TestEnvironmentMapping.java index 846acfce40..85acd18e2e 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestEnvironmentMapping.java +++ b/jme3-examples/src/main/java/jme3test/light/TestEnvironmentMapping.java @@ -42,7 +42,7 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.SkyFactory; /** @@ -62,8 +62,8 @@ public void simpleInitApp() { TextureKey key = new TextureKey("Textures/Sky/Bright/BrightSky.dds", true); key.setGenerateMips(true); - key.setTextureTypeHint(Texture.Type.CubeMap); - final Texture tex = assetManager.loadTexture(key); + key.setTextureTypeHint(GlTexture.Type.CubeMap); + final GlTexture tex = assetManager.loadTexture(key); for (Spatial geom : buggy.getChildren()) { if (geom instanceof Geometry) { diff --git a/jme3-examples/src/main/java/jme3test/light/TestShadowBug.java b/jme3-examples/src/main/java/jme3test/light/TestShadowBug.java index acf2d6df13..1dd4c94d61 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestShadowBug.java +++ b/jme3-examples/src/main/java/jme3test/light/TestShadowBug.java @@ -50,8 +50,8 @@ import com.jme3.shadow.EdgeFilteringMode; import com.jme3.shadow.PointLightShadowRenderer; import com.jme3.shadow.SpotLightShadowRenderer; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; public class TestShadowBug extends SimpleApplication { @@ -119,7 +119,7 @@ protected Geometry makeFloor() { Geometry floor = new Geometry("the Floor", box); floor.setLocalTranslation(200, -9, 200); Material matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matGroundL.setTexture("DiffuseMap", grass); floor.setMaterial(matGroundL); diff --git a/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java b/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java index ed53b0de35..d5ded001ac 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java +++ b/jme3-examples/src/main/java/jme3test/light/TestSpotLight.java @@ -42,7 +42,7 @@ import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Sphere; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; public class TestSpotLight extends SimpleApplication { diff --git a/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java index 11dd519ef3..0ce70de799 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/light/TestSpotLightShadows.java @@ -48,7 +48,7 @@ import com.jme3.shadow.EdgeFilteringMode; import com.jme3.shadow.SpotLightShadowFilter; import com.jme3.shadow.SpotLightShadowRenderer; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; public class TestSpotLightShadows extends SimpleApplication { diff --git a/jme3-examples/src/main/java/jme3test/light/TestSpotLightTerrain.java b/jme3-examples/src/main/java/jme3test/light/TestSpotLightTerrain.java index 9fa5a0ea36..754fa38bd0 100644 --- a/jme3-examples/src/main/java/jme3test/light/TestSpotLightTerrain.java +++ b/jme3-examples/src/main/java/jme3test/light/TestSpotLightTerrain.java @@ -46,8 +46,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.SkyFactory; /** @@ -112,45 +112,45 @@ private void makeTerrain() { matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png")); // HEIGHTMAP image (for the terrain heightmap) - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap", grass); matTerrain.setFloat("DiffuseMap_0_scale", grassScale); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_1", dirt); matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_2", rock); matTerrain.setFloat("DiffuseMap_2_scale", rockScale); // BRICK texture - Texture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); + GlTexture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); brick.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_3", brick); matTerrain.setFloat("DiffuseMap_3_scale", rockScale); // RIVER ROCK texture - Texture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"); + GlTexture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"); riverRock.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_4", riverRock); matTerrain.setFloat("DiffuseMap_4_scale", rockScale); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMap0.setWrap(WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMap1.setWrap(WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMap2.setWrap(WrapMode.Repeat); matTerrain.setTexture("NormalMap", normalMap0); matTerrain.setTexture("NormalMap_1", normalMap1); @@ -191,12 +191,12 @@ private void makeTerrain() { } private void createSky() { - Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); - Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); - Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); - Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); - Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); - Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); + GlTexture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); + GlTexture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); + GlTexture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); + GlTexture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); + GlTexture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); + GlTexture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down); rootNode.attachChild(sky); diff --git a/jme3-examples/src/main/java/jme3test/material/TestMaterialCompare.java b/jme3-examples/src/main/java/jme3test/material/TestMaterialCompare.java index a37855185c..895b75c123 100644 --- a/jme3-examples/src/main/java/jme3test/material/TestMaterialCompare.java +++ b/jme3-examples/src/main/java/jme3test/material/TestMaterialCompare.java @@ -37,7 +37,7 @@ import com.jme3.material.RenderState.BlendMode; import com.jme3.math.ColorRGBA; import com.jme3.system.JmeSystem; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; public class TestMaterialCompare { @@ -79,16 +79,16 @@ public static void main(String[] args) { System.out.println("TEXTURE KEYS ARE NOT EQUAL"); } - Texture tex1 = assetManager.loadTexture(tex1key); + GlTexture tex1 = assetManager.loadTexture(tex1key); mat4.setTexture("DiffuseMap", tex1); testEquality(mat4, mat5, true); // Change some stuff on the texture and compare, materials no longer equal - tex1.setWrap(Texture.WrapMode.MirroredRepeat); + tex1.setWrap(GlTexture.WrapMode.MirroredRepeat); testEquality(mat4, mat5, false); // Comparing different textures - Texture tex2 = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + GlTexture tex2 = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); mat4.setTexture("DiffuseMap", tex2); testEquality(mat4, mat5, false); diff --git a/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java b/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java index 592663efeb..261f1c1bb5 100644 --- a/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java +++ b/jme3-examples/src/main/java/jme3test/material/TestShaderNodes.java @@ -8,7 +8,7 @@ import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.shader.Shader; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.util.logging.Level; import java.util.logging.Logger; @@ -25,7 +25,7 @@ public void simpleInitApp() { Logger.getLogger("com.jme3").setLevel(Level.WARNING); Box boxShape1 = new Box(1f, 1f, 1f); Geometry cube_tex = new Geometry("A Textured Box", boxShape1); - Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + GlTexture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); Material mat = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md"); mat.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); diff --git a/jme3-examples/src/main/java/jme3test/model/shape/TestCylinder.java b/jme3-examples/src/main/java/jme3test/model/shape/TestCylinder.java index bec3847faa..29b0396800 100644 --- a/jme3-examples/src/main/java/jme3test/model/shape/TestCylinder.java +++ b/jme3-examples/src/main/java/jme3test/model/shape/TestCylinder.java @@ -37,7 +37,7 @@ import com.jme3.material.Material; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Cylinder; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; public class TestCylinder extends SimpleApplication { @@ -54,8 +54,8 @@ public void simpleInitApp() { Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); TextureKey key = new TextureKey("Interface/Logo/Monkey.jpg", true); key.setGenerateMips(true); - Texture tex = assetManager.loadTexture(key); - tex.setMinFilter(Texture.MinFilter.Trilinear); + GlTexture tex = assetManager.loadTexture(key); + tex.setMinFilter(GlTexture.MinFilter.Trilinear); mat.setTexture("ColorMap", tex); geom.setMaterial(mat); diff --git a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java index da428f5d5e..2da82578a3 100644 --- a/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java +++ b/jme3-examples/src/main/java/jme3test/niftygui/TestNiftyToMesh.java @@ -40,9 +40,9 @@ import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.texture.image.ColorSpace; diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index aaf4cc4d06..23421f2f02 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -41,6 +41,7 @@ import com.jme3.math.Vector2f; import com.jme3.opencl.*; import com.jme3.system.AppSettings; +import com.jme3.texture.GlImage; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; import java.util.logging.Logger; @@ -80,7 +81,7 @@ public static void main(String[] args){ public void simpleInitApp() { initOpenCL1(); - tex = new Texture2D(settings.getWidth(), settings.getHeight(), 1, com.jme3.texture.Image.Format.RGBA8); + tex = new Texture2D(settings.getWidth(), settings.getHeight(), 1, GlImage.Format.RGBA8); Picture pic = new Picture("julia"); pic.setTexture(assetManager, tex, true); pic.setPosition(0, 0); diff --git a/jme3-examples/src/main/java/jme3test/post/TestCartoonEdge.java b/jme3-examples/src/main/java/jme3test/post/TestCartoonEdge.java index ff6ab497f3..b157d5f0c7 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestCartoonEdge.java +++ b/jme3-examples/src/main/java/jme3test/post/TestCartoonEdge.java @@ -46,7 +46,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.Spatial.CullHint; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; public class TestCartoonEdge extends SimpleApplication { @@ -81,7 +81,7 @@ public void makeToonish(Spatial spatial){ Geometry g = (Geometry) spatial; Material m = g.getMaterial(); if (m.getMaterialDef().getMaterialParam("UseMaterialColors") != null) { - Texture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); + GlTexture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); // t.setMinFilter(Texture.MinFilter.NearestNoMipMaps); // t.setMagFilter(Texture.MagFilter.Nearest); m.setTexture("ColorRamp", t); diff --git a/jme3-examples/src/main/java/jme3test/post/TestContrastAdjustment.java b/jme3-examples/src/main/java/jme3test/post/TestContrastAdjustment.java index 52c125cb3e..940ef370f7 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestContrastAdjustment.java +++ b/jme3-examples/src/main/java/jme3test/post/TestContrastAdjustment.java @@ -43,7 +43,7 @@ import com.jme3.post.filters.ContrastAdjustmentFilter; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Sphere; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * A {@link ContrastAdjustmentFilter} with user-controlled exponents, scales, and input range. @@ -74,7 +74,7 @@ public void simpleInitApp() { final Geometry earth = new Geometry("Earth", globe); earth.rotate(-FastMath.HALF_PI, 0f, 0f); final Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - final Texture texture = assetManager.loadTexture("Textures/Sky/Earth/Earth.jpg"); + final GlTexture texture = assetManager.loadTexture("Textures/Sky/Earth/Earth.jpg"); material.setTexture("ColorMap", texture); earth.setMaterial(material); rootNode.attachChild(earth); diff --git a/jme3-examples/src/main/java/jme3test/post/TestDepthOfField.java b/jme3-examples/src/main/java/jme3test/post/TestDepthOfField.java index 3690fe9aa7..e611685cf6 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestDepthOfField.java +++ b/jme3-examples/src/main/java/jme3test/post/TestDepthOfField.java @@ -50,8 +50,8 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; import java.util.ArrayList; @@ -177,24 +177,24 @@ private void createTerrain(Node rootNode) { matRock.setBoolean("useTriPlanarMapping", false); matRock.setBoolean("WardIso", true); matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap", grass); matRock.setFloat("DiffuseMap_0_scale", 64); - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_1", dirt); matRock.setFloat("DiffuseMap_1_scale", 16); - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_2", rock); matRock.setFloat("DiffuseMap_2_scale", 128); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMap0.setWrap(WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMap1.setWrap(WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMap2.setWrap(WrapMode.Repeat); matRock.setTexture("NormalMap", normalMap0); matRock.setTexture("NormalMap_1", normalMap1); diff --git a/jme3-examples/src/main/java/jme3test/post/TestFBOPassthrough.java b/jme3-examples/src/main/java/jme3test/post/TestFBOPassthrough.java index 72a4c875f5..0582737b9e 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestFBOPassthrough.java +++ b/jme3-examples/src/main/java/jme3test/post/TestFBOPassthrough.java @@ -40,7 +40,7 @@ import com.jme3.scene.Node; import com.jme3.scene.shape.Sphere; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.ui.Picture; diff --git a/jme3-examples/src/main/java/jme3test/post/TestFog.java b/jme3-examples/src/main/java/jme3test/post/TestFog.java index b7a913d79f..890fcddf81 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestFog.java +++ b/jme3-examples/src/main/java/jme3test/post/TestFog.java @@ -50,7 +50,7 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.SkyFactory; import java.util.ArrayList; import java.util.List; @@ -163,25 +163,25 @@ private void createTerrain(Node rootNode) { matRock.setBoolean("useTriPlanarMapping", false); matRock.setBoolean("WardIso", true); matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); - grass.setWrap(Texture.WrapMode.Repeat); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + grass.setWrap(GlTexture.WrapMode.Repeat); matRock.setTexture("DiffuseMap", grass); matRock.setFloat("DiffuseMap_0_scale", 64); - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); - dirt.setWrap(Texture.WrapMode.Repeat); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + dirt.setWrap(GlTexture.WrapMode.Repeat); matRock.setTexture("DiffuseMap_1", dirt); matRock.setFloat("DiffuseMap_1_scale", 16); - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); - rock.setWrap(Texture.WrapMode.Repeat); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + rock.setWrap(GlTexture.WrapMode.Repeat); matRock.setTexture("DiffuseMap_2", rock); matRock.setFloat("DiffuseMap_2_scale", 128); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); - normalMap0.setWrap(Texture.WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); - normalMap1.setWrap(Texture.WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); - normalMap2.setWrap(Texture.WrapMode.Repeat); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + normalMap0.setWrap(GlTexture.WrapMode.Repeat); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + normalMap1.setWrap(GlTexture.WrapMode.Repeat); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + normalMap2.setWrap(GlTexture.WrapMode.Repeat); matRock.setTexture("NormalMap", normalMap0); matRock.setTexture("NormalMap_1", normalMap1); matRock.setTexture("NormalMap_2", normalMap2); diff --git a/jme3-examples/src/main/java/jme3test/post/TestIssue1798.java b/jme3-examples/src/main/java/jme3test/post/TestIssue1798.java index 79605f29a8..a5fe510d32 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestIssue1798.java +++ b/jme3-examples/src/main/java/jme3test/post/TestIssue1798.java @@ -42,7 +42,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.system.AppSettings; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * Test case for JME issue #1798: filtered scenes are squeezed by resizable @@ -98,7 +98,7 @@ private void makeToonish(Spatial spatial) { Geometry g = (Geometry) spatial; Material m = g.getMaterial(); if (m.getMaterialDef().getMaterialParam("UseMaterialColors") != null) { - Texture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); + GlTexture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); m.setTexture("ColorRamp", t); m.setBoolean("UseMaterialColors", true); m.setColor("Specular", ColorRGBA.Black); diff --git a/jme3-examples/src/main/java/jme3test/post/TestMultiRenderTarget.java b/jme3-examples/src/main/java/jme3test/post/TestMultiRenderTarget.java index a5422ac539..0544343ca8 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestMultiRenderTarget.java +++ b/jme3-examples/src/main/java/jme3test/post/TestMultiRenderTarget.java @@ -43,7 +43,7 @@ import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; diff --git a/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java b/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java index a46b14655c..db49516ecc 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPostFilters.java @@ -45,7 +45,7 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; @@ -80,7 +80,7 @@ public void setupFilters() { } public void setupSkyBox() { - Texture envMap; + GlTexture envMap; if (renderer.getCaps().contains(Caps.FloatTexture)) { envMap = assetManager.loadTexture("Textures/Sky/St Peters/StPeters.hdr"); } else { diff --git a/jme3-examples/src/main/java/jme3test/post/TestPostFiltersCompositing.java b/jme3-examples/src/main/java/jme3test/post/TestPostFiltersCompositing.java index 8661ee550e..ef7e5fec8c 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestPostFiltersCompositing.java +++ b/jme3-examples/src/main/java/jme3test/post/TestPostFiltersCompositing.java @@ -41,10 +41,10 @@ import com.jme3.post.filters.ComposeFilter; import com.jme3.scene.Spatial; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.util.SkyFactory; /** @@ -79,7 +79,7 @@ public void simpleInitApp() { //creating a frame buffer for the main viewport FrameBuffer mainVPFrameBuffer = new FrameBuffer(cam.getWidth(), cam.getHeight(), 1); - Texture2D mainVPTexture = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8); + Texture2D mainVPTexture = new Texture2D(cam.getWidth(), cam.getHeight(), GlImage.Format.RGBA8); mainVPFrameBuffer.setDepthTarget(FrameBufferTarget.newTarget(Format.Depth)); mainVPFrameBuffer.addColorTarget(FrameBufferTarget.newTarget(mainVPTexture)); @@ -87,7 +87,7 @@ public void simpleInitApp() { // Create the post processor for the GUI viewport. final FilterPostProcessor guiFpp = new FilterPostProcessor(assetManager); - guiFpp.setFrameBufferFormat(Image.Format.RGBA8); + guiFpp.setFrameBufferFormat(GlImage.Format.RGBA8); guiFpp.addFilter(new ColorOverlayFilter(ColorRGBA.Red)); // This will compose the main viewport texture with the GUI-viewport back buffer. // Note that you can switch the order of the filters so that GUI-viewport filters are applied or not to the main viewport texture diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java index da00ccecd5..442a4c5d4b 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java +++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToCubemap.java @@ -44,8 +44,8 @@ import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.TextureCubeMap; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.util.SkyFactory; @@ -65,7 +65,7 @@ public static void main(String[] args){ app.start(); } - public Texture setupOffscreenView(){ + public GlTexture setupOffscreenView(){ Camera offCamera = new Camera(512, 512); ViewPort offView @@ -83,8 +83,8 @@ public Texture setupOffscreenView(){ //setup framebuffer's texture TextureCubeMap offTex = new TextureCubeMap(512, 512, Format.RGBA8); - offTex.setMinFilter(Texture.MinFilter.Trilinear); - offTex.setMagFilter(Texture.MagFilter.Bilinear); + offTex.setMinFilter(GlTexture.MinFilter.Trilinear); + offTex.setMagFilter(GlTexture.MagFilter.Bilinear); //setup framebuffer to use texture offBuffer.setDepthTarget(FrameBufferTarget.newTarget(Format.Depth)); @@ -116,7 +116,7 @@ public void simpleInitApp() { cam.setLocation(new Vector3f(3, 3, 3)); cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); - Texture offTex = setupOffscreenView(); + GlTexture offTex = setupOffscreenView(); Spatial sky = SkyFactory.createSky(assetManager, offTex, EnvMapType.CubeMap); rootNode.attachChild(sky); diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java index 1cfa50b9a2..ac4ddc43f3 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java +++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToMemory.java @@ -50,7 +50,7 @@ import com.jme3.system.JmeContext.Type; import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer.FrameBufferTarget; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.util.BufferUtils; import com.jme3.util.Screenshots; import java.awt.Color; diff --git a/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java b/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java index 88de57274d..5945c3c005 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java +++ b/jme3-examples/src/main/java/jme3test/post/TestRenderToTexture.java @@ -46,8 +46,8 @@ import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; @@ -66,7 +66,7 @@ public static void main(String[] args){ app.start(); } - public Texture setupOffscreenView(){ + public GlTexture setupOffscreenView(){ Camera offCamera = new Camera(512, 512); offView = renderManager.createPreView("Offscreen View", offCamera); @@ -83,8 +83,8 @@ public Texture setupOffscreenView(){ //setup framebuffer's texture Texture2D offTex = new Texture2D(512, 512, Format.RGBA8); - offTex.setMinFilter(Texture.MinFilter.Trilinear); - offTex.setMagFilter(Texture.MagFilter.Bilinear); + offTex.setMinFilter(GlTexture.MinFilter.Trilinear); + offTex.setMagFilter(GlTexture.MagFilter.Bilinear); //setup framebuffer to use texture offBuffer.setDepthTarget(FrameBufferTarget.newTarget(Format.Depth)); @@ -113,7 +113,7 @@ public void simpleInitApp() { //setup main scene Geometry quad = new Geometry("box", new Box(1, 1, 1)); - Texture offTex = setupOffscreenView(); + GlTexture offTex = setupOffscreenView(); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); mat.setTexture("ColorMap", offTex); diff --git a/jme3-examples/src/main/java/jme3test/post/TestSSAO.java b/jme3-examples/src/main/java/jme3test/post/TestSSAO.java index 9275feb23d..54f23c707f 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestSSAO.java +++ b/jme3-examples/src/main/java/jme3test/post/TestSSAO.java @@ -41,7 +41,7 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.post.ssao.SSAOFilter; import com.jme3.scene.Geometry; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; public class TestSSAO extends SimpleApplication { @@ -59,10 +59,10 @@ public void simpleInitApp() { flyCam.setMoveSpeed(50); Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); - Texture diff = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); - diff.setWrap(Texture.WrapMode.Repeat); - Texture norm = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg"); - norm.setWrap(Texture.WrapMode.Repeat); + GlTexture diff = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); + diff.setWrap(GlTexture.WrapMode.Repeat); + GlTexture norm = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg"); + norm.setWrap(GlTexture.WrapMode.Repeat); mat.setTexture("DiffuseMap", diff); mat.setTexture("NormalMap", norm); mat.setFloat("Shininess", 2.0f); diff --git a/jme3-examples/src/main/java/jme3test/post/TestTransparentCartoonEdge.java b/jme3-examples/src/main/java/jme3test/post/TestTransparentCartoonEdge.java index 2e2c9874f7..1fcdea9557 100644 --- a/jme3-examples/src/main/java/jme3test/post/TestTransparentCartoonEdge.java +++ b/jme3-examples/src/main/java/jme3test/post/TestTransparentCartoonEdge.java @@ -13,7 +13,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.RectangleMesh; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; public class TestTransparentCartoonEdge extends SimpleApplication { @@ -84,7 +84,7 @@ public void makeToonish(Spatial spatial){ Geometry g = (Geometry) spatial; Material m = g.getMaterial(); if (m.getMaterialDef().getName().equals("Phong Lighting")){ - Texture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); + GlTexture t = assetManager.loadTexture("Textures/ColorRamp/toon.png"); // t.setMinFilter(Texture.MinFilter.NearestNoMipMaps); // t.setMagFilter(Texture.MagFilter.Nearest); m.setTexture("ColorRamp", t); diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestBackgroundImage.java b/jme3-examples/src/main/java/jme3test/renderer/TestBackgroundImage.java index c8c004a9c3..52d0352ccd 100644 --- a/jme3-examples/src/main/java/jme3test/renderer/TestBackgroundImage.java +++ b/jme3-examples/src/main/java/jme3test/renderer/TestBackgroundImage.java @@ -47,7 +47,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Quad; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.util.List; /** @@ -88,7 +88,7 @@ public void simpleInitApp() { * assign it to the Gui bucket, * and attach it to the background viewport. */ - Texture quadTexture + GlTexture quadTexture = assetManager.loadTexture("Interface/Logo/Monkey.png"); Material quadMaterial = new Material(assetManager, Materials.UNSHADED); quadMaterial.setTexture("ColorMap", quadTexture); diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestDepthStencil.java b/jme3-examples/src/main/java/jme3test/renderer/TestDepthStencil.java index 0f333ac661..29c7079707 100644 --- a/jme3-examples/src/main/java/jme3test/renderer/TestDepthStencil.java +++ b/jme3-examples/src/main/java/jme3test/renderer/TestDepthStencil.java @@ -46,7 +46,7 @@ import com.jme3.scene.control.AbstractControl; import com.jme3.scene.shape.Sphere; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.ui.Picture; diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestInconsistentCompareDetection.java b/jme3-examples/src/main/java/jme3test/renderer/TestInconsistentCompareDetection.java index dbb2eaad8d..4f44a3ec37 100644 --- a/jme3-examples/src/main/java/jme3test/renderer/TestInconsistentCompareDetection.java +++ b/jme3-examples/src/main/java/jme3test/renderer/TestInconsistentCompareDetection.java @@ -41,7 +41,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Box; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * Changes a material's texture from another thread while it is rendered. @@ -51,7 +51,7 @@ */ public class TestInconsistentCompareDetection extends SimpleApplication { - private static Texture t1, t2; + private static GlTexture t1, t2; public static void main(String[] args){ TestInconsistentCompareDetection app = new TestInconsistentCompareDetection(); @@ -104,7 +104,7 @@ public void run() { for (Spatial child : rootNode.getChildren()) { Geometry g = (Geometry) (((Node)child).getChild(0)); Material m = g.getMaterial(); - Texture curTex = m.getTextureParam("ColorMap").getTextureValue(); + GlTexture curTex = m.getTextureParam("ColorMap").getTextureValue(); if (curTex == t1) { m.setTexture("ColorMap", t2); } else { diff --git a/jme3-examples/src/main/java/jme3test/renderer/TestIssue37.java b/jme3-examples/src/main/java/jme3test/renderer/TestIssue37.java index ce276e81d9..04d8cb0d03 100644 --- a/jme3-examples/src/main/java/jme3test/renderer/TestIssue37.java +++ b/jme3-examples/src/main/java/jme3test/renderer/TestIssue37.java @@ -39,7 +39,7 @@ import com.jme3.scene.Mesh; import com.jme3.scene.shape.Box; import com.jme3.shader.VarType; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; /** * Test a Material with increasing numbers of texture parameters, to see what @@ -59,7 +59,7 @@ public class TestIssue37 extends SimpleApplication { private int numTextures; private Material manyTexturesMaterial; - private Texture testTexture; + private GlTexture testTexture; public static void main(String[] args) { Application application = new TestIssue37(); diff --git a/jme3-examples/src/main/java/jme3test/scene/instancing/TestInstanceNode.java b/jme3-examples/src/main/java/jme3test/scene/instancing/TestInstanceNode.java index 8a3da3abdd..be26b0a68a 100644 --- a/jme3-examples/src/main/java/jme3test/scene/instancing/TestInstanceNode.java +++ b/jme3-examples/src/main/java/jme3test/scene/instancing/TestInstanceNode.java @@ -66,7 +66,7 @@ public static void main(String[] args){ } private Geometry createInstance(float x, float z) { - Mesh mesh; + Mesh mesh; if (FastMath.nextRandomInt(0, 1) == 1) mesh = mesh2; else mesh = mesh1; Geometry geometry = new Geometry("randomGeom", mesh); @@ -156,7 +156,7 @@ public void simpleUpdate(float tpf) { Geometry geom = (Geometry) instance; geom.setMaterial(materials[FastMath.nextRandomInt(0, materials.length - 1)]); - Mesh mesh; + Mesh mesh; if (FastMath.nextRandomInt(0, 1) == 1) mesh = mesh2; else mesh = mesh1; geom.setMesh(mesh); diff --git a/jme3-examples/src/main/java/jme3test/stencil/TestStencilOutline.java b/jme3-examples/src/main/java/jme3test/stencil/TestStencilOutline.java index 406b15621e..3b49ff3be7 100644 --- a/jme3-examples/src/main/java/jme3test/stencil/TestStencilOutline.java +++ b/jme3-examples/src/main/java/jme3test/stencil/TestStencilOutline.java @@ -15,7 +15,7 @@ import com.jme3.scene.control.AbstractControl; import com.jme3.scene.shape.Box; import com.jme3.system.AppSettings; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import java.util.logging.Level; import java.util.logging.Logger; @@ -131,7 +131,7 @@ public void simpleInitApp() { //This is to make sure a depth stencil format is used in the TestChooser app. FilterPostProcessor postProcessor=new FilterPostProcessor(assetManager); - postProcessor.setFrameBufferDepthFormat(Image.Format.Depth24Stencil8); + postProcessor.setFrameBufferDepthFormat(GlImage.Format.Depth24Stencil8); viewPort.addProcessor(postProcessor); postProcessor.addFilter(new BloomFilter()); } diff --git a/jme3-examples/src/main/java/jme3test/stress/TestShaderNodesStress.java b/jme3-examples/src/main/java/jme3test/stress/TestShaderNodesStress.java index 34ab16f550..10b8fea703 100644 --- a/jme3-examples/src/main/java/jme3test/stress/TestShaderNodesStress.java +++ b/jme3-examples/src/main/java/jme3test/stress/TestShaderNodesStress.java @@ -10,7 +10,7 @@ import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,7 +33,7 @@ public void simpleInitApp() { cam.setLocation(new Vector3f(0.0f, 0.0f, 0.40647888f)); cam.setRotation(new Quaternion(0.0f, 1.0f, 0.0f, 0.0f)); - Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + GlTexture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); Material mat = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md"); //Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); diff --git a/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainAdvancedTest.java b/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainAdvancedTest.java index d4cd04e403..07c14715df 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainAdvancedTest.java +++ b/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainAdvancedTest.java @@ -49,11 +49,11 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; import com.jme3.texture.TextureArray; import java.util.ArrayList; import java.util.List; @@ -229,31 +229,31 @@ private void setUpTerrainMaterial() { // load textures for texture arrays // These MUST all have the same dimensions and format in order to be put into a texture array. //ALBEDO MAPS - Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); - Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); - Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); - Texture tileRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); - Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); - Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); + GlTexture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); + GlTexture tileRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); + GlTexture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); // NORMAL MAPS - Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); - Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); - Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); - Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); - Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); - Texture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png"); - Texture normalMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); + GlTexture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); + GlTexture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); + GlTexture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); + GlTexture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); + GlTexture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); + GlTexture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png"); + GlTexture normalMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); //PACKED METALLIC/ROUGHNESS / AMBIENT OCCLUSION / EMISSIVE INTENSITY MAPS - Texture metallicRoughnessAoEiMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png"); // put all images into lists to create texture arrays. // @@ -261,9 +261,9 @@ private void setUpTerrainMaterial() { // sent to the material to tell the shader to choose that texture from // the textureArray when setting up a texture slot's mat params. // - List albedoImages = new ArrayList<>(); - List normalMapImages = new ArrayList<>(); - List metallicRoughnessAoEiMapImages = new ArrayList<>(); + List albedoImages = new ArrayList<>(); + List normalMapImages = new ArrayList<>(); + List metallicRoughnessAoEiMapImages = new ArrayList<>(); albedoImages.add(dirt.getImage()); //0 albedoImages.add(darkRock.getImage()); //1 @@ -457,7 +457,7 @@ public void simpleUpdate(float tpf) { private void setUpTerrain() { // HEIGHTMAP image (for the terrain heightmap) TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false); - Texture heightMapImage = assetManager.loadTexture(hmKey); + GlTexture heightMapImage = assetManager.loadTexture(hmKey); // CREATE HEIGHTMAP AbstractHeightMap heightmap = null; @@ -481,7 +481,7 @@ private void setUpTerrain() { rootNode.attachChild(terrain); } - private void setWrapAndMipMaps(Texture texture){ + private void setWrapAndMipMaps(GlTexture texture){ texture.setWrap(WrapMode.Repeat); texture.setMinFilter(MinFilter.Trilinear); texture.setMagFilter(MagFilter.Bilinear); diff --git a/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainTest.java b/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainTest.java index 1500257612..83dc7f633e 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainTest.java +++ b/jme3-examples/src/main/java/jme3test/terrain/PBRTerrainTest.java @@ -48,8 +48,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; /** * This test uses 'PBRTerrain.j3md' to create a terrain Material for PBR. @@ -193,7 +193,7 @@ private void setUpTerrainMaterial() { // this material also supports 'AlphaMap_2', so you can get up to 12 diffuse textures // DIRT texture, Diffuse textures 0 to 3 use the first AlphaMap - Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); dirt.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_0", dirt); matTerrain.setFloat("AlbedoMap_0_scale", dirtScale); @@ -202,7 +202,7 @@ private void setUpTerrainMaterial() { //matTerrain.setInt("AfflictionMode_0", 0); // DARK ROCK texture - Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); + GlTexture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); darkRock.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_1", darkRock); matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale); @@ -211,14 +211,14 @@ private void setUpTerrainMaterial() { //matTerrain.setInt("AfflictionMode_1", 0); // SNOW texture - Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); + GlTexture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); snow.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_2", snow); matTerrain.setFloat("AlbedoMap_2_scale", snowScale); matTerrain.setFloat("Roughness_2", 0.55f); matTerrain.setFloat("Metallic_2", 0.12f); - Texture tiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); + GlTexture tiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); tiles.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_3", tiles); matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale); @@ -226,7 +226,7 @@ private void setUpTerrainMaterial() { matTerrain.setFloat("Metallic_3", 0.08f); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); grass.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_4", grass); matTerrain.setFloat("AlbedoMap_4_scale", grassScale); @@ -234,7 +234,7 @@ private void setUpTerrainMaterial() { matTerrain.setFloat("Metallic_4", 0); // MARBLE texture - Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); + GlTexture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); marble.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_5", marble); matTerrain.setFloat("AlbedoMap_5_scale", marbleScale); @@ -242,32 +242,32 @@ private void setUpTerrainMaterial() { matTerrain.setFloat("Metallic_5", 0.8f); // Gravel texture - Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); + GlTexture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); gravel.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_6", gravel); matTerrain.setFloat("AlbedoMap_6_scale", gravelScale); matTerrain.setFloat("Roughness_6", 0.9f); matTerrain.setFloat("Metallic_6", 0.07f); // NORMAL MAPS - Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); + GlTexture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); normalMapDirt.setWrap(WrapMode.Repeat); - Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); + GlTexture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); normalMapDarkRock.setWrap(WrapMode.Repeat); - Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); + GlTexture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); normalMapSnow.setWrap(WrapMode.Repeat); - Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); + GlTexture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); normalMapGravel.setWrap(WrapMode.Repeat); - Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); + GlTexture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); normalMapGrass.setWrap(WrapMode.Repeat); // Texture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png"); // normalMapMarble.setWrap(WrapMode.Repeat); - Texture normalMapTiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); + GlTexture normalMapTiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); normalMapTiles.setWrap(WrapMode.Repeat); matTerrain.setTexture("NormalMap_0", normalMapDirt); @@ -365,7 +365,7 @@ public void simpleUpdate(float tpf) { private void setUpTerrain() { // HEIGHTMAP image (for the terrain heightmap) TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false); - Texture heightMapImage = assetManager.loadTexture(hmKey); + GlTexture heightMapImage = assetManager.loadTexture(hmKey); // CREATE HEIGHTMAP AbstractHeightMap heightmap = null; diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainFractalGridTest.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainFractalGridTest.java index 76d10a8220..d99ca8b487 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainFractalGridTest.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainFractalGridTest.java @@ -19,8 +19,8 @@ import com.jme3.terrain.noise.filter.SmoothFilter; import com.jme3.terrain.noise.fractal.FractalSum; import com.jme3.terrain.noise.modulator.NoiseModulator; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; public class TerrainFractalGridTest extends SimpleApplication { @@ -54,19 +54,19 @@ public void simpleInitApp() { // slopeTileFactor: the texture scale for slopes // terrainSize: the total size of the terrain (used for scaling the texture) // GRASS texture - Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region1ColorMap", grass); mat_terrain.setVector3("region1", new Vector3f(15, 200, this.grassScale)); // DIRT texture - Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region2ColorMap", dirt); mat_terrain.setVector3("region2", new Vector3f(0, 20, this.dirtScale)); // ROCK texture - Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + GlTexture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); rock.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region3ColorMap", rock); mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainGridAlphaMapTest.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainGridAlphaMapTest.java index a5f01976bd..cb1750f08c 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainGridAlphaMapTest.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainGridAlphaMapTest.java @@ -38,8 +38,8 @@ import com.jme3.terrain.noise.filter.SmoothFilter; import com.jme3.terrain.noise.fractal.FractalSum; import com.jme3.terrain.noise.modulator.NoiseModulator; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import java.io.File; public class TerrainGridAlphaMapTest extends SimpleApplication { @@ -86,19 +86,19 @@ public void simpleInitApp() { material.setFloat("Shininess", 0.0f); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); material.setTexture("DiffuseMap", grass); material.setFloat("DiffuseMap_0_scale", grassScale); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); material.setTexture("DiffuseMap_1", dirt); material.setFloat("DiffuseMap_1_scale", dirtScale); // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); material.setTexture("DiffuseMap_2", rock); material.setFloat("DiffuseMap_2_scale", rockScale); @@ -185,7 +185,7 @@ public void gridMoved(Vector3f newCenter) { @Override public void tileAttached(Vector3f cell, TerrainQuad quad) { - Texture alpha = null; + GlTexture alpha = null; try { alpha = assetManager.loadTexture("TerrainAlphaTest/alpha_" + (int)cell.x+ "_" + (int)cell.z + ".png"); } catch (Exception e) { diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTest.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTest.java index 762b32f2da..36b1d17120 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTest.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTest.java @@ -24,8 +24,8 @@ import com.jme3.terrain.geomipmap.grid.ImageTileLoader; import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.Namer; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; public class TerrainGridTest extends SimpleApplication { @@ -64,19 +64,19 @@ public void simpleInitApp() { // slopeTileFactor: the texture scale for slopes // terrainSize: the total size of the terrain (used for scaling the texture) // GRASS texture - Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region1ColorMap", grass); mat_terrain.setVector3("region1", new Vector3f(88, 200, this.grassScale)); // DIRT texture - Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region2ColorMap", dirt); mat_terrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale)); // ROCK texture - Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + GlTexture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); rock.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region3ColorMap", rock); mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTileLoaderTest.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTileLoaderTest.java index 5f9ca109fe..3bb3e1fd0e 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTileLoaderTest.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainGridTileLoaderTest.java @@ -24,8 +24,8 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.geomipmap.grid.AssetTileLoader; import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; public class TerrainGridTileLoaderTest extends SimpleApplication { @@ -67,19 +67,19 @@ public void simpleInitApp() { // slopeTileFactor: the texture scale for slopes // terrainSize: the total size of the terrain (used for scaling the texture) // GRASS texture - Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region1ColorMap", grass); mat_terrain.setVector3("region1", new Vector3f(88, 200, this.grassScale)); // DIRT texture - Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region2ColorMap", dirt); mat_terrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale)); // ROCK texture - Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + GlTexture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); rock.setWrap(WrapMode.Repeat); mat_terrain.setTexture("region3ColorMap", rock); mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainTest.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainTest.java index 4f91ebcf0e..1be4fc5b47 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainTest.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainTest.java @@ -46,8 +46,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; /** * Demonstrates how to use terrain. @@ -105,22 +105,22 @@ public void simpleInitApp() { matRock.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); // HEIGHTMAP image (for the terrain heightmap) - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("Tex1", grass); matRock.setFloat("Tex1Scale", grassScale); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("Tex2", dirt); matRock.setFloat("Tex2Scale", dirtScale); // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("Tex3", rock); matRock.setFloat("Tex3Scale", rockScale); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAdvanced.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAdvanced.java index c69eeac3fb..3d015d9c2c 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAdvanced.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAdvanced.java @@ -51,8 +51,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.SkyFactory; /** @@ -106,46 +106,46 @@ public void simpleInitApp() { // HEIGHTMAP image (for the terrain heightmap) TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false); - Texture heightMapImage = assetManager.loadTexture(hmKey); + GlTexture heightMapImage = assetManager.loadTexture(hmKey); // DIRT texture, Diffuse textures 0 to 3 use the first AlphaMap - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap", dirt); matTerrain.setFloat("DiffuseMap_0_scale", dirtScale); // DARK ROCK texture - Texture darkRock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); + GlTexture darkRock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); darkRock.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_1", darkRock); matTerrain.setFloat("DiffuseMap_1_scale", darkRockScale); // PINK ROCK texture - Texture pinkRock = assetManager.loadTexture("Textures/Terrain/Rock/Rock.PNG"); + GlTexture pinkRock = assetManager.loadTexture("Textures/Terrain/Rock/Rock.PNG"); pinkRock.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_2", pinkRock); matTerrain.setFloat("DiffuseMap_2_scale", pinkRockScale); // RIVER ROCK texture, this texture will use the next alphaMap: AlphaMap_1 - Texture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"); + GlTexture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"); riverRock.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_3", riverRock); matTerrain.setFloat("DiffuseMap_3_scale", riverRockScale); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_4", grass); matTerrain.setFloat("DiffuseMap_4_scale", grassScale); // BRICK texture - Texture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); + GlTexture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"); brick.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_5", brick); matTerrain.setFloat("DiffuseMap_5_scale", brickScale); // ROAD texture - Texture road = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture road = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); road.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_6", road); matTerrain.setFloat("DiffuseMap_6_scale", roadScale); @@ -157,13 +157,13 @@ public void simpleInitApp() { // NORMAL MAPS - Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMapDirt = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMapDirt.setWrap(WrapMode.Repeat); - Texture normalMapPinkRock = assetManager.loadTexture("Textures/Terrain/Rock/Rock_normal.png"); + GlTexture normalMapPinkRock = assetManager.loadTexture("Textures/Terrain/Rock/Rock_normal.png"); normalMapPinkRock.setWrap(WrapMode.Repeat); - Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMapGrass = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMapGrass.setWrap(WrapMode.Repeat); - Texture normalMapRoad = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMapRoad = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMapRoad.setWrap(WrapMode.Repeat); matTerrain.setTexture("NormalMap", normalMapDirt); matTerrain.setTexture("NormalMap_1", normalMapPinkRock); @@ -296,12 +296,12 @@ public void onAction(String name, boolean pressed, float tpf) { }; private void createSky() { - Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); - Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); - Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); - Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); - Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); - Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); + GlTexture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); + GlTexture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); + GlTexture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); + GlTexture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); + GlTexture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); + GlTexture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down); rootNode.attachChild(sky); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAndroid.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAndroid.java index 57be5d293a..de512811bf 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAndroid.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestAndroid.java @@ -46,8 +46,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; /** * Demonstrates how to use terrain on Android. @@ -93,22 +93,22 @@ public void simpleInitApp() { matRock.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); // HEIGHTMAP image (for the terrain heightmap) - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains128.png"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains128.png"); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("Tex1", grass); matRock.setFloat("Tex1Scale", grassScale); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("Tex2", dirt); matRock.setFloat("Tex2Scale", dirtScale); // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("Tex3", rock); matRock.setFloat("Tex3Scale", rockScale); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestCollision.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestCollision.java index 456e5cec29..78aba04165 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestCollision.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestCollision.java @@ -59,8 +59,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import java.util.ArrayList; import java.util.List; @@ -104,16 +104,16 @@ public void simpleInitApp() { setupKeys(); matRock = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md"); matRock.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("Tex1", grass); matRock.setFloat("Tex1Scale", 64f); - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("Tex2", dirt); matRock.setFloat("Tex2Scale", 32f); - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("Tex3", rock); matRock.setFloat("Tex3Scale", 128f); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestModifyHeight.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestModifyHeight.java index 4a34906fd0..105054a89a 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestModifyHeight.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestModifyHeight.java @@ -57,8 +57,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import java.util.ArrayList; import java.util.List; @@ -275,25 +275,25 @@ private void createTerrain() { matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap", grass); matTerrain.setFloat("DiffuseMap_0_scale", grassScale); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_1", dirt); matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_2", rock); matTerrain.setFloat("DiffuseMap_2_scale", rockScale); // HEIGHTMAP image (for the terrain heightmap) - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); AbstractHeightMap heightmap = null; try { heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.5f); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestReadWrite.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestReadWrite.java index 06a4f95776..8ab507b7ff 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestReadWrite.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestReadWrite.java @@ -51,8 +51,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import java.io.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -100,33 +100,33 @@ private void createMap() { matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); // HEIGHTMAP image (for the terrain heightmap) - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap", grass); matTerrain.setFloat("DiffuseMap_0_scale", grassScale); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_1", dirt); matTerrain.setFloat("DiffuseMap_1_scale", dirtScale); // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap_2", rock); matTerrain.setFloat("DiffuseMap_2_scale", rockScale); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMap0.setWrap(WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMap1.setWrap(WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMap2.setWrap(WrapMode.Repeat); matTerrain.setTexture("NormalMap", normalMap0); matTerrain.setTexture("NormalMap_1", normalMap1); diff --git a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestTile.java b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestTile.java index e4d60bd915..8ba864afe8 100644 --- a/jme3-examples/src/main/java/jme3test/terrain/TerrainTestTile.java +++ b/jme3-examples/src/main/java/jme3test/terrain/TerrainTestTile.java @@ -51,8 +51,8 @@ import com.jme3.terrain.geomipmap.NeighbourFinder; import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import java.util.List; /** @@ -179,7 +179,7 @@ private class TiledTerrain extends Node implements Terrain, NeighbourFinder { matTerrain.setFloat("Shininess", 0); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matTerrain.setTexture("DiffuseMap", grass); matTerrain.setFloat("DiffuseMap_0_scale", grassScale); diff --git a/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java b/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java index 16ba966618..1cc8017dda 100755 --- a/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestAnisotropicFilter.java @@ -13,9 +13,9 @@ import com.jme3.renderer.Limits; import com.jme3.scene.Geometry; import com.jme3.scene.shape.RectangleMesh; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ColorSpace; import com.jme3.texture.image.ImageRaster; @@ -52,16 +52,16 @@ public void simpleInitApp() { private static Material createCheckerBoardMaterial(AssetManager assetManager) { Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - Texture tex = createCheckerBoardTexture(); // assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.dds"); - tex.setMagFilter(Texture.MagFilter.Bilinear); - tex.setMinFilter(Texture.MinFilter.Trilinear); - tex.setWrap(Texture.WrapMode.Repeat); + GlTexture tex = createCheckerBoardTexture(); // assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.dds"); + tex.setMagFilter(GlTexture.MagFilter.Bilinear); + tex.setMinFilter(GlTexture.MinFilter.Trilinear); + tex.setWrap(GlTexture.WrapMode.Repeat); mat.setTexture("ColorMap", tex); return mat; } private static Texture2D createCheckerBoardTexture() { - Image image = new Image(Format.RGBA8, 1024, 1024, BufferUtils.createByteBuffer(1024 * 1024 * 4), ColorSpace.sRGB); + GlImage image = new GlImage(Format.RGBA8, 1024, 1024, BufferUtils.createByteBuffer(1024 * 1024 * 4), ColorSpace.sRGB); ImageRaster raster = ImageRaster.create(image); for (int y = 0; y < 1024; y++) { diff --git a/jme3-examples/src/main/java/jme3test/texture/TestImageRaster.java b/jme3-examples/src/main/java/jme3test/texture/TestImageRaster.java index 5288d4ffe6..b02b123a63 100644 --- a/jme3-examples/src/main/java/jme3test/texture/TestImageRaster.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestImageRaster.java @@ -11,11 +11,11 @@ import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ImageRaster; import com.jme3.util.BufferUtils; @@ -23,11 +23,11 @@ public class TestImageRaster extends SimpleApplication { - private Image convertImage(Image image, Format newFormat) { + private GlImage convertImage(GlImage image, Format newFormat) { int width = image.getWidth(); int height = image.getHeight(); ByteBuffer data = BufferUtils.createByteBuffer( (int)Math.ceil(newFormat.getBitsPerPixel() / 8.0) * width * height); - Image convertedImage = new Image(newFormat, width, height, data,null, image.getColorSpace()); + GlImage convertedImage = new GlImage(newFormat, width, height, data,null, image.getColorSpace()); ImageRaster sourceReader = ImageRaster.create(image); ImageRaster targetWriter = ImageRaster.create(convertedImage); @@ -41,8 +41,8 @@ private Image convertImage(Image image, Format newFormat) { return convertedImage; } - private void convertAndPutImage(Image image, float posX, float posY) { - Texture tex = new Texture2D(image); + private void convertAndPutImage(GlImage image, float posX, float posY) { + GlTexture tex = new Texture2D(image); tex.setMagFilter(MagFilter.Nearest); tex.setMinFilter(MinFilter.NearestNoMipMaps); tex.setAnisotropicFilter(16); @@ -60,7 +60,7 @@ private void convertAndPutImage(Image image, float posX, float posY) { txt.setBox(new Rectangle(0, 0, 5, 5)); txt.setQueueBucket(RenderQueue.Bucket.Transparent); txt.setSize(0.5f); - txt.setText(image.getFormat().name()); + txt.setText(image.getGlFormat().name()); txt.setLocalTranslation(posX, posY, 0); rootNode.attachChild(txt); } @@ -70,11 +70,11 @@ public void simpleInitApp() { cam.setLocation(new Vector3f(16, 6, 36)); flyCam.setMoveSpeed(10); - Texture tex = assetManager.loadTexture("com/jme3/app/Monkey.png"); + GlTexture tex = assetManager.loadTexture("com/jme3/app/Monkey.png"); // Texture tex = assetManager.loadTexture("Textures/HdrTest/Memorial.hdr"); - Image originalImage = tex.getImage(); + GlImage originalImage = tex.getImage(); - Image image = convertImage(originalImage, Format.RGBA32F); + GlImage image = convertImage(originalImage, Format.RGBA32F); convertAndPutImage(image, 0, 0); image = convertImage(image, Format.RGB32F); diff --git a/jme3-examples/src/main/java/jme3test/texture/TestShaderImage.java b/jme3-examples/src/main/java/jme3test/texture/TestShaderImage.java index 52f698c99d..3b02292c2c 100644 --- a/jme3-examples/src/main/java/jme3test/texture/TestShaderImage.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestShaderImage.java @@ -11,7 +11,7 @@ import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Quad; import com.jme3.shader.VarType; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.Texture2D; import com.jme3.texture.TextureImage; @@ -37,7 +37,7 @@ public void simpleInitApp() { int width = context.getFramebufferWidth(); int height = context.getFramebufferHeight(); - Texture2D target = new Texture2D(width, height, Image.Format.RGBA8); + Texture2D target = new Texture2D(width, height, GlImage.Format.RGBA8); TextureImage targetImage = new TextureImage(target, TextureImage.Access.WriteOnly); mat.setParam("TargetImage", VarType.Image2D, targetImage); diff --git a/jme3-examples/src/main/java/jme3test/texture/TestSkyLoading.java b/jme3-examples/src/main/java/jme3test/texture/TestSkyLoading.java index 21c1b590b9..c86f790ec7 100644 --- a/jme3-examples/src/main/java/jme3test/texture/TestSkyLoading.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestSkyLoading.java @@ -34,7 +34,7 @@ import com.jme3.app.SimpleApplication; import com.jme3.scene.Spatial; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.SkyFactory; public class TestSkyLoading extends SimpleApplication { @@ -46,12 +46,12 @@ public static void main(String[] args){ @Override public void simpleInitApp() { - Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); - Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); - Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); - Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); - Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); - Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); + GlTexture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg"); + GlTexture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg"); + GlTexture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg"); + GlTexture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg"); + GlTexture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg"); + GlTexture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down); rootNode.attachChild(sky); diff --git a/jme3-examples/src/main/java/jme3test/texture/TestTexture3D.java b/jme3-examples/src/main/java/jme3test/texture/TestTexture3D.java index e3f41b6fee..b0aad67d50 100644 --- a/jme3-examples/src/main/java/jme3test/texture/TestTexture3D.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestTexture3D.java @@ -42,9 +42,9 @@ import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Usage; import com.jme3.scene.shape.Sphere; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture3D; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; @@ -91,7 +91,7 @@ public void simpleInitApp() { Geometry g = new Geometry("sphere", sphere); Material material = new Material(assetManager, "jme3test/texture/tex3D.j3md"); try { - Texture texture = this.getTexture(); + GlTexture texture = this.getTexture(); material.setTexture("Texture", texture); } catch (IOException e) { e.printStackTrace(); @@ -114,7 +114,7 @@ public void simpleInitApp() { /** * This method creates an RGB8 texture with the sizes of 10x10x10 pixels. */ - private Texture getTexture() throws IOException { + private GlTexture getTexture() throws IOException { ArrayList data = new ArrayList<>(1); ByteBuffer bb = BufferUtils.createByteBuffer(10 * 10 * 10 * 3);//all data must be inside one buffer for (int i = 0; i < 10; ++i) { @@ -126,6 +126,6 @@ private Texture getTexture() throws IOException { } bb.rewind(); data.add(bb); - return new Texture3D(new Image(Format.RGB8, 10, 10, 10, data, null, ColorSpace.Linear)); + return new Texture3D(new GlImage(Format.RGB8, 10, 10, 10, data, null, ColorSpace.Linear)); } } diff --git a/jme3-examples/src/main/java/jme3test/texture/TestTexture3DLoading.java b/jme3-examples/src/main/java/jme3test/texture/TestTexture3DLoading.java index ada3f1fffe..e935b12d7e 100644 --- a/jme3-examples/src/main/java/jme3test/texture/TestTexture3DLoading.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestTexture3DLoading.java @@ -39,7 +39,7 @@ import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; public class TestTexture3DLoading extends SimpleApplication { @@ -60,9 +60,9 @@ public void simpleInitApp() { Material material = new Material(assetManager, "jme3test/texture/tex3DThumb.j3md"); TextureKey key = new TextureKey("Textures/3D/flame.dds"); key.setGenerateMips(true); - key.setTextureTypeHint(Texture.Type.ThreeDimensional); + key.setTextureTypeHint(GlTexture.Type.ThreeDimensional); - Texture t = assetManager.loadTexture(key); + GlTexture t = assetManager.loadTexture(key); int rows = 4;//4 * 4 diff --git a/jme3-examples/src/main/java/jme3test/texture/TestTextureArray.java b/jme3-examples/src/main/java/jme3test/texture/TestTextureArray.java index ba56b3ff2a..0c4be35f17 100644 --- a/jme3-examples/src/main/java/jme3test/texture/TestTextureArray.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestTextureArray.java @@ -8,8 +8,8 @@ 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.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.TextureArray; import com.jme3.util.BufferUtils; import java.util.ArrayList; @@ -31,13 +31,13 @@ public void simpleInitApp() } - Texture tex1 = assetManager.loadTexture( "Textures/Terrain/Pond/Pond.jpg"); - Texture tex2 = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); - List images = new ArrayList<>(); + GlTexture tex1 = assetManager.loadTexture( "Textures/Terrain/Pond/Pond.jpg"); + GlTexture 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); - tex3.setMinFilter(Texture.MinFilter.Trilinear); + tex3.setMinFilter(GlTexture.MinFilter.Trilinear); mat.setTexture("ColorMap", tex3); Mesh m = new Mesh(); diff --git a/jme3-examples/src/main/java/jme3test/texture/TestTextureArrayCompressed.java b/jme3-examples/src/main/java/jme3test/texture/TestTextureArrayCompressed.java index 0af064f557..8c1d0d55a4 100644 --- a/jme3-examples/src/main/java/jme3test/texture/TestTextureArrayCompressed.java +++ b/jme3-examples/src/main/java/jme3test/texture/TestTextureArrayCompressed.java @@ -8,8 +8,8 @@ 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.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.TextureArray; import com.jme3.util.BufferUtils; import java.util.ArrayList; @@ -31,13 +31,13 @@ public void simpleInitApp() } - Texture tex1 = assetManager.loadTexture( "Textures/Terrain/Pond/Pond_dxt5.dds"); - Texture tex2 = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_dxt5.dds"); - List images = new ArrayList<>(); + GlTexture tex1 = assetManager.loadTexture( "Textures/Terrain/Pond/Pond_dxt5.dds"); + GlTexture tex2 = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_dxt5.dds"); + List images = new ArrayList<>(); images.add(tex1.getImage()); images.add(tex2.getImage()); TextureArray tex3 = new TextureArray(images); - tex3.setMinFilter(Texture.MinFilter.Trilinear); + tex3.setMinFilter(GlTexture.MinFilter.Trilinear); mat.setTexture("ColorMap", tex3); Mesh m = new Mesh(); diff --git a/jme3-examples/src/main/java/jme3test/vulkan/AttributeBufferBenchmark.java b/jme3-examples/src/main/java/jme3test/vulkan/AttributeBufferBenchmark.java new file mode 100644 index 0000000000..6aa1148389 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/vulkan/AttributeBufferBenchmark.java @@ -0,0 +1,78 @@ +package jme3test.vulkan; + +import com.jme3.vulkan.Format; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +/** + * Benchmarks interaction with ByteBuffers through {@link com.jme3.vulkan.Format.Component + * Component} compatibility, which ensure that whatever primitives are provided + * are correctly put into the buffer, and vise versa. Components will be critical + * for ensuring that Meshes don't care what MeshDescription they are using. + * + *

From the tests, it seems that the extra overhead Components use for puts + * is minimal. Component put versus direct put pretty much take the same time.

+ */ +public class AttributeBufferBenchmark { + + public static final Format format = Format.RGBA8_SRGB; + public static final int verts = 5000; + + private static long startNanos; + + public static void main(String[] args) { + + ByteBuffer buffer = MemoryUtil.memCalloc(format.getTotalBytes() * verts); + + for (int t = 0; t < 10; t++) { + fillBufferByComponent(buffer); + fillBufferRaw(buffer); + System.out.println(); + } + + MemoryUtil.memFree(buffer); + + } + + public static void fillBufferByComponent(ByteBuffer buffer) { + float value = getTestValue(); + start(); + for (int i = 0; i < verts; i++) { + int p = i * format.getTotalBytes(); + for (Format.Component c : format) { + // The advantage of Component put is that we can provide + // any primitive type, and the Component will automatically + // convert to the correct type. + c.putFloat(buffer, p, value); + } + } + end("Fill buffer by component"); + } + + public static void fillBufferRaw(ByteBuffer buffer) { + float value = getTestValue(); + start(); + for (int i = 0; i < verts; i++) { + int p = i * format.getTotalBytes(); + for (Format.Component c : format) { + buffer.put(p + c.getOffset(), (byte)value); + } + } + end("Fill buffer raw"); + } + + public static void start() { + startNanos = System.nanoTime(); + } + + public static void end(String task) { + long end = System.nanoTime(); + System.out.println(task + ": " + ((double)Math.abs(end - startNanos) / 1_000_000) + "ms"); + } + + public static float getTestValue() { + return (float)Math.random(); + } + +} diff --git a/jme3-examples/src/main/java/jme3test/vulkan/VkGLCompatibilityTest.java b/jme3-examples/src/main/java/jme3test/vulkan/VkGLCompatibilityTest.java new file mode 100644 index 0000000000..1acc6a3bac --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/vulkan/VkGLCompatibilityTest.java @@ -0,0 +1,32 @@ +package jme3test.vulkan; + +import com.jme3.app.FlyCamAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.system.AppSettings; +import com.jme3.system.vulkan.LwjglVulkanContext; + +public class VkGLCompatibilityTest extends SimpleApplication { + + public static void main(String[] args) { + VulkanHelperTest app = new VulkanHelperTest(); + AppSettings settings = new AppSettings(true); + settings.setWidth(768); + settings.setHeight(768); + settings.setRenderer("CUSTOM" + LwjglVulkanContext.class.getName()); + app.setSettings(settings); + app.setShowSettings(false); + app.start(); + } + + public VkGLCompatibilityTest() { + super(new FlyCamAppState()); + } + + @Override + public void simpleInitApp() { + + //Material material; + + } + +} diff --git a/jme3-examples/src/main/java/jme3test/vulkan/VulkanHelperTest.java b/jme3-examples/src/main/java/jme3test/vulkan/VulkanHelperTest.java new file mode 100644 index 0000000000..47c365caa7 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/vulkan/VulkanHelperTest.java @@ -0,0 +1,428 @@ +package jme3test.vulkan; + +import com.jme3.app.FlyCamAppState; +import com.jme3.app.SimpleApplication; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Spatial; +import com.jme3.shaderc.ShaderType; +import com.jme3.shaderc.ShadercLoader; +import com.jme3.system.AppSettings; +import com.jme3.system.vulkan.LwjglVulkanContext; +import com.jme3.texture.ImageView; +import com.jme3.util.natives.Native; +import com.jme3.vulkan.Format; +import com.jme3.vulkan.VulkanInstance; +import com.jme3.vulkan.buffers.BufferUsage; +import com.jme3.vulkan.buffers.PersistentBuffer; +import com.jme3.vulkan.buffers.StageableBuffer; +import com.jme3.vulkan.commands.CommandBuffer; +import com.jme3.vulkan.commands.CommandPool; +import com.jme3.vulkan.descriptors.*; +import com.jme3.vulkan.devices.DeviceFeature; +import com.jme3.vulkan.devices.DeviceFilter; +import com.jme3.vulkan.devices.GeneralPhysicalDevice; +import com.jme3.vulkan.devices.LogicalDevice; +import com.jme3.vulkan.frames.SingleResource; +import com.jme3.vulkan.frames.UpdateFrame; +import com.jme3.vulkan.frames.UpdateFrameManager; +import com.jme3.vulkan.images.*; +import com.jme3.vulkan.material.MatrixTransformMaterial; +import com.jme3.vulkan.material.TestMaterial; +import com.jme3.vulkan.memory.MemoryProp; +import com.jme3.vulkan.memory.MemorySize; +import com.jme3.vulkan.mesh.*; +import com.jme3.vulkan.pass.Attachment; +import com.jme3.vulkan.pass.Subpass; +import com.jme3.vulkan.pass.RenderPass; +import com.jme3.vulkan.pipelines.*; +import com.jme3.vulkan.pipelines.states.ColorBlendAttachment; +import com.jme3.vulkan.pipelines.states.DynamicState; +import com.jme3.vulkan.shader.ShaderModule; +import com.jme3.vulkan.shader.ShaderStage; +import com.jme3.vulkan.surface.Surface; +import com.jme3.vulkan.surface.Swapchain; +import com.jme3.vulkan.surface.SwapchainUpdater; +import com.jme3.vulkan.sync.Fence; +import com.jme3.vulkan.sync.Semaphore; +import com.jme3.vulkan.sync.SyncGroup; +import com.jme3.vulkan.update.CommandBatch; +import com.jme3.vulkan.update.BasicCommandBatch; +import com.jme3.vulkan.util.Flag; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.*; + +import java.util.logging.Level; + +import static org.lwjgl.vulkan.VK13.*; + +public class VulkanHelperTest extends SimpleApplication implements SwapchainUpdater { + + private VulkanInstance instance; + private Surface surface; + private LogicalDevice device; + private Swapchain swapchain; + private ShaderModule vertModule, fragModule; + private PipelineLayout pipelineLayout; + private RenderPass renderPass; + private GraphicsPipeline pipeline; + private CommandPool graphicsPool; + private StageableBuffer vertexBuffer, indexBuffer; + private DescriptorPool descriptorPool; + private DescriptorSetLayout descriptorLayout; + private UpdateFrameManager frames; + private boolean swapchainResizeFlag = false; + private boolean applicationStopped = false; + + // framebuffer + private VulkanImageView depthView; + + // commands + private CommandBatch graphics, perFrameData, sharedData; + private Fence sharedDataFence; + + public static void main(String[] args) { + VulkanHelperTest app = new VulkanHelperTest(); + AppSettings settings = new AppSettings(true); + settings.setFrameRate(0); + settings.setVSync(false); + settings.setWidth(768); + settings.setHeight(768); + settings.setRenderer("CUSTOM" + LwjglVulkanContext.class.getName()); + app.setSettings(settings); + app.setShowSettings(false); + app.start(); + } + + public VulkanHelperTest() { + super(new FlyCamAppState()); + } + + @Override + public void simpleInitApp() { + + assetManager.registerLoader(ShadercLoader.class, "glsl"); + assetManager.registerLoader(VulkanImageLoader.class, "png", "jpg"); + flyCam.setMoveSpeed(5f); + flyCam.setDragToRotate(true); + + long window = ((LwjglVulkanContext)context).getWindowHandle(); + + instance = new VulkanInstance(VK_API_VERSION_1_3); + try (VulkanInstance.Builder i = instance.build()) { + i.addGlfwExtensions(); + i.addDebugExtension(); + i.addLunarGLayer(); + i.setApplicationName(VulkanHelperTest.class.getSimpleName()); + i.setApplicationVersion(1, 0, 0); + } + instance.createLogger(Level.SEVERE); + + // surface + surface = new Surface(instance, window); + + // logical device + device = new LogicalDevice<>(instance); + try (LogicalDevice.Builder d = device.build(id -> new GeneralPhysicalDevice(instance, surface, id))) { + d.addFilter(surface); + d.addFilter(DeviceFilter.swapchain(surface)); + d.addCriticalExtension(KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME); + d.addFeature(DeviceFeature.anisotropy(1f, true)); + } + GeneralPhysicalDevice physDevice = device.getPhysicalDevice(); + + graphicsPool = device.getLongTermPool(physDevice.getGraphics()); + + // swapchain + swapchain = new Swapchain(device, surface); + swapchain.build(s -> { + s.addQueue(physDevice.getGraphics()); + s.addQueue(physDevice.getPresent()); + s.selectFormat(Format.B8G8R8A8_SRGB.getVkEnum(), KHRSurface.VK_COLOR_SPACE_SRGB_NONLINEAR_KHR); + s.selectMode(Swapchain.PresentMode.Mailbox); + s.selectExtentByWindow(); + s.selectImageCount(2); + }); + + // Describes the layout of a descriptor set. The descriptor set + // will represent two uniforms: a uniform buffer at binding 0 + // requiring 1 descriptor, and an image sampler at binding 1 + // requiring 1 descriptor. + descriptorLayout = new DescriptorSetLayout(device, + new SetLayoutBinding(Descriptor.UniformBuffer, 0, 1, ShaderStage.Vertex), + new SetLayoutBinding(Descriptor.CombinedImageSampler, 1, 1, ShaderStage.Fragment)); + descriptorPool = new DescriptorPool(device, 10, + new PoolSize(Descriptor.UniformBuffer, 3), + new PoolSize(Descriptor.StorageBuffer, 4), + new PoolSize(Descriptor.CombinedImageSampler, 2)); + + CommandPool initPool = device.getShortTermPool(physDevice.getGraphics()); + CommandBuffer initCommands = initPool.allocateTransientCommandBuffer(); + initCommands.begin(); + + // depth texture + depthView = createDepthAttachment(initCommands); + + initCommands.endAndSubmit(SyncGroup.ASYNC); + initCommands.getPool().getQueue().waitIdle(); + + // render pass + renderPass = new RenderPass(device); + try (RenderPass.Builder p = renderPass.build()) { + Attachment color = p.createAttachment(swapchain.getFormat(), VK_SAMPLE_COUNT_1_BIT, a -> { + a.setLoad(VulkanImage.Load.Clear); + a.setStore(VulkanImage.Store.Store); + a.setStencilLoad(VulkanImage.Load.DontCare); + a.setStencilStore(VulkanImage.Store.DontCare); + a.setInitialLayout(VulkanImage.Layout.Undefined); + a.setFinalLayout(VulkanImage.Layout.PresentSrc); + }); + Attachment depth = p.createAttachment(depthView.getImage().getFormat(), VK_SAMPLE_COUNT_1_BIT, a -> { + a.setLoad(VulkanImage.Load.Clear); + a.setStore(VulkanImage.Store.DontCare); + a.setStencilLoad(VulkanImage.Load.DontCare); + a.setStencilStore(VulkanImage.Store.DontCare); + a.setInitialLayout(VulkanImage.Layout.Undefined); + a.setFinalLayout(VulkanImage.Layout.DepthStencilAttachmentOptimal); + }); + Subpass subpass = p.createSubpass(PipelineBindPoint.Graphics, s -> { + s.addColorAttachment(color.createReference(VulkanImage.Layout.ColorAttachmentOptimal)); + s.setDepthStencilAttachment(depth.createReference(VulkanImage.Layout.DepthStencilAttachmentOptimal)); + }); + p.createDependency(null, subpass, d -> { + d.setSrcStageMask(Flag.of(PipelineStage.ColorAttachmentOutput, PipelineStage.EarlyFragmentTests)); + d.setSrcAccessMask(Flag.of(subpass.getPosition())); + d.setDstStageMask(Flag.of(PipelineStage.ColorAttachmentOutput, PipelineStage.EarlyFragmentTests)); + d.setDstAccessMask(Flag.of(Access.ColorAttachmentWrite, Access.DepthStencilAttachmentWrite)); + }); + } + swapchain.createFrameBuffers(renderPass, depthView); + + // mesh description + MeshDescription meshDesc = new MeshDescription(); + int meshBinding0 = meshDesc.addAttribute(BuiltInAttribute.Position, InputRate.Vertex, Format.RGB32SFloat, 0); + meshDesc.addAttribute(BuiltInAttribute.TexCoord, meshBinding0, Format.RG32SFloat, 1); + meshDesc.addAttribute(BuiltInAttribute.Normal, meshBinding0, Format.RGB32SFloat, 2); + + // pipeline + pipelineLayout = new PipelineLayout(device, descriptorLayout); + vertModule = new ShaderModule(device, assetManager.loadAsset(ShadercLoader.key( + "Shaders/VulkanVertTest.glsl", ShaderType.Vertex))); + fragModule = new ShaderModule(device, assetManager.loadAsset(ShadercLoader.key( + "Shaders/VulkanFragTest.glsl", ShaderType.Fragment))); + pipeline = new GraphicsPipeline(device, pipelineLayout, renderPass, 0); + try (GraphicsPipeline.Builder p = pipeline.build()) { + p.addShader(vertModule, ShaderStage.Vertex, "main"); + p.addShader(fragModule, ShaderStage.Fragment, "main"); + p.getVertexInput().setMesh(meshDesc); + p.getRasterization().setCullMode(CullMode.None); + p.getViewportState().addViewport(); + p.getViewportState().addScissor(); + p.getColorBlend().addAttachment(new ColorBlendAttachment()); + p.getDynamicState().addTypes(DynamicState.Type.ViewPort, DynamicState.Type.Scissor); + } + + frames = new UpdateFrameManager(2, n -> new Frame()); + + // material color texture + VulkanImage image = assetManager.loadAsset(VulkanImageLoader.key(initPool, "Common/Textures/MissingTexture.png")); + VulkanImageView imgView = new VulkanImageView(image, ImageView.Type.TwoDemensional); + try (VulkanImageView.Builder i = imgView.build()) { + i.setAspect(VulkanImage.Aspect.Color); + } + // material + VulkanTexture texture = new VulkanTexture(device, imgView); + try (Sampler.Builder t = texture.build()) { + t.setMinMagFilters(Filter.Linear, Filter.Linear); + t.setEdgeModes(AddressMode.Repeat); + t.setMipmapMode(MipmapMode.Linear); + } + + graphics = new BasicCommandBatch(); + perFrameData = new BasicCommandBatch(); + sharedData = new BasicCommandBatch(); + sharedDataFence = new Fence(device, true); + + TestMaterial material = new TestMaterial(descriptorPool); + material.getBaseColorMap().setResource(new SingleResource<>(texture)); + + Mesh m = new MyCustomMesh(device, frames, meshDesc, sharedData, + Vector3f.UNIT_Z, Vector3f.UNIT_Y, 1f, 1f, 0.5f, 0.5f); + MatrixTransformMaterial t = new MatrixTransformMaterial(descriptorPool); + t.getTransforms().setResource(frames.perFrame(n -> + new PersistentBuffer(device, MemorySize.floats(16), BufferUsage.Uniform, false))); + Geometry geometry = new Geometry("geometry", m, t); + geometry.setMaterial(material); + rootNode.attachChild(geometry); + + } + + @Override + public void stop() { + applicationStopped = true; + device.waitIdle(); + Native.get().clear(); // destroy all native objects + super.stop(); + } + + @Override + public boolean swapchainOutOfDate(Swapchain swapchain, int imageAcquireCode) { + if (swapchainResizeFlag || imageAcquireCode == KHRSwapchain.VK_ERROR_OUT_OF_DATE_KHR + || imageAcquireCode == KHRSwapchain.VK_SUBOPTIMAL_KHR) { + swapchainResizeFlag = false; +// try (Swapchain.Builder s = swapchain.build()) { +// s.addQueue(device.getPhysicalDevice().getGraphics()); +// s.addQueue(device.getPhysicalDevice().getPresent()); +// s.selectFormat(Format.B8G8R8A8_SRGB.getVkEnum(), KHRSurface.VK_COLOR_SPACE_SRGB_NONLINEAR_KHR); +// s.selectMode(Swapchain.PresentMode.Mailbox); +// s.selectExtentByWindow(); +// s.selectImageCount(2); +// } + CommandBuffer cmd = device.getShortTermPool(device.getPhysicalDevice().getGraphics()).allocateTransientCommandBuffer(); + cmd.begin(); + depthView = createDepthAttachment(cmd); + cmd.endAndSubmit(SyncGroup.ASYNC); + cmd.getPool().getQueue().waitIdle(); + swapchain.createFrameBuffers(renderPass, depthView); + return true; + } + if (imageAcquireCode != VK_SUCCESS) { + throw new RuntimeException("Failed to acquire swapchain image."); + } + return false; + } + + @Override + public void reshape(int w, int h) { + swapchainResizeFlag = true; + } + + @Override + public void simpleUpdate(float tpf) { + frames.update(tpf); + } + + private VulkanImageView createDepthAttachment(CommandBuffer cmd) { + Format depthFormat = device.getPhysicalDevice().findSupportedFormat( + VulkanImage.Tiling.Optimal, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, + Format.Depth32SFloat, Format.Depth32SFloat_Stencil8UInt, Format.Depth24UNorm_Stencil8UInt); + BasicVulkanImage image = new BasicVulkanImage(device, VulkanImage.Type.TwoDemensional); + try (BasicVulkanImage.Builder i = image.build()) { + i.setSize(swapchain.getExtent().x, swapchain.getExtent().y); + i.setFormat(depthFormat); + i.setTiling(VulkanImage.Tiling.Optimal); + i.setUsage(ImageUsage.DepthStencilAttachment); + i.setMemoryProps(MemoryProp.DeviceLocal); + } + VulkanImageView view = new VulkanImageView(image, ImageView.Type.TwoDemensional); + try (VulkanImageView.Builder v = view.build()) { + v.allMipmaps(); + v.setAspect(VulkanImage.Aspect.Depth); + } + image.transitionLayout(cmd, VulkanImage.Layout.Undefined, VulkanImage.Layout.DepthStencilAttachmentOptimal); + return view; + } + + private class Frame implements UpdateFrame { + + // render manager + private final CommandBuffer perFrameDataCommands = graphicsPool.allocateCommandBuffer(); + private final CommandBuffer sharedDataCommands = graphicsPool.allocateCommandBuffer(); + private final CommandBuffer graphicsCommands = graphicsPool.allocateCommandBuffer(); + private final Semaphore imageAvailable = new Semaphore(device, PipelineStage.ColorAttachmentOutput); + private final Semaphore perFrameDataFinished = new Semaphore(device, PipelineStage.TopOfPipe); + private final Semaphore sharedDataFinished = new Semaphore(device, PipelineStage.TopOfPipe); + private final Semaphore renderFinished = new Semaphore(device); + private final Fence inFlight = new Fence(device, true); + + @Override + public void update(UpdateFrameManager frames, float tpf) { + + // block until this frame has fully completed previous rendering commands + if (applicationStopped) return; + inFlight.block(5000); + if (applicationStopped) return; + + // get swapchain image to present with + Swapchain.PresentImage image = swapchain.acquireNextImage(VulkanHelperTest.this, imageAvailable, null, 5000); + if (image == null) { + return; // no image available: skip rendering this frame + } + inFlight.reset(); + + // set camera to render with + renderManager.setCamera(cam, false); + + // update matrix uniform (geometry) + for (Spatial s : rootNode) { + if (s instanceof Geometry) { + ((Geometry)s).updateTransformMaterial(cam); + } + } + + // update shared data + { + sharedDataFence.block(5000); + sharedDataCommands.resetAndBegin(); + SyncGroup dataSync = sharedDataFinished.toGroupSignal(); + if (sharedData.run(sharedDataCommands, frames.getCurrentFrame())) { + sharedDataFence.reset(); + dataSync.setFence(sharedDataFence); // force the next frame to wait + } + sharedDataCommands.endAndSubmit(dataSync); + } + + // update per-frame data + { + perFrameDataCommands.resetAndBegin(); + perFrameData.run(perFrameDataCommands, frames.getCurrentFrame()); + perFrameDataCommands.endAndSubmit(perFrameDataFinished.toGroupSignal()); + } + + // begin graphics commands + graphicsCommands.resetAndBegin(); + + // material graphics + renderPass.begin(graphicsCommands, image.getFrameBuffer()); + pipeline.bind(graphicsCommands); + + // viewport and scissor + try (MemoryStack stack = MemoryStack.stackPush()) { + VkViewport.Buffer vp = VkViewport.calloc(1, stack) + .x(0f).y(0f) + .width(swapchain.getExtent().getX()) + .height(swapchain.getExtent().getY()) + .minDepth(0f).maxDepth(1f); + vkCmdSetViewport(graphicsCommands.getBuffer(), 0, vp); + VkRect2D.Buffer scissor = VkRect2D.calloc(1, stack); + scissor.offset().set(0, 0); + scissor.extent(swapchain.getExtent().toStruct(stack)); + vkCmdSetScissor(graphicsCommands.getBuffer(), 0, scissor); + } + + // run graphics commands via CommandBatch + graphics.run(graphicsCommands, frames.getCurrentFrame()); + + // draw all geometries in the rootNode + for (Spatial s : rootNode) { + if (s instanceof Geometry) { + Geometry g = (Geometry)s; + g.draw(graphicsCommands, pipeline); + } + } + + // material + renderPass.end(graphicsCommands); + + // render manager + graphicsCommands.endAndSubmit(new SyncGroup(new Semaphore[] + {imageAvailable, perFrameDataFinished, sharedDataFinished}, renderFinished, inFlight)); + swapchain.present(device.getPhysicalDevice().getPresent(), image, renderFinished.toGroupWait()); + + } + + } + +} diff --git a/jme3-examples/src/main/java/jme3test/water/TestMultiPostWater.java b/jme3-examples/src/main/java/jme3test/water/TestMultiPostWater.java index 2784d59fa1..f71cabd154 100644 --- a/jme3-examples/src/main/java/jme3test/water/TestMultiPostWater.java +++ b/jme3-examples/src/main/java/jme3test/water/TestMultiPostWater.java @@ -47,8 +47,8 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; @@ -166,24 +166,24 @@ private void createTerrain(Node rootNode) { matRock.setBoolean("useTriPlanarMapping", false); matRock.setBoolean("WardIso", true); matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/pools.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/pools.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap", grass); matRock.setFloat("DiffuseMap_0_scale", 64); - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_1", dirt); matRock.setFloat("DiffuseMap_1_scale", 16); - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_2", rock); matRock.setFloat("DiffuseMap_2_scale", 128); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMap0.setWrap(WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMap1.setWrap(WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMap2.setWrap(WrapMode.Repeat); matRock.setTexture("NormalMap", normalMap0); matRock.setTexture("NormalMap_1", normalMap1); diff --git a/jme3-examples/src/main/java/jme3test/water/TestPostWater.java b/jme3-examples/src/main/java/jme3test/water/TestPostWater.java index 7f6117bc0c..08d3d8cc7b 100644 --- a/jme3-examples/src/main/java/jme3test/water/TestPostWater.java +++ b/jme3-examples/src/main/java/jme3test/water/TestPostWater.java @@ -61,8 +61,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; @@ -231,7 +231,7 @@ private void createWaterFilter() { private void createTerrain(Node mainScene) { Material matRock = createTerrainMaterial(); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); AbstractHeightMap heightmap = null; try { heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); @@ -276,7 +276,7 @@ private Material createTerrainMaterial() { } private void setTexture(String texture, Material mat, String param) { - Texture tex = assetManager.loadTexture(texture); + GlTexture tex = assetManager.loadTexture(texture); tex.setWrap(WrapMode.Repeat); mat.setTexture(param, tex); } diff --git a/jme3-ios/src/main/java/com/jme3/system/ios/IosImageLoader.java b/jme3-ios/src/main/java/com/jme3/system/ios/IosImageLoader.java index 07a881ee5f..0a9fa89461 100644 --- a/jme3-ios/src/main/java/com/jme3/system/ios/IosImageLoader.java +++ b/jme3-ios/src/main/java/com/jme3/system/ios/IosImageLoader.java @@ -34,8 +34,8 @@ import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetLoader; import com.jme3.asset.TextureKey; -import com.jme3.texture.Image; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; import java.io.IOException; import java.io.InputStream; @@ -48,7 +48,7 @@ public class IosImageLoader implements AssetLoader { @Override public Object load(AssetInfo info) throws IOException { boolean flip = ((TextureKey) info.getKey()).isFlipY(); - Image img = null; + GlImage img = null; InputStream in = null; try { in = info.openStream(); @@ -68,5 +68,5 @@ public Object load(AssetInfo info) throws IOException { * @param inputStream the InputStream to load the image data from * @return the loaded Image */ - private static native Image loadImageData(Format format, boolean flipY, InputStream inputStream); + private static native GlImage loadImageData(Format format, boolean flipY, InputStream inputStream); } diff --git a/jme3-jbullet/src/main/java/com/jme3/bullet/animation/RagUtils.java b/jme3-jbullet/src/main/java/com/jme3/bullet/animation/RagUtils.java index 0a51b894e8..d92217a14b 100644 --- a/jme3-jbullet/src/main/java/com/jme3/bullet/animation/RagUtils.java +++ b/jme3-jbullet/src/main/java/com/jme3/bullet/animation/RagUtils.java @@ -98,7 +98,7 @@ private RagUtils() { * @return a new map from bone/torso names to sets of vertex coordinates */ static Map coordsMap(Mesh[] meshes, - String[] managerMap) { + String[] managerMap) { float[] wArray = new float[4]; int[] iArray = new int[4]; Vector3f bindPosition = new Vector3f(); @@ -218,7 +218,7 @@ static Joint findMainBone(Armature skeleton, Mesh[] targetMeshes) { * @return an expanded list (either storeResult or a new instance) */ static List listAnimatedMeshes(Spatial subtree, - List storeResult) { + List storeResult) { if (storeResult == null) { storeResult = new ArrayList<>(10); } @@ -440,7 +440,7 @@ private static void addWeights(Mesh mesh, float[] totalWeights) { * @return a bone/torso name */ private static String findManager(Mesh mesh, int vertexIndex, int[] iArray, - float[] wArray, String[] managerMap) { + float[] wArray, String[] managerMap) { vertexBoneIndices(mesh, vertexIndex, iArray); vertexBoneWeights(mesh, vertexIndex, wArray); Map weightMap = weightMap(iArray, wArray, managerMap); @@ -569,7 +569,7 @@ private static float[] totalWeights(Mesh[] meshes, Armature skeleton) { * @return the data vector (either storeResult or a new instance) */ private static int[] vertexBoneIndices(Mesh mesh, - int vertexIndex, int[] storeResult) { + int vertexIndex, int[] storeResult) { if (storeResult == null) { storeResult = new int[4]; } else { @@ -608,7 +608,7 @@ private static int[] vertexBoneIndices(Mesh mesh, * @return the data vector (either storeResult or a new instance) */ private static float[] vertexBoneWeights(Mesh mesh, - int vertexIndex, float[] storeResult) { + int vertexIndex, float[] storeResult) { if (storeResult == null) { storeResult = new float[4]; } else { @@ -651,8 +651,8 @@ private static float[] vertexBoneWeights(Mesh mesh, * @return the data vector (either storeResult or a new instance) */ private static Vector3f vertexVector3f(Mesh mesh, - VertexBuffer.Type bufferType, int vertexIndex, - Vector3f storeResult) { + VertexBuffer.Type bufferType, int vertexIndex, + Vector3f storeResult) { assert bufferType == VertexBuffer.Type.BindPoseNormal || bufferType == VertexBuffer.Type.BindPosePosition || bufferType == VertexBuffer.Type.Binormal diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index e95a2a56d0..ac665cc9ec 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -37,7 +37,8 @@ import com.jme3.opencl.Image.ImageFormat; import com.jme3.scene.VertexBuffer; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.List; @@ -163,8 +164,8 @@ public Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access) { } @Override - public Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int mipLevel, MemoryAccess access) { - int imageID = image.getId(); + public Image bindImage(GlImage image, GlTexture.Type textureType, int mipLevel, MemoryAccess access) { + int imageID = image.getNativeObject(); if (imageID == -1) { throw new IllegalArgumentException("image was not yet uploaded to the GPU"); } @@ -189,7 +190,7 @@ protected Image bindPureRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAcce return new LwjglImage(mem); } - private int convertTextureType(Texture.Type textureType) { + private int convertTextureType(GlTexture.Type textureType) { switch (textureType) { case TwoDimensional: return GL11.GL_TEXTURE_2D; case TwoDimensionalArray: return GL30.GL_TEXTURE_2D_ARRAY; diff --git a/jme3-lwjgl3/build.gradle b/jme3-lwjgl3/build.gradle index 5e929e8c2f..efd0863fea 100644 --- a/jme3-lwjgl3/build.gradle +++ b/jme3-lwjgl3/build.gradle @@ -12,6 +12,8 @@ dependencies { api libs.lwjgl3.openal api libs.lwjgl3.opencl api libs.lwjgl3.opengl + api libs.lwjgl3.vulkan + api libs.lwjgl3.shaderc runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-windows') }) runtimeOnly(variantOf(libs.lwjgl3.base){ classifier('natives-windows-x86') }) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java index 980b07527e..a0662f1ff3 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java @@ -35,6 +35,7 @@ import com.jme3.input.KeyInput; import com.jme3.input.RawInputListener; import com.jme3.input.event.KeyInputEvent; +import com.jme3.system.GlfwWindow; import com.jme3.system.lwjgl.LwjglWindow; import java.util.ArrayDeque; import java.util.Queue; @@ -56,9 +57,9 @@ public class GlfwKeyInput implements KeyInput { private final Queue keyInputEvents = new ArrayDeque<>(); /** - * The LWJGL context. + * The GLFW window. */ - private final LwjglWindow context; + private final GlfwWindow context; /** * The key callback. @@ -77,7 +78,7 @@ public class GlfwKeyInput implements KeyInput { private boolean initialized; - public GlfwKeyInput(final LwjglWindow context) { + public GlfwKeyInput(final GlfwWindow context) { this.context = context; } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java index 1aba44d570..94562060f1 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java @@ -37,8 +37,8 @@ import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseMotionEvent; import com.jme3.math.Vector2f; -import com.jme3.system.lwjgl.LwjglWindow; -import com.jme3.system.lwjgl.WindowSizeListener; +import com.jme3.system.GlfwWindow; +import com.jme3.system.WindowSizeListener; import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; import java.nio.IntBuffer; @@ -114,7 +114,7 @@ private static ByteBuffer transformCursorImage(final IntBuffer imageData, final private final Queue mouseMotionEvents = new ArrayDeque<>(); private final Queue mouseButtonEvents = new ArrayDeque<>(); - private final LwjglWindow context; + private final GlfwWindow context; private WindowSizeListener windowSizeListener; private RawInputListener listener; @@ -138,7 +138,7 @@ private static ByteBuffer transformCursorImage(final IntBuffer imageData, final private boolean initialized; private final Vector2f inputScale = new Vector2f(); - public GlfwMouseInput(final LwjglWindow context) { + public GlfwMouseInput(final GlfwWindow context) { this.context = context; this.cursorVisible = true; } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index 8fef7ad1f1..930c4ddb14 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -37,7 +37,8 @@ import com.jme3.opencl.Image.ImageFormat; import com.jme3.scene.VertexBuffer; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.List; @@ -174,9 +175,9 @@ public Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access) { } @Override - public Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int mipLevel, MemoryAccess access) { + public Image bindImage(GlImage image, GlTexture.Type textureType, int mipLevel, MemoryAccess access) { Utils.assertSharingPossible(); - int imageID = image.getId(); + int imageID = image.getNativeObject(); if (imageID == -1) { throw new IllegalArgumentException("image was not yet uploaded to the GPU"); } @@ -202,7 +203,7 @@ protected Image bindPureRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAcce return new LwjglImage(mem); } - private int convertTextureType(Texture.Type textureType) { + private int convertTextureType(GlTexture.Type textureType) { switch (textureType) { case TwoDimensional: return GL11.GL_TEXTURE_2D; case TwoDimensionalArray: return GL30.GL_TEXTURE_2D_ARRAY; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/shaderc/ShaderType.java b/jme3-lwjgl3/src/main/java/com/jme3/shaderc/ShaderType.java new file mode 100644 index 0000000000..2aff284de9 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/shaderc/ShaderType.java @@ -0,0 +1,37 @@ +package com.jme3.shaderc; + +import org.lwjgl.util.shaderc.Shaderc; +import org.lwjgl.vulkan.VK10; + +public enum ShaderType { + + Vertex(VK10.VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK10.VK_SHADER_STAGE_VERTEX_BIT, Shaderc.shaderc_vertex_shader), + Fragment(VK10.VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK10.VK_SHADER_STAGE_FRAGMENT_BIT, Shaderc.shaderc_fragment_shader), + Tessellation(VK10.VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK10.VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, Shaderc.shaderc_tess_evaluation_shader), + TessellationControl(VK10.VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK10.VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, Shaderc.shaderc_tess_control_shader), + Geometry(VK10.VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK10.VK_SHADER_STAGE_GEOMETRY_BIT, Shaderc.shaderc_geometry_shader), + Compute(VK10.VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK10.VK_SHADER_STAGE_COMPUTE_BIT, Shaderc.shaderc_compute_shader); + + private final int vulkanPipeline; + private final int vulkanShader; + private final int shaderc; + + ShaderType(int vulkanPipeline, int vulkanShader, int shaderc) { + this.vulkanPipeline = vulkanPipeline; + this.vulkanShader = vulkanShader; + this.shaderc = shaderc; + } + + public int getVulkanPipeline() { + return vulkanPipeline; + } + + public int getVulkanShader() { + return vulkanShader; + } + + public int getShaderc() { + return shaderc; + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/shaderc/ShadercLoader.java b/jme3-lwjgl3/src/main/java/com/jme3/shaderc/ShadercLoader.java new file mode 100644 index 0000000000..8ffce7d8c8 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/shaderc/ShadercLoader.java @@ -0,0 +1,136 @@ +package com.jme3.shaderc; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetLoader; +import com.jme3.util.natives.Native; +import com.jme3.util.natives.NativeReference; +import jme3tools.shader.ShaderDebug; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.util.shaderc.Shaderc; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.ByteBuffer; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.system.MemoryUtil.NULL; + +public class ShadercLoader implements AssetLoader { + + private static final Logger LOG = Logger.getLogger(ShadercLoader.class.getName()); + private static final Compiler compiler = new Compiler(); + + @Override + public Object load(AssetInfo assetInfo) throws IOException { + if (!(assetInfo.getKey() instanceof Key)) { + throw new IllegalArgumentException("Requires " + Key.class.getName()); + } + Key key = (Key)assetInfo.getKey(); + try (InputStream in = assetInfo.openStream()) { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder code = new StringBuilder(); + for (String line; (line = reader.readLine()) != null; ) { + code.append(line).append('\n'); + } + return compile(key.getName(), code.toString(), key.getShaderType(), key.getEntryPoint()); + } + } + + public static ByteBuffer compile(String name, String code, ShaderType type, String entry) { + synchronized (compiler) { try (MemoryStack stack = MemoryStack.stackPush()) { + long preprocessed = Shaderc.shaderc_compile_into_preprocessed_text(compiler.getNativeObject(), code, + type.getShaderc(), name, entry, NULL); + handleCompileCodes(preprocessed, name, code); + ByteBuffer bytecode = Objects.requireNonNull(Shaderc.shaderc_result_get_bytes(preprocessed)); + long compiled = Shaderc.shaderc_compile_into_spv(compiler.getNativeObject(), bytecode, + type.getShaderc(), stack.UTF8(name), stack.UTF8(entry), NULL); + handleCompileCodes(compiled, name, code); + return Shaderc.shaderc_result_get_bytes(compiled); + }} + } + + private static void handleCompileCodes(long result, String name, String code) { + int status = Shaderc.shaderc_result_get_compilation_status(result); + if (status != Shaderc.shaderc_compilation_status_success) { + LOG.log(Level.SEVERE, "Bad compile of\n{0}", ShaderDebug.formatShaderSource(code)); + throw new RuntimeException("Failed to compile " + name + ":\n" + + Shaderc.shaderc_result_get_error_message(result)); + } + long warnings = Shaderc.shaderc_result_get_num_warnings(result); + if (warnings > 0) { + LOG.warning("Compiled with " + warnings + " warning" + (warnings == 1 ? "" : "s") + ": " + name); + } else { + LOG.fine("Compiled with no warnings: " + name); + } + } + + public static AssetKey key(String name, ShaderType type) { + return new Key(name, type, "main"); + } + + public static AssetKey key(String name, ShaderType type, String entry) { + return new Key(name, type, entry); + } + + private static class Compiler implements Native { + + private final NativeReference ref; + private long id; + + private Compiler() { + id = Shaderc.shaderc_compiler_initialize(); + if (id == NULL) { + throw new NullPointerException("Unable to initialize Shaderc compiler."); + } + ref = Native.get().register(this); + } + + @Override + public Long getNativeObject() { + return id; + } + + @Override + public Runnable createNativeDestroyer() { + return () -> Shaderc.shaderc_compiler_release(id); + } + + @Override + public void prematureNativeDestruction() { + id = NULL; + } + + @Override + public NativeReference getNativeReference() { + return ref; + } + + } + + public static class Key extends AssetKey { + + private final ShaderType shaderType; + private final String entryPoint; + + public Key(String name, ShaderType shaderType, String entryPoint) { + super(name); + this.shaderType = shaderType; + this.entryPoint = entryPoint; + } + + public ShaderType getShaderType() { + return shaderType; + } + + public String getEntryPoint() { + return entryPoint; + } + + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/GlfwWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/GlfwWindow.java new file mode 100644 index 0000000000..e18f38f0d8 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/GlfwWindow.java @@ -0,0 +1,17 @@ +package com.jme3.system; + +import com.jme3.math.Vector2f; + +public interface GlfwWindow { + + long getWindowHandle(); + + Vector2f getWindowContentScale(Vector2f store); + + boolean isRenderable(); + + void registerWindowSizeListener(WindowSizeListener listener); + + void removeWindowSizeListener(WindowSizeListener listener); + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/Sync.java b/jme3-lwjgl3/src/main/java/com/jme3/system/Sync.java similarity index 99% rename from jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/Sync.java rename to jme3-lwjgl3/src/main/java/com/jme3/system/Sync.java index 3161f00a9b..6c0200c5ca 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/Sync.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/Sync.java @@ -29,7 +29,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.system.lwjgl; +package com.jme3.system; /** * A highly accurate sync method that continually adapts to the system @@ -38,7 +38,7 @@ * @author Riven * @author kappaOne */ -class Sync { +public class Sync { /** number of nanoseconds in a second */ private static final long NANOS_IN_SECOND = 1000L * 1000L * 1000L; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/WindowSizeListener.java b/jme3-lwjgl3/src/main/java/com/jme3/system/WindowSizeListener.java similarity index 97% rename from jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/WindowSizeListener.java rename to jme3-lwjgl3/src/main/java/com/jme3/system/WindowSizeListener.java index 2d2105b802..b3b687f0fc 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/WindowSizeListener.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/WindowSizeListener.java @@ -29,7 +29,9 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.system.lwjgl; +package com.jme3.system; + +import com.jme3.system.lwjgl.LwjglWindow; /** * Listen to window size changes. Note, GLFW does not support registering multiple callbacks diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index 03085401a7..6a24633944 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -43,21 +43,15 @@ import com.jme3.input.lwjgl.GlfwKeyInput; import com.jme3.input.lwjgl.GlfwMouseInput; import com.jme3.math.Vector2f; -import com.jme3.system.AppSettings; -import com.jme3.system.Displays; -import com.jme3.system.JmeContext; -import com.jme3.system.JmeSystem; -import com.jme3.system.NanoTimer; +import com.jme3.system.*; import com.jme3.util.BufferUtils; import com.jme3.util.SafeArrayList; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; -import java.nio.IntBuffer; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -76,7 +70,7 @@ * * @author Daniel Johansson */ -public abstract class LwjglWindow extends LwjglContext implements Runnable { +public abstract class LwjglWindow extends LwjglContext implements Runnable, GlfwWindow { private static final Logger LOGGER = Logger.getLogger(LwjglWindow.class.getName()); @@ -212,6 +206,7 @@ public LwjglWindow(final JmeContext.Type type) { * * @param listener The WindowSizeListener to register. */ + @Override public void registerWindowSizeListener(WindowSizeListener listener) { windowSizeListeners.add(listener); } @@ -221,6 +216,7 @@ public void registerWindowSizeListener(WindowSizeListener listener) { * * @param listener The WindowSizeListener to remove. */ + @Override public void removeWindowSizeListener(WindowSizeListener listener) { windowSizeListeners.remove(listener); } @@ -863,6 +859,7 @@ public void destroy(boolean waitFor) { } } + @Override public long getWindowHandle() { return window; } @@ -880,6 +877,7 @@ public long getWindowHandle() { * @return The window content scale * @see Window content scale */ + @Override public Vector2f getWindowContentScale(Vector2f store) { if (store == null) store = new Vector2f(); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/vulkan/LwjglVulkanContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/vulkan/LwjglVulkanContext.java new file mode 100644 index 0000000000..d72b629447 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/vulkan/LwjglVulkanContext.java @@ -0,0 +1,457 @@ +package com.jme3.system.vulkan; + +import com.jme3.input.JoyInput; +import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; +import com.jme3.input.TouchInput; +import com.jme3.input.lwjgl.GlfwJoystickInput; +import com.jme3.input.lwjgl.GlfwKeyInput; +import com.jme3.input.lwjgl.GlfwMouseInput; +import com.jme3.math.Vector2f; +import com.jme3.opencl.Context; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.vulkan.VulkanRenderer; +import com.jme3.system.*; +import com.jme3.system.Sync; +import com.jme3.system.WindowSizeListener; +import org.lwjgl.PointerBuffer; +import org.lwjgl.glfw.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.lwjgl.system.MemoryUtil.NULL; +import static org.lwjgl.glfw.GLFW.*; + +public class LwjglVulkanContext implements JmeContext, GlfwWindow, Runnable { + + private static final Logger LOGGER = Logger.getLogger(LwjglVulkanContext.class.getName()); + + private long window = NULL; + private SystemListener engine; + private VulkanRenderer renderer; + private Thread engineThread; + private Timer engineTimer; + private final AtomicBoolean created = new AtomicBoolean(false); + private final AtomicBoolean destroy = new AtomicBoolean(false); + private final AtomicBoolean restart = new AtomicBoolean(false); + private final AtomicBoolean focused = new AtomicBoolean(true); + private final AppSettings settings = new AppSettings(true); + private final Collection sizeListeners = new ArrayList<>(); + private final Vector2f windowScale = new Vector2f(1, 1); + private int frameBufferWidth, frameBufferHeight; + + private GLFWErrorCallback errorCallback; + private GLFWWindowFocusCallback focusCallback; + private GLFWWindowSizeCallback sizeCallback; + private GLFWFramebufferSizeCallback fbSizeCallback; + + private GlfwMouseInput mouseInput; + private GlfwKeyInput keyInput; + private JoyInput joyInput; + + private final int[] width = new int[1]; + private final int[] height = new int[1]; + + private boolean autoFlush = true; + + @Override + public void run() { + engineInitialize(); + engineLoop(); + engineTerminate(); + } + + @Override + public void create(boolean waitFor) { + (engineThread = new Thread(this, getClass().getSimpleName())).start(); + if (waitFor) { + waitForContextLifeEvent(true); + } + } + + protected void waitForContextLifeEvent(boolean creation) { + synchronized (created) { + while (created.get() != creation) try { + created.wait(); + } catch (InterruptedException ignored) {} + } + } + + protected void engineInitialize() { + glfwInitialize(); + rendererInitialize(); + engineTimer = new NanoTimer(); + engine.initialize(); + synchronized (created) { + created.set(true); + created.notifyAll(); + } + } + + protected void glfwInitialize() { + glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() { + @Override + public void invoke(int error, long description) { + final String message = GLFWErrorCallback.getDescription(description); + engine.handleError(message, new Exception(message)); + } + }); + if (glfwPlatformSupported(GLFW_PLATFORM_WAYLAND)) { + // Disables the libdecor bar when creating a fullscreen context + // https://www.glfw.org/docs/latest/intro_guide.html#init_hints_wayland + glfwInitHint(GLFW_WAYLAND_LIBDECOR, settings.isFullscreen() ? GLFW_WAYLAND_DISABLE_LIBDECOR : GLFW_WAYLAND_PREFER_LIBDECOR); + } + glfwInit(); + if (!GLFWVulkan.glfwVulkanSupported()) { + throw new NullPointerException("Hardware does not support Vulkan."); + } + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + window = glfwCreateWindow(getSettings().getWidth(), getSettings().getHeight(), getSettings().getTitle(), NULL, NULL); + glfwSetWindowFocusCallback(window, focusCallback = new GLFWWindowFocusCallback() { + @Override + public void invoke(long window, boolean focus) { + if (focus != focused.get()) { + if (!focus) { + engine.loseFocus(); + } else { + engine.gainFocus(); + engineTimer.reset(); + } + focused.set(focus); + } + } + }); + glfwSetWindowSizeCallback(window, sizeCallback = new GLFWWindowSizeCallback() { + @Override + public void invoke(final long window, final int width, final int height) { + updateSizes(); + } + }); + glfwSetFramebufferSizeCallback(window, fbSizeCallback = new GLFWFramebufferSizeCallback() { + @Override + public void invoke(final long window, final int width, final int height) { + updateSizes(); + } + }); + } + + protected void rendererInitialize() { + renderer = new VulkanRenderer(); + } + + protected void engineLoop() { + while (true) { + if (restart.get()) { + restartContext(); + } + engine.update(); + if (renderer != null) { + renderer.postFrame(); + } + syncFrames(); + glfwPollEvents(); + if (destroy.get()) { + break; + } + if (glfwWindowShouldClose(window)) { + engine.requestClose(false); + } + } + } + + protected void syncFrames() { + if (autoFlush) { + Sync.sync(getSettings().getFrameRate()); + } else { + Sync.sync(20); + } + } + + protected void engineTerminate() { + System.out.println("terminate engine"); + engine.destroy(); + //glfwDestroyWindow(window); + glfwDestroy(); + glfwTerminate(); + System.out.println("Engine termination complete. Have a nice day."); + } + + protected void updateSizes() { + // framebuffer size (resolution) may differ from window size (e.g. HiDPI) + // resize window informants + glfwGetWindowSize(window, width, height); + int w = Math.max(width[0], 1); + int h = Math.max(height[0], 1); + if (settings.getWindowWidth() != w || settings.getWindowHeight() != h) { + settings.setWindowSize(w, h); + for (WindowSizeListener l : sizeListeners) { + l.onWindowSizeChanged(w, h); + } + } + // resize framebuffer informants + glfwGetFramebufferSize(window, width, height); + if (width[0] != frameBufferWidth || height[0] != frameBufferHeight) { + settings.setResolution(width[0], height[0]); + engine.reshape(width[0], height[0]); + frameBufferWidth = width[0]; + frameBufferHeight = height[0]; + } + // rescale engine + float xScale = (float)width[0] / w; + float yScale = (float)height[0] / h; + if (windowScale.x != xScale || windowScale.y != yScale) { + engine.rescale(xScale, yScale); + windowScale.set(xScale, yScale); + } + } + + protected void restartContext() { + try { + glfwDestroy(); + glfwInitialize(); + } catch (Exception ex) { + LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex); + } + // Reinitialize context flags and such + rendererInitialize(); + + // We need to reinit the mouse and keyboard input as they are tied to a window handle + if (keyInput != null && keyInput.isInitialized()) { + keyInput.resetContext(); + } + if (mouseInput != null && mouseInput.isInitialized()) { + mouseInput.resetContext(); + } + + LOGGER.fine("Display restarted."); + } + + protected void glfwDestroy() { + try { + if (renderer != null) { + renderer.cleanup(); + } + if (errorCallback != null) { + // We need to specifically set this to null as we might set a new callback before we reinit GLFW + glfwSetErrorCallback(null); + errorCallback.close(); + errorCallback = null; + } + if (sizeCallback != null) { + sizeCallback.close(); + sizeCallback = null; + } + if (fbSizeCallback != null) { + fbSizeCallback.close(); + fbSizeCallback = null; + } + if (focusCallback != null) { + focusCallback.close(); + focusCallback = null; + } + if (window != NULL) { + glfwDestroyWindow(window); + window = NULL; + } + } catch (final Exception ex) { + engine.handleError("Failed to destroy context", ex); + } + } + + @Override + public Type getType() { + return Type.Display; + } + + @Override + public void setSettings(AppSettings settings) { + this.settings.copyFrom(settings); + } + + @Override + public SystemListener getSystemListener() { + return engine; + } + + @Override + public void setSystemListener(SystemListener listener) { + this.engine = listener; + } + + @Override + public AppSettings getSettings() { + return settings; + } + + @Override + public Renderer getRenderer() { + return renderer; + } + + @Override + public Context getOpenCLContext() { + return null; + } + + @Override + public MouseInput getMouseInput() { + if (mouseInput == null) { + mouseInput = new GlfwMouseInput(this); + } + return mouseInput; + } + + @Override + public KeyInput getKeyInput() { + if (keyInput == null) { + keyInput = new GlfwKeyInput(this); + } + return keyInput; + } + + @Override + public JoyInput getJoyInput() { + if (joyInput == null) { + joyInput = new GlfwJoystickInput(); + } + return joyInput; + } + + @Override + public TouchInput getTouchInput() { + return null; + } + + @Override + public Timer getTimer() { + return engineTimer; + } + + @Override + public void setTitle(String title) { + if (window != NULL) { + glfwSetWindowTitle(window, title); + } + } + + @Override + public boolean isCreated() { + return created.get(); + } + + @Override + public long getWindowHandle() { + return window; + } + + @Override + public Vector2f getWindowContentScale(Vector2f store) { + if (store == null) store = new Vector2f(); + glfwGetFramebufferSize(window, width, height); + store.set(width[0], height[0]); + glfwGetWindowSize(window, width, height); + store.x /= width[0]; + store.y /= height[0]; + return store; + } + + @Override + public boolean isRenderable() { + return renderer != null; + } + + @Override + public void registerWindowSizeListener(WindowSizeListener listener) { + sizeListeners.add(listener); + } + + @Override + public void removeWindowSizeListener(WindowSizeListener listener) { + sizeListeners.remove(listener); + } + + @Override + public void setAutoFlushFrames(boolean enabled) { + autoFlush = enabled; + } + + @Override + public void restart() { + if (created.get()) { + restart.set(true); + } else { + LOGGER.warning("Cannot restart context: not yet initialized."); + } + } + + @Override + public void destroy(boolean waitFor) { + destroy.set(true); + if (Thread.currentThread() != engineThread) { + waitForContextLifeEvent(false); + } + } + + @Override + public int getFramebufferHeight() { + glfwGetFramebufferSize(window, width, height); + return width[0]; + } + + @Override + public int getFramebufferWidth() { + glfwGetFramebufferSize(window, width, height); + return height[0]; + } + + @Override + public int getWindowXPosition() { + glfwGetWindowPos(window, width, height); + return width[0]; + } + + @Override + public int getWindowYPosition() { + glfwGetWindowPos(window, width, height); + return height[0]; + } + + @Override + public Displays getDisplays() { + PointerBuffer displays = glfwGetMonitors(); + long primary = glfwGetPrimaryMonitor(); + Displays displayList = new Displays(); + + for (int i = 0; i < displays.limit(); i++) { + long monitorI = displays.get(i); + int monPos = displayList.addNewMonitor(monitorI); + if (primary == monitorI) displayList.setPrimaryDisplay(monPos); + final GLFWVidMode modes = glfwGetVideoMode(monitorI); + String name = glfwGetMonitorName(monitorI); + int width = modes.width(); + int height = modes.height(); + int rate = modes.refreshRate(); + displayList.setInfo(monPos, name, width, height, rate); + LOGGER.log(Level.INFO, "Display id: " + monitorI + " Resolution: " + width + " x " + height + " @ " + rate); + } + return displayList; + } + + @Override + public int getPrimaryDisplay() { + long prim = glfwGetPrimaryMonitor(); + Displays monitors = getDisplays(); + for (int i = 0; i < monitors.size(); i++) { + long monitorI = monitors.get(i).getDisplay(); + if (monitorI == prim) return i; + } + LOGGER.log(Level.SEVERE, "Couldn't locate Primary Monitor in the list of Monitors."); + return -1; + } + +} diff --git a/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java b/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java index 4d08588759..6f1d21d041 100644 --- a/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java +++ b/jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java @@ -44,9 +44,10 @@ import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Usage; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ColorSpace; import com.jme3.texture.image.ImageRaster; @@ -223,11 +224,11 @@ public Image loadImage(final String filename) { // Fix GLES format incompatibility issue with glTexSubImage Renderer renderer = display.getRenderer(); if (renderer == null || renderer.getCaps().contains(Caps.OpenGLES20)) { - if (texture.getImage().getFormat() != Format.RGBA8) { - com.jme3.texture.Image sourceImage = texture.getImage(); + if (texture.getImage().getGlFormat() != Format.RGBA8) { + GlImage sourceImage = texture.getImage(); int size = sourceImage.getWidth() * sourceImage.getHeight() * 4; ByteBuffer buffer = BufferUtils.createByteBuffer(size); - com.jme3.texture.Image rgba8Image = new com.jme3.texture.Image(Format.RGBA8, + GlImage rgba8Image = new GlImage(Format.RGBA8, sourceImage.getWidth(), sourceImage.getHeight(), buffer, @@ -250,7 +251,7 @@ public Image loadImage(final String filename) { @Override public Image loadImage(final ByteBuffer imageData, final int imageWidth, final int imageHeight) { - return new ImageImpl(new com.jme3.texture.Image(Format.RGBA8, imageWidth, imageHeight, imageData, ColorSpace.Linear)); + return new ImageImpl(new GlImage(Format.RGBA8, imageWidth, imageHeight, imageData, ColorSpace.Linear)); } @Override @@ -334,7 +335,7 @@ public void removeImageFromAtlas(final Image image, final int x, final int y, fi initialData.rewind(); modifyTexture( getTextureAtlas(atlasTextureId), - new com.jme3.texture.Image(Format.RGBA8, image.getWidth(), image.getHeight(), initialData, ColorSpace.sRGB), + new GlImage(Format.RGBA8, image.getWidth(), image.getHeight(), initialData, ColorSpace.sRGB), x, y); } @@ -376,7 +377,7 @@ private Texture2D createAtlasTextureInternal(final int width, final int height) // re-use pre-defined initial data instead of creating a new buffer initialData.rewind(); - Texture2D texture = new Texture2D(new com.jme3.texture.Image(Format.RGBA8, width, height, initialData, ColorSpace.sRGB)); + Texture2D texture = new Texture2D(new GlImage(Format.RGBA8, width, height, initialData, ColorSpace.sRGB)); texture.setMinFilter(MinFilter.NearestNoMipMaps); texture.setMagFilter(MagFilter.Nearest); return texture; @@ -384,7 +385,7 @@ private Texture2D createAtlasTextureInternal(final int width, final int height) private void modifyTexture( final Texture2D textureAtlas, - final com.jme3.texture.Image image, + final GlImage image, final int x, final int y) { Renderer renderer = display.getRenderer(); @@ -417,9 +418,9 @@ private int addTexture(final Texture2D texture) { */ private static class ImageImpl implements BatchRenderBackend.Image { - private final com.jme3.texture.Image image; + private final GlImage image; - public ImageImpl(final com.jme3.texture.Image image) { + public ImageImpl(final GlImage image) { this.image = image; } @@ -451,11 +452,11 @@ public int getHeight() { private static class ModifyTexture { private final Texture2D atlas; - private final com.jme3.texture.Image image; + private final GlImage image; private final int x; private final int y; - private ModifyTexture(final Texture2D atlas, final com.jme3.texture.Image image, final int x, final int y) { + private ModifyTexture(final Texture2D atlas, final GlImage image, final int x, final int y) { this.atlas = atlas; this.image = image; this.x = x; diff --git a/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderImageJme.java b/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderImageJme.java index 2354f1c596..72f156d832 100644 --- a/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderImageJme.java +++ b/jme3-niftygui/src/main/java/com/jme3/niftygui/RenderImageJme.java @@ -32,16 +32,16 @@ package com.jme3.niftygui; import com.jme3.asset.TextureKey; -import com.jme3.texture.Image; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; import com.jme3.texture.Texture2D; import de.lessvoid.nifty.spi.render.RenderImage; public class RenderImageJme implements RenderImage { private Texture2D texture; - private Image image; + private GlImage image; private int width; private int height; diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxImage.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxImage.java index 518dd4134a..ca53746803 100644 --- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxImage.java +++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxImage.java @@ -37,7 +37,7 @@ import com.jme3.asset.TextureKey; import com.jme3.scene.plugins.fbx.file.FbxElement; import com.jme3.scene.plugins.fbx.obj.FbxObject; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.util.PlaceholderAssets; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -86,7 +86,7 @@ public void fromElement(FbxElement element) { } } - private Image loadImageSafe(AssetManager assetManager, TextureKey texKey) { + private GlImage loadImageSafe(AssetManager assetManager, TextureKey texKey) { try { return assetManager.loadTexture(texKey).getImage(); } catch (AssetNotFoundException ex) { @@ -123,7 +123,7 @@ public TextureKey getTextureKey() { @Override protected Object toJmeObject() { - Image image = null; + GlImage image = null; String fileName = null; String relativeFilePathJme; diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxMaterial.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxMaterial.java index 8574bf0637..7487f5ba8a 100644 --- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxMaterial.java +++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxMaterial.java @@ -38,7 +38,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.scene.plugins.fbx.file.FbxElement; import com.jme3.scene.plugins.fbx.obj.FbxObject; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.image.ColorSpace; import java.util.logging.Level; import java.util.logging.Logger; @@ -108,12 +108,12 @@ protected Material toJmeObject() { float shininess = 1f; boolean separateTexCoord = false; - Texture diffuseMap = null; - Texture specularMap = null; - Texture normalMap = null; - Texture transpMap = null; - Texture emitMap = null; - Texture aoMap = null; + GlTexture diffuseMap = null; + GlTexture specularMap = null; + GlTexture normalMap = null; + GlTexture transpMap = null; + GlTexture emitMap = null; + GlTexture aoMap = null; FbxTexture fbxDiffuseMap = null; diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxTexture.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxTexture.java index cb1cdd0d9e..06cdb4eb56 100644 --- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxTexture.java +++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/material/FbxTexture.java @@ -35,16 +35,16 @@ import com.jme3.asset.TextureKey; import com.jme3.scene.plugins.fbx.file.FbxElement; import com.jme3.scene.plugins.fbx.obj.FbxObject; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; -import com.jme3.texture.Texture.WrapAxis; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; +import com.jme3.texture.GlTexture.WrapAxis; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.PlaceholderAssets; -public class FbxTexture extends FbxObject { +public class FbxTexture extends FbxObject { private static enum AlphaSource { None, @@ -65,11 +65,11 @@ public String getUvSet() { } @Override - protected Texture toJmeObject() { - Image image = null; + protected GlTexture toJmeObject() { + GlImage image = null; TextureKey key = null; if (media != null) { - image = (Image) media.getJmeObject(); + image = (GlImage) media.getJmeObject(); key = media.getTextureKey(); } if (image == null) { diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxImage.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxImage.java index 7ef3299339..632fab9e3d 100644 --- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxImage.java +++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxImage.java @@ -3,8 +3,8 @@ import java.io.File; import com.jme3.asset.AssetManager; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.image.ColorSpace; import com.jme3.util.BufferUtils; import com.jme3.scene.plugins.fbx.ContentTextureKey; @@ -19,7 +19,7 @@ public class FbxImage extends FbxObject { byte[] content; String imageType; - public Image image; + public GlImage image; public FbxImage(SceneLoader scene, FbxElement element) { super(scene, element); @@ -47,16 +47,16 @@ public FbxImage(SceneLoader scene, FbxElement element) { } - private Image createImage() { + private GlImage createImage() { AssetManager assetManager = scene.assetManager; - Image image = null; + GlImage image = null; if(filename != null) { // Try load by absolute path File file = new File(filename); if(file.exists() && file.isFile()) { File dir = new File(file.getParent()); String locatorPath = dir.getAbsolutePath(); - Texture tex = null; + GlTexture tex = null; try { assetManager.registerLocator(locatorPath, com.jme3.asset.plugins.FileLocator.class); tex = assetManager.loadTexture(file.getName()); @@ -71,7 +71,7 @@ private Image createImage() { // Try load by relative path File dir = new File(scene.sceneFolderName); String locatorPath = dir.getAbsolutePath(); - Texture tex = null; + GlTexture tex = null; try { assetManager.registerLocator(locatorPath, com.jme3.asset.plugins.FileLocator.class); tex = assetManager.loadTexture(relativeFilename); @@ -92,7 +92,7 @@ private Image createImage() { if(filename != null) { String locatorPath = scene.sceneFilename; filename = scene.sceneFilename + File.separatorChar + filename; // Unique path - Texture tex = null; + GlTexture tex = null; try { assetManager.registerLocator(locatorPath, ContentTextureLocator.class); tex = assetManager.loadTexture(new ContentTextureKey(filename, content)); @@ -108,7 +108,7 @@ private Image createImage() { if(relativeFilename != null) { String[] split = relativeFilename.split("[\\\\/]"); String filename = split[split.length - 1]; - Texture tex = null; + GlTexture tex = null; try { tex = assetManager.loadTexture(new ContentTextureKey(scene.currentAssetInfo.getKey().getFolder() + filename, content)); } catch(Exception e) {} @@ -117,7 +117,7 @@ private Image createImage() { } } if(image == null) - return new Image(Image.Format.RGB8, 1, 1, BufferUtils.createByteBuffer((int) (Image.Format.RGB8.getBitsPerPixel() / 8L)), ColorSpace.Linear); + return new GlImage(GlImage.Format.RGB8, 1, 1, BufferUtils.createByteBuffer((int) (GlImage.Format.RGB8.getBitsPerPixel() / 8L)), ColorSpace.Linear); return image; } } diff --git a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxTexture.java b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxTexture.java index 1ccc01141d..7525dac8ab 100644 --- a/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxTexture.java +++ b/jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/objects/FbxTexture.java @@ -1,8 +1,8 @@ package com.jme3.scene.plugins.fbx.objects; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.scene.plugins.fbx.SceneLoader; import com.jme3.scene.plugins.fbx.file.FbxElement; @@ -11,7 +11,7 @@ public class FbxTexture extends FbxObject { String bindType; String filename; - public Texture texture; + public GlTexture texture; public FbxTexture(SceneLoader scene, FbxElement element) { super(scene, element); diff --git a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java index 3002515633..b3d48fa49c 100644 --- a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java +++ b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java @@ -46,7 +46,7 @@ import com.jme3.scene.control.CameraControl; import com.jme3.scene.mesh.MorphTarget; import static com.jme3.scene.plugins.gltf.GltfUtils.*; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.util.IntMap; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; @@ -761,7 +761,7 @@ public Texture2D readTexture(JsonObject texture, boolean flip) throws IOExceptio if (samplerIndex != null) { texture2d = readSampler(samplerIndex, texture2d); } else { - texture2d.setWrap(Texture.WrapMode.Repeat); + texture2d.setWrap(GlTexture.WrapMode.Repeat); } texture2d = customContentManager.readExtensionAndExtras("texture", texture, texture2d); @@ -801,7 +801,7 @@ public Texture2D readImage(int sourceIndex, boolean flip) throws IOException { // external file image String decoded = decodeUri(uri); TextureKey key = new TextureKey(info.getKey().getFolder() + decoded, flip); - Texture tex = info.getManager().loadTexture(key); + GlTexture tex = info.getManager().loadTexture(key); result = (Texture2D) tex; } return result; @@ -1016,10 +1016,10 @@ public Texture2D readSampler(int samplerIndex, Texture2D texture) throws IOExcep throw new AssetLoadException("No samplers defined"); } JsonObject sampler = samplers.get(samplerIndex).getAsJsonObject(); - Texture.MagFilter magFilter = getMagFilter(getAsInteger(sampler, "magFilter")); - Texture.MinFilter minFilter = getMinFilter(getAsInteger(sampler, "minFilter")); - Texture.WrapMode wrapS = getWrapMode(getAsInteger(sampler, "wrapS")); - Texture.WrapMode wrapT = getWrapMode(getAsInteger(sampler, "wrapT")); + GlTexture.MagFilter magFilter = getMagFilter(getAsInteger(sampler, "magFilter")); + GlTexture.MinFilter minFilter = getMinFilter(getAsInteger(sampler, "minFilter")); + GlTexture.WrapMode wrapS = getWrapMode(getAsInteger(sampler, "wrapS")); + GlTexture.WrapMode wrapT = getWrapMode(getAsInteger(sampler, "wrapT")); if (magFilter != null) { texture.setMagFilter(magFilter); @@ -1027,8 +1027,8 @@ public Texture2D readSampler(int samplerIndex, Texture2D texture) throws IOExcep if (minFilter != null) { texture.setMinFilter(minFilter); } - texture.setWrap(Texture.WrapAxis.S, wrapS); - texture.setWrap(Texture.WrapAxis.T, wrapT); + texture.setWrap(GlTexture.WrapAxis.S, wrapS); + texture.setWrap(GlTexture.WrapAxis.T, wrapT); texture = customContentManager.readExtensionAndExtras("texture.sampler", sampler, texture); diff --git a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java index 8f015f28db..50ffa165b7 100644 --- a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java +++ b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java @@ -40,7 +40,7 @@ import com.jme3.plugins.json.Json; import com.jme3.plugins.json.JsonParser; import com.jme3.scene.*; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.util.*; import java.io.*; import java.nio.*; @@ -178,52 +178,52 @@ public static int getIndex(String name) { return Integer.parseInt(num); } - public static Texture.MagFilter getMagFilter(Integer value) { + public static GlTexture.MagFilter getMagFilter(Integer value) { if (value == null) { return null; } switch (value) { case 9728: - return Texture.MagFilter.Nearest; + return GlTexture.MagFilter.Nearest; case 9729: - return Texture.MagFilter.Bilinear; + return GlTexture.MagFilter.Bilinear; } return null; } - public static Texture.MinFilter getMinFilter(Integer value) { + public static GlTexture.MinFilter getMinFilter(Integer value) { if (value == null) { return null; } switch (value) { case 9728: - return Texture.MinFilter.NearestNoMipMaps; + return GlTexture.MinFilter.NearestNoMipMaps; case 9729: - return Texture.MinFilter.BilinearNoMipMaps; + return GlTexture.MinFilter.BilinearNoMipMaps; case 9984: - return Texture.MinFilter.NearestNearestMipMap; + return GlTexture.MinFilter.NearestNearestMipMap; case 9985: - return Texture.MinFilter.BilinearNearestMipMap; + return GlTexture.MinFilter.BilinearNearestMipMap; case 9986: - return Texture.MinFilter.NearestLinearMipMap; + return GlTexture.MinFilter.NearestLinearMipMap; case 9987: - return Texture.MinFilter.Trilinear; + return GlTexture.MinFilter.Trilinear; } return null; } - public static Texture.WrapMode getWrapMode(Integer value) { + public static GlTexture.WrapMode getWrapMode(Integer value) { if (value == null) { - return Texture.WrapMode.Repeat; + return GlTexture.WrapMode.Repeat; } switch (value) { case 33071: - return Texture.WrapMode.EdgeClamp; + return GlTexture.WrapMode.EdgeClamp; case 33648: - return Texture.WrapMode.MirroredRepeat; + return GlTexture.WrapMode.MirroredRepeat; default: - return Texture.WrapMode.Repeat; + return GlTexture.WrapMode.Repeat; } } diff --git a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/MaterialAdapter.java b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/MaterialAdapter.java index b6b10f9c83..e1cf01d08f 100644 --- a/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/MaterialAdapter.java +++ b/jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/MaterialAdapter.java @@ -37,7 +37,7 @@ import com.jme3.material.*; import com.jme3.math.*; import com.jme3.shader.VarType; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.util.HashMap; import java.util.Map; @@ -94,7 +94,7 @@ public void setParam(String gltfParamName, Object value) { return; } MatParam param; - if (value instanceof Texture) { + if (value instanceof GlTexture) { MatParam defParam = getMaterial().getMaterialDef().getMaterialParam(name); if (defParam == null) { throw new AssetLoadException("Material definition " + getMaterialDefPath() + " has not param with name" + name); @@ -102,10 +102,10 @@ public void setParam(String gltfParamName, Object value) { if (!(defParam instanceof MatParamTexture)) { throw new AssetLoadException("param with name" + name + "in material definition " + getMaterialDefPath() + " should be a texture param"); } - param = new MatParamTexture(VarType.Texture2D, name, (Texture) value, ((MatParamTexture) defParam).getColorSpace()); + param = new MatParamTexture(VarType.Texture2D, name, (GlTexture) value, ((MatParamTexture) defParam).getColorSpace()); param = adaptMatParam(param); if (param != null) { - getMaterial().setTextureParam(param.getName(), param.getVarType(), (Texture) param.getValue()); + getMaterial().setTextureParam(param.getName(), param.getVarType(), (GlTexture) param.getValue()); } } else { param = new MatParam(getVarType(value), name, value); diff --git a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MOutputCapsule.java b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MOutputCapsule.java index 950466b4ba..d701ef799c 100644 --- a/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MOutputCapsule.java +++ b/jme3-plugins/src/main/java/com/jme3/material/plugin/export/material/J3MOutputCapsule.java @@ -38,8 +38,8 @@ import com.jme3.material.MatParamTexture; import com.jme3.math.*; import com.jme3.shader.VarType; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.util.IntMap; import java.io.IOException; import java.io.Writer; @@ -157,7 +157,7 @@ private String formatMatParam(MatParam param){ protected static String formatMatParamTexture(MatParamTexture param) { StringBuilder ret = new StringBuilder(); - Texture tex = (Texture) param.getValue(); + GlTexture tex = (GlTexture) param.getValue(); TextureKey key; if (tex != null) { key = (TextureKey) tex.getKey(); @@ -166,16 +166,16 @@ protected static String formatMatParamTexture(MatParamTexture param) { ret.append("Flip "); } - ret.append(formatWrapMode(tex, Texture.WrapAxis.S)); - ret.append(formatWrapMode(tex, Texture.WrapAxis.T)); - ret.append(formatWrapMode(tex, Texture.WrapAxis.R)); + ret.append(formatWrapMode(tex, GlTexture.WrapAxis.S)); + ret.append(formatWrapMode(tex, GlTexture.WrapAxis.T)); + ret.append(formatWrapMode(tex, GlTexture.WrapAxis.R)); //Min and Mag filter - if (tex.getMinFilter() != Texture.MinFilter.Trilinear) { + if (tex.getMinFilter() != GlTexture.MinFilter.Trilinear) { ret.append("Min").append(tex.getMinFilter().name()).append(" "); } - if (tex.getMagFilter() != Texture.MagFilter.Bilinear) { + if (tex.getMagFilter() != GlTexture.MagFilter.Bilinear) { ret.append("Mag").append(tex.getMagFilter().name()).append(" "); } @@ -185,7 +185,7 @@ protected static String formatMatParamTexture(MatParamTexture param) { return ret.toString(); } - protected static String formatWrapMode(Texture texVal, Texture.WrapAxis axis) { + protected static String formatWrapMode(GlTexture texVal, GlTexture.WrapAxis axis) { WrapMode mode; try { mode = texVal.getWrap(axis); diff --git a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java index 5c0b33ed63..26a25bbf04 100644 --- a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java +++ b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java @@ -39,8 +39,8 @@ import com.jme3.scene.plugins.ogre.matext.MaterialExtensionLoader; import com.jme3.scene.plugins.ogre.matext.MaterialExtensionSet; import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.PlaceholderAssets; import com.jme3.util.blockparser.BlockLanguageParser; @@ -60,7 +60,7 @@ public class MaterialLoader implements AssetLoader { private String folderName; private AssetManager assetManager; private ColorRGBA ambient, diffuse, specular, emissive; - private Texture[] textures = new Texture[4]; + private GlTexture[] textures = new GlTexture[4]; private String texName; private String matName; private float shininess; @@ -132,11 +132,11 @@ private void readTextureImage(String content){ TextureKey texKey = new TextureKey(folderName + path, false); texKey.setGenerateMips(genMips); if (cubic) { - texKey.setTextureTypeHint(Texture.Type.CubeMap); + texKey.setTextureTypeHint(GlTexture.Type.CubeMap); } try { - Texture loadedTexture = assetManager.loadTexture(texKey); + GlTexture loadedTexture = assetManager.loadTexture(texKey); textures[texUnit].setImage(loadedTexture.getImage()); textures[texUnit].setMinFilter(loadedTexture.getMinFilter()); diff --git a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/matext/MaterialExtensionLoader.java b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/matext/MaterialExtensionLoader.java index 0b444b80d4..44be3d766f 100644 --- a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/matext/MaterialExtensionLoader.java +++ b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/matext/MaterialExtensionLoader.java @@ -38,8 +38,8 @@ import com.jme3.material.Material; import com.jme3.material.MaterialList; import com.jme3.scene.plugins.ogre.MaterialLoader; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.PlaceholderAssets; import com.jme3.util.blockparser.Statement; @@ -74,7 +74,7 @@ private void readExtendingMaterialStatement(Statement statement) throws IOExcept TextureKey texKey = new TextureKey(texturePath, false); texKey.setGenerateMips(true); - Texture tex; + GlTexture tex; try { tex = assetManager.loadTexture(texKey); diff --git a/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java b/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java index e5dfa75965..400b9db850 100644 --- a/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java +++ b/jme3-plugins/src/test/java/com/jme3/material/plugin/TestMaterialWrite.java @@ -41,7 +41,7 @@ import com.jme3.material.plugins.J3MLoader; import com.jme3.math.ColorRGBA; import com.jme3.system.JmeSystem; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import org.junit.Before; import org.junit.Test; @@ -77,11 +77,11 @@ public void testWriteMat() throws Exception { mat.setFloat("Shininess", 2.5f); - Texture tex = assetManager.loadTexture(new TextureKey("Common/Textures/MissingTexture.png", true)); - tex.setMagFilter(Texture.MagFilter.Nearest); - tex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - tex.setWrap(Texture.WrapAxis.S, Texture.WrapMode.Repeat); - tex.setWrap(Texture.WrapAxis.T, Texture.WrapMode.MirroredRepeat); + GlTexture tex = assetManager.loadTexture(new TextureKey("Common/Textures/MissingTexture.png", true)); + tex.setMagFilter(GlTexture.MagFilter.Nearest); + tex.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); + tex.setWrap(GlTexture.WrapAxis.S, GlTexture.WrapMode.Repeat); + tex.setWrap(GlTexture.WrapAxis.T, GlTexture.WrapMode.MirroredRepeat); mat.setTexture("DiffuseMap", tex); mat.getAdditionalRenderState().setDepthWrite(false); diff --git a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/effects/TestIssue1773.java b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/effects/TestIssue1773.java index 05eb097ee7..4abd237422 100644 --- a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/effects/TestIssue1773.java +++ b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/effects/TestIssue1773.java @@ -60,7 +60,7 @@ import com.jme3.scene.shape.CenterQuad; import com.jme3.scene.shape.Torus; import com.jme3.shadow.DirectionalLightShadowFilter; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import org.jmonkeyengine.screenshottests.testframework.ScreenshotTestBase; import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.params.ParameterizedTest; @@ -219,8 +219,8 @@ private void setupGround() { quad.scaleTextureCoordinates(new Vector2f(2, 2)); Geometry floor = new Geometry("Floor", quad); Material mat = new Material(assetManager, Materials.LIGHTING); - Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); - tex.setWrap(Texture.WrapMode.Repeat); + GlTexture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); + tex.setWrap(GlTexture.WrapMode.Repeat); mat.setTexture("DiffuseMap", tex); floor.setMaterial(mat); floor.rotate(-FastMath.HALF_PI, 0, 0); diff --git a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrain.java b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrain.java index 37f8063300..d2a71fa756 100644 --- a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrain.java +++ b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrain.java @@ -47,8 +47,8 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import org.jmonkeyengine.screenshottests.testframework.ScreenshotTestBase; import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.params.ParameterizedTest; @@ -143,7 +143,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png")); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); dirt.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_0", dirt); matTerrain.setFloat("AlbedoMap_0_scale", dirtScale); @@ -151,7 +151,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setFloat("Metallic_0", 0); // DARK ROCK texture - Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); + GlTexture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); darkRock.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_1", darkRock); matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale); @@ -159,7 +159,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setFloat("Metallic_1", 0.02f); // SNOW texture - Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); + GlTexture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); snow.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_2", snow); matTerrain.setFloat("AlbedoMap_2_scale", snowScale); @@ -167,7 +167,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setFloat("Metallic_2", 0.12f); // TILES texture - Texture tiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); + GlTexture tiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); tiles.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_3", tiles); matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale); @@ -175,7 +175,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setFloat("Metallic_3", 0.08f); // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); grass.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_4", grass); matTerrain.setFloat("AlbedoMap_4_scale", grassScale); @@ -183,7 +183,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setFloat("Metallic_4", 0); // MARBLE texture - Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); + GlTexture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); marble.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_5", marble); matTerrain.setFloat("AlbedoMap_5_scale", marbleScale); @@ -191,7 +191,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setFloat("Metallic_5", 0.8f); // Gravel texture - Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); + GlTexture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); gravel.setWrap(WrapMode.Repeat); matTerrain.setTexture("AlbedoMap_6", gravel); matTerrain.setFloat("AlbedoMap_6_scale", gravelScale); @@ -199,22 +199,22 @@ private void setUpTerrainMaterial(AssetManager assetManager) { matTerrain.setFloat("Metallic_6", 0.07f); // NORMAL MAPS - Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); + GlTexture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); normalMapDirt.setWrap(WrapMode.Repeat); - Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); + GlTexture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); normalMapDarkRock.setWrap(WrapMode.Repeat); - Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); + GlTexture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); normalMapSnow.setWrap(WrapMode.Repeat); - Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); + GlTexture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); normalMapGravel.setWrap(WrapMode.Repeat); - Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); + GlTexture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); normalMapGrass.setWrap(WrapMode.Repeat); - Texture normalMapTiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); + GlTexture normalMapTiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); normalMapTiles.setWrap(WrapMode.Repeat); matTerrain.setTexture("NormalMap_0", normalMapDirt); @@ -230,7 +230,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { private void setUpTerrain(SimpleApplication simpleApp, AssetManager assetManager) { // HEIGHTMAP image (for the terrain heightmap) TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false); - Texture heightMapImage = assetManager.loadTexture(hmKey); + GlTexture heightMapImage = assetManager.loadTexture(hmKey); // CREATE HEIGHTMAP AbstractHeightMap heightmap; diff --git a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrainAdvanced.java b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrainAdvanced.java index a1f5830896..0f8b1c2d35 100644 --- a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrainAdvanced.java +++ b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/terrain/TestPBRTerrainAdvanced.java @@ -48,11 +48,11 @@ import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; import com.jme3.texture.TextureArray; import org.jmonkeyengine.screenshottests.testframework.ScreenshotTestBase; import org.junit.jupiter.api.TestInfo; @@ -167,36 +167,36 @@ private void setUpTerrainMaterial(AssetManager assetManager) { // load textures for texture arrays // These MUST all have the same dimensions and format in order to be put into a texture array. //ALBEDO MAPS - Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); - Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); - Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); - Texture tileRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); - Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); - Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png"); + GlTexture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png"); + GlTexture tileRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png"); + GlTexture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png"); + GlTexture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png"); // NORMAL MAPS - Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); - Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); - Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); - Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); - Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); - Texture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png"); - Texture normalMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); + GlTexture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png"); + GlTexture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png"); + GlTexture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png"); + GlTexture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png"); + GlTexture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png"); + GlTexture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png"); + GlTexture normalMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png"); //PACKED METALLIC/ROUGHNESS / AMBIENT OCCLUSION / EMISSIVE INTENSITY MAPS - Texture metallicRoughnessAoEiMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png"); - Texture metallicRoughnessAoEiMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png"); + GlTexture metallicRoughnessAoEiMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png"); // put all images into lists to create texture arrays. - List albedoImages = new ArrayList<>(); - List normalMapImages = new ArrayList<>(); - List metallicRoughnessAoEiMapImages = new ArrayList<>(); + List albedoImages = new ArrayList<>(); + List normalMapImages = new ArrayList<>(); + List metallicRoughnessAoEiMapImages = new ArrayList<>(); albedoImages.add(dirt.getImage()); //0 albedoImages.add(darkRock.getImage()); //1 @@ -298,7 +298,7 @@ private void setUpTerrainMaterial(AssetManager assetManager) { terrain.setMaterial(matTerrain); } - private void setWrapAndMipMaps(Texture texture) { + private void setWrapAndMipMaps(GlTexture texture) { texture.setWrap(WrapMode.Repeat); texture.setMinFilter(MinFilter.Trilinear); texture.setMagFilter(MagFilter.Bilinear); @@ -307,7 +307,7 @@ private void setWrapAndMipMaps(Texture texture) { private void setUpTerrain(SimpleApplication simpleApp, AssetManager assetManager) { // HEIGHTMAP image (for the terrain heightmap) TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false); - Texture heightMapImage = assetManager.loadTexture(hmKey); + GlTexture heightMapImage = assetManager.loadTexture(hmKey); // CREATE HEIGHTMAP AbstractHeightMap heightmap; diff --git a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/water/TestPostWater.java b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/water/TestPostWater.java index 7868ecd71e..270497c549 100644 --- a/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/water/TestPostWater.java +++ b/jme3-screenshot-tests/src/test/java/org/jmonkeyengine/screenshottests/water/TestPostWater.java @@ -52,8 +52,8 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.GlTexture; +import com.jme3.texture.GlTexture.WrapMode; import com.jme3.texture.Texture2D; import com.jme3.util.SkyFactory; import com.jme3.util.SkyFactory.EnvMapType; @@ -170,24 +170,24 @@ private void createTerrain(Node rootNode, AssetManager assetManager) { matRock.setBoolean("useTriPlanarMapping", false); matRock.setBoolean("WardIso", true); matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + GlTexture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap", grass); matRock.setFloat("DiffuseMap_0_scale", 64); - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + GlTexture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_1", dirt); matRock.setFloat("DiffuseMap_1_scale", 16); - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + GlTexture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); rock.setWrap(WrapMode.Repeat); matRock.setTexture("DiffuseMap_2", rock); matRock.setFloat("DiffuseMap_2_scale", 128); - Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); + GlTexture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg"); normalMap0.setWrap(WrapMode.Repeat); - Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); + GlTexture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png"); normalMap1.setWrap(WrapMode.Repeat); - Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); + GlTexture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png"); normalMap2.setWrap(WrapMode.Repeat); matRock.setTexture("NormalMap", normalMap0); matRock.setTexture("NormalMap_1", normalMap1); diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/grid/ImageTileLoader.java b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/grid/ImageTileLoader.java index d6692c25ca..6435e2b378 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/grid/ImageTileLoader.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/geomipmap/grid/ImageTileLoader.java @@ -40,7 +40,7 @@ import com.jme3.terrain.geomipmap.TerrainGridTileLoader; import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.*; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -112,7 +112,7 @@ private HeightMap getHeightMapAt(Vector3f location) { try { name = namer.getName(x, z); logger.log(Level.FINE, "Loading heightmap from file: {0}", name); - final Texture texture = assetManager.loadTexture(new TextureKey(name)); + final GlTexture texture = assetManager.loadTexture(new TextureKey(name)); heightmap = new ImageBasedHeightMap(texture.getImage()); /*if (assetInfo != null){ InputStream in = assetInfo.openStream(); diff --git a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java index 459beffb63..0958f27ced 100644 --- a/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java +++ b/jme3-terrain/src/main/java/com/jme3/terrain/heightmap/ImageBasedHeightMap.java @@ -32,7 +32,7 @@ package com.jme3.terrain.heightmap; import com.jme3.math.ColorRGBA; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.image.ImageRaster; /** @@ -47,11 +47,11 @@ public class ImageBasedHeightMap extends AbstractHeightMap { - protected Image colorImage; + protected GlImage colorImage; private float backwardsCompScale = 255f; - public void setImage(Image image) { + public void setImage(GlImage image) { this.colorImage = image; } @@ -66,11 +66,11 @@ public void setImage(Image image) { * @param colorImage * Image to map to the height map. */ - public ImageBasedHeightMap(Image colorImage) { + public ImageBasedHeightMap(GlImage colorImage) { this.colorImage = colorImage; } - public ImageBasedHeightMap(Image colorImage, float heightScale) { + public ImageBasedHeightMap(GlImage colorImage, float heightScale) { this.colorImage = colorImage; this.heightScale = heightScale; } diff --git a/jme3-terrain/src/test/java/com/jme3/terrain/TestTerrainExporting.java b/jme3-terrain/src/test/java/com/jme3/terrain/TestTerrainExporting.java index 7dceb63b0e..613fb77b42 100644 --- a/jme3-terrain/src/test/java/com/jme3/terrain/TestTerrainExporting.java +++ b/jme3-terrain/src/test/java/com/jme3/terrain/TestTerrainExporting.java @@ -38,7 +38,7 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import org.junit.Assert; import org.junit.Test; @@ -55,7 +55,7 @@ public class TestTerrainExporting extends BaseAWTTest { @Test public void testTerrainExporting() { - Texture heightMapImage = getAssetManager().loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture heightMapImage = getAssetManager().loadTexture("Textures/Terrain/splat/mountains512.png"); AbstractHeightMap map = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); map.load(); diff --git a/jme3-terrain/src/test/java/com/jme3/terrain/collision/TerrainCollisionTest.java b/jme3-terrain/src/test/java/com/jme3/terrain/collision/TerrainCollisionTest.java index 32768f4060..868f0194fb 100644 --- a/jme3-terrain/src/test/java/com/jme3/terrain/collision/TerrainCollisionTest.java +++ b/jme3-terrain/src/test/java/com/jme3/terrain/collision/TerrainCollisionTest.java @@ -6,7 +6,7 @@ import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.heightmap.AbstractHeightMap; import com.jme3.terrain.heightmap.ImageBasedHeightMap; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -16,7 +16,7 @@ public class TerrainCollisionTest extends BaseAWTTest { @Before public void initQuad() { - Texture heightMapImage = getAssetManager().loadTexture("Textures/Terrain/splat/mountains512.png"); + GlTexture heightMapImage = getAssetManager().loadTexture("Textures/Terrain/splat/mountains512.png"); AbstractHeightMap map = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f); map.load(); quad = new TerrainQuad("terrain", 65, 513, map.getHeightMap()); diff --git a/jme3-testdata/src/main/resources/Shaders/VulkanFragTest.glsl b/jme3-testdata/src/main/resources/Shaders/VulkanFragTest.glsl new file mode 100644 index 0000000000..a1a5605e9f --- /dev/null +++ b/jme3-testdata/src/main/resources/Shaders/VulkanFragTest.glsl @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0) in vec2 texCoord; + +layout(location = 0) out vec4 outColor; + +layout(set = 0, binding = 1) uniform sampler2D colorTexture; + +void main() { + outColor = texture(colorTexture, texCoord); +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Shaders/VulkanTest.json b/jme3-testdata/src/main/resources/Shaders/VulkanTest.json new file mode 100644 index 0000000000..7c0a0ada7e --- /dev/null +++ b/jme3-testdata/src/main/resources/Shaders/VulkanTest.json @@ -0,0 +1,11 @@ +{ + "name" : "VulkanTest", + "techniques" : { + "main" : { + "shaders" : { + "vertex" : "Shaders/VulkanFragTest.json", + "fragment" : "Shaders/VulkanVertTest.json" + } + } + } +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Shaders/VulkanTest.yml b/jme3-testdata/src/main/resources/Shaders/VulkanTest.yml new file mode 100644 index 0000000000..19daacd60d --- /dev/null +++ b/jme3-testdata/src/main/resources/Shaders/VulkanTest.yml @@ -0,0 +1,20 @@ +name: "VulkanTest" +parameters: + Matrices: + type: "UniformBuffer" + set: 0 + binding: 0 + usage: "Stream" + define: "MATRICES" + stages: ["vertex"] + BaseColorMap: + type: "Texture" + set: 0 + binding: 1 + default: "Common/Textures/MissingTexture.jpg" + stages: ["fragment"] +techniques: + main: + shaders: + vertex: "Shaders/VulkanVertTest.yml" + fragment: "Shaders/VulkanFragTest.yml" \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.glsl b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.glsl new file mode 100644 index 0000000000..5960ce60f9 --- /dev/null +++ b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.glsl @@ -0,0 +1,16 @@ +#version 450 + +layout (location = 0) in vec3 inPosition; +layout (location = 1) in vec2 inTexCoord; +layout (location = 2) in vec3 inNormal; + +layout (location = 0) out vec2 texCoord; + +layout (set = 0, binding = 0) uniform CameraBuffer { + mat4 worldViewProjectionMatrix; +} cam; + +void main() { + gl_Position = cam.worldViewProjectionMatrix * vec4(inPosition, 1.0); + texCoord = inTexCoord; +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.j4md b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.j4md new file mode 100644 index 0000000000..1d14be2c60 --- /dev/null +++ b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.j4md @@ -0,0 +1,19 @@ +MaterialDef VulkanVertTest { + + Imports { + UniformBuffer : com.jme3.vulkan.material.UniformBuffer + } + + Vulkan { + Set { + UniformBuffer Camera (vertex) + } + Set { + UniformBuffer Material (fragment) + } + Set { + UniformBuffer Geometry (vertex) + } + } + +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.json b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.json new file mode 100644 index 0000000000..8bc5811cb9 --- /dev/null +++ b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.json @@ -0,0 +1,15 @@ +{ + "shader" : "Shaders/VulkanVertTest.glsl", + "type" : "vertex", + "platforms" : ["vulkan", "opengl"], + "versions" : [460, 450], + "parameters" : { + "Matrices" : { + "type" : "UniformBuffer", + "set" : 0, + "binding" : 0, + "usage" : "Stream", + "define" : "MATRICES" + } + } +} \ No newline at end of file diff --git a/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.yml b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.yml new file mode 100644 index 0000000000..2d48bd103a --- /dev/null +++ b/jme3-testdata/src/main/resources/Shaders/VulkanVertTest.yml @@ -0,0 +1,6 @@ +shader: "Shaders/VulkanVertTest.glsl" +type: "vertex" +platforms: ["vulkan", "opengl", "gles"] +versions: [460, 450] +parameters: + Matrices: "MATRICES" \ No newline at end of file diff --git a/jme3-vr/src/main/java/com/jme3/input/vr/AbstractVRMouseManager.java b/jme3-vr/src/main/java/com/jme3/input/vr/AbstractVRMouseManager.java index 6be4cae9fb..e798dab3d3 100644 --- a/jme3-vr/src/main/java/com/jme3/input/vr/AbstractVRMouseManager.java +++ b/jme3-vr/src/main/java/com/jme3/input/vr/AbstractVRMouseManager.java @@ -11,7 +11,7 @@ import com.jme3.math.Vector2f; import com.jme3.system.AppSettings; import com.jme3.system.lwjgl.LwjglWindow; -import com.jme3.texture.Texture; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; @@ -115,7 +115,7 @@ public void setImage(String texture) { if (environment.getApplication() != null){ if( environment.isInVR() == false ){ - Texture tex = environment.getApplication().getAssetManager().loadTexture(texture); + GlTexture tex = environment.getApplication().getAssetManager().loadTexture(texture); mouseImage.setTexture(environment.getApplication().getAssetManager(), (Texture2D)tex, true); ySize = tex.getImage().getHeight(); mouseImage.setHeight(ySize); @@ -123,7 +123,7 @@ public void setImage(String texture) { mouseImage.getMaterial().getAdditionalRenderState().setBlendMode(BlendMode.Alpha); mouseImage.getMaterial().getAdditionalRenderState().setDepthWrite(false); } else { - Texture tex = environment.getApplication().getAssetManager().loadTexture(texture); + GlTexture tex = environment.getApplication().getAssetManager().loadTexture(texture); mouseImage.setTexture(environment.getApplication().getAssetManager(), (Texture2D)tex, true); ySize = tex.getImage().getHeight(); mouseImage.setHeight(ySize); diff --git a/jme3-vr/src/main/java/com/jme3/input/vr/lwjgl_openvr/LWJGLOpenVRViewManager.java b/jme3-vr/src/main/java/com/jme3/input/vr/lwjgl_openvr/LWJGLOpenVRViewManager.java index 2b658e53f4..022e3c3374 100644 --- a/jme3-vr/src/main/java/com/jme3/input/vr/lwjgl_openvr/LWJGLOpenVRViewManager.java +++ b/jme3-vr/src/main/java/com/jme3/input/vr/lwjgl_openvr/LWJGLOpenVRViewManager.java @@ -12,7 +12,7 @@ import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.scene.Spatial; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; +import com.jme3.texture.GlImage; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; import com.jme3.util.VRGUIPositioningMode; @@ -70,7 +70,7 @@ public LWJGLOpenVRViewManager(VREnvironment environment) { * @see #getFullTexId() */ protected int getLeftTexId() { - return getLeftTexture().getImage().getId(); + return getLeftTexture().getImage().getNativeObject(); } /** @@ -81,7 +81,7 @@ protected int getLeftTexId() { * @see #getFullTexId() */ protected int getRightTexId() { - return getRightTexture().getImage().getId(); + return getRightTexture().getImage().getNativeObject(); } /** @@ -92,7 +92,7 @@ protected int getRightTexId() { * @see #getRightTexId() */ private int getFullTexId() { - return dualEyeTex.getImage().getId(); + return dualEyeTex.getImage().getNativeObject(); } /** @@ -197,11 +197,11 @@ public void postRender() { logger.severe("Submit to left compositor error: " + " (" + Integer.toString(errl) + ")"); logger.severe(" Texture handle: " + leftTextureType.handle()); - logger.severe(" Left eye texture " + leftEyeTexture.getName() + " (" + leftEyeTexture.getImage().getId() + ")"); + logger.severe(" Left eye texture " + leftEyeTexture.getName() + " (" + leftEyeTexture.getImage().getNativeObject() + ")"); logger.severe(" Type: " + leftEyeTexture.getType()); logger.severe(" Size: " + leftEyeTexture.getImage().getWidth() + "x" + leftEyeTexture.getImage().getHeight()); logger.severe(" Image depth: " + leftEyeTexture.getImage().getDepth()); - logger.severe(" Image format: " + leftEyeTexture.getImage().getFormat()); + logger.severe(" Image format: " + leftEyeTexture.getImage().getGlFormat()); logger.severe(" Image color space: " + leftEyeTexture.getImage().getColorSpace()); } @@ -212,11 +212,11 @@ public void postRender() { // logger.severe(" Texture type: "+OpenVRUtil.getETextureTypeString(rightTextureType.eType)); logger.severe(" Texture handle: " + rightTextureType.handle()); - logger.severe(" Right eye texture " + rightEyeTexture.getName() + " (" + rightEyeTexture.getImage().getId() + ")"); + logger.severe(" Right eye texture " + rightEyeTexture.getName() + " (" + rightEyeTexture.getImage().getNativeObject() + ")"); logger.severe(" Type: " + rightEyeTexture.getType()); logger.severe(" Size: " + rightEyeTexture.getImage().getWidth() + "x" + rightEyeTexture.getImage().getHeight()); logger.severe(" Image depth: " + rightEyeTexture.getImage().getDepth()); - logger.severe(" Image format: " + rightEyeTexture.getImage().getFormat()); + logger.severe(" Image format: " + rightEyeTexture.getImage().getGlFormat()); logger.severe(" Image color space: " + rightEyeTexture.getImage().getColorSpace()); } } @@ -502,19 +502,19 @@ private void setupFinalFullTexture(Camera cam) { //offBuffer.setSrgb(true); //setup framebuffer's texture - dualEyeTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8); + dualEyeTex = new Texture2D(cam.getWidth(), cam.getHeight(), GlImage.Format.RGBA8); dualEyeTex.setMinFilter(Texture2D.MinFilter.BilinearNoMipMaps); dualEyeTex.setMagFilter(Texture2D.MagFilter.Bilinear); - logger.config("Dual eye texture " + dualEyeTex.getName() + " (" + dualEyeTex.getImage().getId() + ")"); + logger.config("Dual eye texture " + dualEyeTex.getName() + " (" + dualEyeTex.getImage().getNativeObject() + ")"); logger.config(" Type: " + dualEyeTex.getType()); logger.config(" Size: " + dualEyeTex.getImage().getWidth() + "x" + dualEyeTex.getImage().getHeight()); logger.config(" Image depth: " + dualEyeTex.getImage().getDepth()); - logger.config(" Image format: " + dualEyeTex.getImage().getFormat()); + logger.config(" Image format: " + dualEyeTex.getImage().getGlFormat()); logger.config(" Image color space: " + dualEyeTex.getImage().getColorSpace()); //setup framebuffer to use texture - out.setDepthBuffer(Image.Format.Depth); + out.setDepthBuffer(GlImage.Format.Depth); out.setColorTexture(dualEyeTex); ViewPort viewPort = environment.getApplication().getViewPort(); @@ -538,12 +538,12 @@ private ViewPort setupViewBuffers(Camera cam, String viewName) { //offBufferLeft.setSrgb(true); //setup framebuffer's texture - Texture2D offTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8); + Texture2D offTex = new Texture2D(cam.getWidth(), cam.getHeight(), GlImage.Format.RGBA8); offTex.setMinFilter(Texture2D.MinFilter.BilinearNoMipMaps); offTex.setMagFilter(Texture2D.MagFilter.Bilinear); //setup framebuffer to use texture - offBufferLeft.setDepthBuffer(Image.Format.Depth); + offBufferLeft.setDepthBuffer(GlImage.Format.Depth); offBufferLeft.setColorTexture(offTex); ViewPort viewPort = environment.getApplication().getRenderManager().createPreView(viewName, cam); diff --git a/jme3-vr/src/main/java/com/jme3/input/vr/oculus/OculusVR.java b/jme3-vr/src/main/java/com/jme3/input/vr/oculus/OculusVR.java index 75c14c1647..ef02d44e8e 100644 --- a/jme3-vr/src/main/java/com/jme3/input/vr/oculus/OculusVR.java +++ b/jme3-vr/src/main/java/com/jme3/input/vr/oculus/OculusVR.java @@ -540,16 +540,16 @@ public void setupFramebuffers(int eye) { int textureId = textureIdB.get(); // TODO less hacky way of getting our texture into JMonkeyEngine - Image img = new Image(); + GlImage img = new GlImage(); img.setId(textureId); - img.setFormat(Image.Format.RGBA8); + img.setFormat(GlImage.Format.RGBA8); img.setWidth(textureW); img.setHeight(textureH); Texture2D tex = new Texture2D(img); FrameBuffer buffer = new FrameBuffer(textureW, textureH, 1); - buffer.setDepthBuffer(Image.Format.Depth); + buffer.setDepthBuffer(GlImage.Format.Depth); buffer.setColorTexture(tex); framebuffers[eye][i] = buffer; diff --git a/jme3-vr/src/main/java/com/jme3/input/vr/openvr/OpenVRViewManager.java b/jme3-vr/src/main/java/com/jme3/input/vr/openvr/OpenVRViewManager.java index c6d0237321..b472ec8ea0 100644 --- a/jme3-vr/src/main/java/com/jme3/input/vr/openvr/OpenVRViewManager.java +++ b/jme3-vr/src/main/java/com/jme3/input/vr/openvr/OpenVRViewManager.java @@ -23,8 +23,8 @@ import com.jme3.system.jopenvr.VRTextureBounds_t; import com.jme3.system.jopenvr.VR_IVRSystem_FnTable; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; import com.jme3.util.VRGUIPositioningMode; @@ -70,7 +70,7 @@ public OpenVRViewManager(VREnvironment environment){ * @see #getFullTexId() */ protected int getLeftTexId() { - return getLeftTexture().getImage().getId(); + return getLeftTexture().getImage().getNativeObject(); } /** @@ -80,7 +80,7 @@ protected int getLeftTexId() { * @see #getFullTexId() */ protected int getRightTexId() { - return getRightTexture().getImage().getId(); + return getRightTexture().getImage().getNativeObject(); } /** @@ -90,7 +90,7 @@ protected int getRightTexId() { * @see #getRightTexId() */ private int getFullTexId() { - return dualEyeTex.getImage().getId(); + return dualEyeTex.getImage().getNativeObject(); } /** @@ -216,11 +216,11 @@ public void postRender() { logger.severe(" Texture type: "+OpenVRUtil.getETextureTypeString(leftTextureType.eType)); logger.severe(" Texture handle: "+leftTextureType.handle); - logger.severe(" Left eye texture "+leftEyeTexture.getName()+" ("+leftEyeTexture.getImage().getId()+")"); + logger.severe(" Left eye texture "+leftEyeTexture.getName()+" ("+leftEyeTexture.getImage().getNativeObject()+")"); logger.severe(" Type: "+leftEyeTexture.getType()); logger.severe(" Size: "+leftEyeTexture.getImage().getWidth()+"x"+leftEyeTexture.getImage().getHeight()); logger.severe(" Image depth: "+leftEyeTexture.getImage().getDepth()); - logger.severe(" Image format: "+leftEyeTexture.getImage().getFormat()); + logger.severe(" Image format: "+leftEyeTexture.getImage().getGlFormat()); logger.severe(" Image color space: "+leftEyeTexture.getImage().getColorSpace()); } @@ -230,11 +230,11 @@ public void postRender() { logger.severe(" Texture type: "+OpenVRUtil.getETextureTypeString(rightTextureType.eType)); logger.severe(" Texture handle: "+rightTextureType.handle); - logger.severe(" Right eye texture "+rightEyeTexture.getName()+" ("+rightEyeTexture.getImage().getId()+")"); + logger.severe(" Right eye texture "+rightEyeTexture.getName()+" ("+rightEyeTexture.getImage().getNativeObject()+")"); logger.severe(" Type: "+rightEyeTexture.getType()); logger.severe(" Size: "+rightEyeTexture.getImage().getWidth()+"x"+rightEyeTexture.getImage().getHeight()); logger.severe(" Image depth: "+rightEyeTexture.getImage().getDepth()); - logger.severe(" Image format: "+rightEyeTexture.getImage().getFormat()); + logger.severe(" Image format: "+rightEyeTexture.getImage().getGlFormat()); logger.severe(" Image color space: "+rightEyeTexture.getImage().getColorSpace()); } } @@ -536,7 +536,7 @@ private void setupCamerasAndViews() { } } - private ViewPort setupMirrorBuffers(Camera cam, Texture tex, boolean expand) { + private ViewPort setupMirrorBuffers(Camera cam, GlTexture tex, boolean expand) { if (environment != null){ if (environment.getApplication() != null){ Camera cloneCam = cam.clone(); @@ -575,19 +575,19 @@ private void setupFinalFullTexture(Camera cam) { //offBuffer.setSrgb(true); //setup framebuffer's texture - dualEyeTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8); - dualEyeTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - dualEyeTex.setMagFilter(Texture.MagFilter.Bilinear); + dualEyeTex = new Texture2D(cam.getWidth(), cam.getHeight(), GlImage.Format.RGBA8); + dualEyeTex.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); + dualEyeTex.setMagFilter(GlTexture.MagFilter.Bilinear); - logger.config("Dual eye texture "+dualEyeTex.getName()+" ("+dualEyeTex.getImage().getId()+")"); + logger.config("Dual eye texture "+dualEyeTex.getName()+" ("+dualEyeTex.getImage().getNativeObject()+")"); logger.config(" Type: "+dualEyeTex.getType()); logger.config(" Size: "+dualEyeTex.getImage().getWidth()+"x"+dualEyeTex.getImage().getHeight()); logger.config(" Image depth: "+dualEyeTex.getImage().getDepth()); - logger.config(" Image format: "+dualEyeTex.getImage().getFormat()); + logger.config(" Image format: "+dualEyeTex.getImage().getGlFormat()); logger.config(" Image color space: "+dualEyeTex.getImage().getColorSpace()); //setup framebuffer to use texture - out.setDepthBuffer(Image.Format.Depth); + out.setDepthBuffer(GlImage.Format.Depth); out.setColorTexture(dualEyeTex); ViewPort viewPort = environment.getApplication().getViewPort(); @@ -610,12 +610,12 @@ private ViewPort setupViewBuffers(Camera cam, String viewName){ //offBufferLeft.setSrgb(true); //setup framebuffer's texture - Texture2D offTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8); - offTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - offTex.setMagFilter(Texture.MagFilter.Bilinear); + Texture2D offTex = new Texture2D(cam.getWidth(), cam.getHeight(), GlImage.Format.RGBA8); + offTex.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); + offTex.setMagFilter(GlTexture.MagFilter.Bilinear); //setup framebuffer to use texture - offBufferLeft.setDepthBuffer(Image.Format.Depth); + offBufferLeft.setDepthBuffer(GlImage.Format.Depth); offBufferLeft.setColorTexture(offTex); ViewPort viewPort = environment.getApplication().getRenderManager().createPreView(viewName, cam); diff --git a/jme3-vr/src/main/java/com/jme3/post/CartoonSSAO.java b/jme3-vr/src/main/java/com/jme3/post/CartoonSSAO.java index eb1ddd5404..7f695d4ff6 100644 --- a/jme3-vr/src/main/java/com/jme3/post/CartoonSSAO.java +++ b/jme3-vr/src/main/java/com/jme3/post/CartoonSSAO.java @@ -4,11 +4,10 @@ import com.jme3.material.Material; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; -import com.jme3.post.Filter; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.texture.Image.Format; +import com.jme3.texture.GlImage.Format; /** * A Cartoon Screen Space Ambient Occlusion filter with instance rendering capabilities. diff --git a/jme3-vr/src/main/java/com/jme3/shadow/AbstractShadowRendererVR.java b/jme3-vr/src/main/java/com/jme3/shadow/AbstractShadowRendererVR.java index ac2df723c4..ef16d9df99 100644 --- a/jme3-vr/src/main/java/com/jme3/shadow/AbstractShadowRendererVR.java +++ b/jme3-vr/src/main/java/com/jme3/shadow/AbstractShadowRendererVR.java @@ -56,10 +56,10 @@ import com.jme3.scene.Spatial; import com.jme3.scene.debug.WireFrustum; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture.MagFilter; -import com.jme3.texture.Texture.MinFilter; -import com.jme3.texture.Texture.ShadowCompareMode; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture.MagFilter; +import com.jme3.texture.GlTexture.MinFilter; +import com.jme3.texture.GlTexture.ShadowCompareMode; import com.jme3.texture.Texture2D; import com.jme3.texture.FrameBuffer.FrameBufferTarget; import com.jme3.ui.Picture; diff --git a/jme3-vr/src/main/java/com/jme3/util/VRGuiManager.java b/jme3-vr/src/main/java/com/jme3/util/VRGuiManager.java index 61033e7ab6..7e1512d64a 100644 --- a/jme3-vr/src/main/java/com/jme3/util/VRGuiManager.java +++ b/jme3-vr/src/main/java/com/jme3/util/VRGuiManager.java @@ -17,8 +17,8 @@ import com.jme3.scene.shape.CenterQuad; import com.jme3.system.AppSettings; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image.Format; -import com.jme3.texture.Texture; +import com.jme3.texture.GlImage.Format; +import com.jme3.texture.GlTexture; import com.jme3.texture.Texture2D; import java.awt.GraphicsEnvironment; import java.util.Iterator; @@ -427,8 +427,8 @@ private Spatial getGuiQuad(Camera sourceCam){ //setup framebuffer's texture guiTexture = new Texture2D((int)guiCanvasSize.x, (int)guiCanvasSize.y, Format.RGBA8); - guiTexture.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - guiTexture.setMagFilter(Texture.MagFilter.Bilinear); + guiTexture.setMinFilter(GlTexture.MinFilter.BilinearNoMipMaps); + guiTexture.setMagFilter(GlTexture.MagFilter.Bilinear); //setup framebuffer to use texture offBuffer.setDepthBuffer(Format.Depth);