From 70f9da9907ed02a990d938d3a2deddda1f8ffeb3 Mon Sep 17 00:00:00 2001 From: Riccardo Balbo Date: Fri, 19 Jan 2024 09:11:20 +0100 Subject: [PATCH] Expand support for GL ES / WebGL compatible formats. (#2101) * Add more WebGL / GLES supported formats * Add compressonator ETC formats to DDS loader * ETCFlipper description --------- Co-authored-by: SceneMax3D --- .../java/com/jme3/renderer/opengl/GLExt.java | 5 +++++ .../jme3/renderer/opengl/GLImageFormats.java | 21 +++++++++++++++---- .../src/main/java/com/jme3/texture/Image.java | 17 +++++++++++++++ .../com/jme3/texture/plugins/DDSLoader.java | 20 ++++++++++++++++++ .../com/jme3/texture/plugins/DXTFlipper.java | 8 ++++++- .../com/jme3/texture/plugins/ETCFlipper.java | 19 +++++++++++++++++ 6 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 jme3-core/src/plugins/java/com/jme3/texture/plugins/ETCFlipper.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java index ea9add1583..3cc4f175fa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java @@ -45,6 +45,11 @@ public interface GLExt { public static final int GL_ALREADY_SIGNALED = 0x911A; public static final int GL_COMPRESSED_RGB8_ETC2 = 0x9274; + public static final int GL_COMPRESSED_SRGB8_ETC2 = 0x9275; + public static final int GL_COMPRESSED_RGBA8_ETC2_EAC = 0x9278; + public static final int GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279; + public static final int GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276; + public static final int GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277; public static final int GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; public static final int GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; public static final int GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; 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 396af9ee34..c73943c54e 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 @@ -242,13 +242,17 @@ public static GLImageFormat[][] getFormatsForCaps(EnumSet caps) { // But for render buffers it's OK. format(formatToGL, Format.Depth16, GL.GL_DEPTH_COMPONENT16, GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_SHORT); - // NOTE: OpenGL ES 2.0 does not support DEPTH_COMPONENT as internal format -- fallback to 16-bit depth. - if (caps.contains(Caps.OpenGLES20)) { + + if (caps.contains(Caps.WebGL)) { + // NOTE: fallback to 24-bit depth as workaround for firefox bug in WebGL 2 where DEPTH_COMPONENT16 is not handled properly + format(formatToGL, Format.Depth, GL2.GL_DEPTH_COMPONENT24, GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_INT); + } else if (caps.contains(Caps.OpenGLES20)) { + // NOTE: OpenGL ES 2.0 does not support DEPTH_COMPONENT as internal format -- fallback to 16-bit depth. format(formatToGL, Format.Depth, GL.GL_DEPTH_COMPONENT16, GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_SHORT); } else { format(formatToGL, Format.Depth, GL.GL_DEPTH_COMPONENT, GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_BYTE); } - if (caps.contains(Caps.OpenGL20) || caps.contains(Caps.Depth24)) { + if (caps.contains(Caps.OpenGLES30) || caps.contains(Caps.OpenGL20) || caps.contains(Caps.Depth24)) { format(formatToGL, Format.Depth24, GL2.GL_DEPTH_COMPONENT24, GL.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_INT); } if (caps.contains(Caps.FloatDepthBuffer)) { @@ -274,11 +278,20 @@ public static GLImageFormat[][] getFormatsForCaps(EnumSet caps) { } if (caps.contains(Caps.TextureCompressionETC2)) { + formatComp(formatToGL, Format.ETC2, GLExt.GL_COMPRESSED_RGBA8_ETC2_EAC, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); + formatComp(formatToGL, Format.ETC2_ALPHA1, GLExt.GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); formatComp(formatToGL, Format.ETC1, GLExt.GL_COMPRESSED_RGB8_ETC2, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); + if (caps.contains(Caps.Srgb)) { + formatCompSrgb(formatToGL, Format.ETC2, GLExt.GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); + formatCompSrgb(formatToGL, Format.ETC2_ALPHA1, GLExt.GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); + formatCompSrgb(formatToGL, Format.ETC1, GLExt.GL_COMPRESSED_SRGB8_ETC2, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); + } } else if (caps.contains(Caps.TextureCompressionETC1)) { - formatComp(formatToGL, Format.ETC1, GLExt.GL_ETC1_RGB8_OES, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); + formatComp(formatToGL, Format.ETC1, GLExt.GL_ETC1_RGB8_OES, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); } + + if(caps.contains(Caps.OpenGL42) || caps.contains(Caps.TextureCompressionBPTC)) { formatComp(formatToGL, Format.BC6H_SF16, GLExt.GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); formatComp(formatToGL, Format.BC6H_UF16, GLExt.GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL.GL_RGB, GL.GL_UNSIGNED_BYTE); diff --git a/jme3-core/src/main/java/com/jme3/texture/Image.java b/jme3-core/src/main/java/com/jme3/texture/Image.java index 4f576b810c..c5c0395021 100644 --- a/jme3-core/src/main/java/com/jme3/texture/Image.java +++ b/jme3-core/src/main/java/com/jme3/texture/Image.java @@ -330,6 +330,23 @@ public enum Format { * 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. 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 f7881e45c2..6ea0f8d45d 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 @@ -86,6 +86,10 @@ public class DDSLoader implements AssetLoader { private static final int PF_DX10 = 0x30315844; // a DX10 format private static final int PF_BC4S = 0x53344342; // a DX9 file format for BC4 signed private static final int PF_BC5S = 0x53354342; // a DX9 file format for BC5 signed + private static final int PF_ETC2_RGBA_CSN = 0x41435445; // ETC2 RGBA format notation from Compressonator + private static final int PF_ETC2_RGB_CSN = 0x32435445; // ETC2 RGB format notation from Compressonator + private static final int PF_ETC_RGB_CSN = 0x20435445; // ETC RGB format notation from Compressonator + private static final int PF_ETC2_RGBA1_CSN = 0x50435445; // ETC RGB + Alpha1 format notation from Compressonator private static final int DX10DIM_TEXTURE3D = 0x4; private static final int DX10MISC_TEXTURECUBE = 0x4; private static final double LOG2 = Math.log(2); @@ -341,6 +345,22 @@ private void readPixelFormat() throws IOException { bpp = 8; pixelFormat = Format.SIGNED_RGTC2; break; + case PF_ETC_RGB_CSN: + bpp = 4; + pixelFormat = Format.ETC1; + break; + case PF_ETC2_RGB_CSN: + bpp = 4; + pixelFormat = Format.ETC1; + break; + case PF_ETC2_RGBA1_CSN: + bpp = 4; + pixelFormat = Format.ETC2_ALPHA1; + break; + case PF_ETC2_RGBA_CSN: + bpp = 8; + pixelFormat = Format.ETC2; + break; default: throw new IOException("Unknown fourcc: " + string(fourcc) + ", " + Integer.toHexString(fourcc)); } 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 a07c3d215e..10a02df4a3 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 @@ -36,6 +36,7 @@ import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.logging.Logger; /** * DXTFlipper is a utility class used to flip along Y axis DXT compressed textures. @@ -43,6 +44,7 @@ * @author Kirill Vainer */ public class DXTFlipper { + private static final Logger logger = Logger.getLogger(DXTFlipper.class.getName()); private static final ByteBuffer bb = ByteBuffer.allocate(8); @@ -202,7 +204,11 @@ private static void flipDXT1orDXTA3Block(byte[] block, int h){ } } - public static ByteBuffer flipDXT(ByteBuffer img, int w, int h, Format format){ + public static ByteBuffer flipDXT(ByteBuffer img, int w, int h, Format format) { + if (format == Format.ETC1 || format == Format.ETC2 || format == Format.ETC2_ALPHA1) { + logger.warning("This is not a DXT format, but ETC. Use flipETC instead."); + return ETCFlipper.flipETC(img, w, h, format); + } int originalLimit = img.limit(); int blocksX = (int) FastMath.ceil(w / 4f); int blocksY = (int) FastMath.ceil(h / 4f); 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 new file mode 100644 index 0000000000..0809a5f7bb --- /dev/null +++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/ETCFlipper.java @@ -0,0 +1,19 @@ +package com.jme3.texture.plugins; + +import java.nio.ByteBuffer; +import java.util.logging.Logger; + +import com.jme3.texture.Image.Format; + +/** + * A place-holder for future implementation of ETC texture flipping. + * +*/ +public class ETCFlipper { + private static final Logger logger = Logger.getLogger(ETCFlipper.class.getName()); + + public static ByteBuffer flipETC(ByteBuffer img, int w, int h, Format format) { + logger.warning("ETC texture flipping is not supported yet"); + return img; + } +}