package com.jme3.system.android; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView.EGLConfigChooser; import java.util.logging.Level; import java.util.logging.Logger; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLDisplay; /** * AndroidConfigChooser is used to determine the best suited EGL Config * * @author larynx */ public class AndroidConfigChooser implements EGLConfigChooser { private static final Logger logger = Logger.getLogger(AndroidConfigChooser.class.getName()); protected int clientOpenGLESVersion = 0; protected EGLConfig bestConfig = null; protected EGLConfig fastestConfig = null; protected EGLConfig choosenConfig = null; protected ConfigType type; protected int pixelFormat; protected boolean verbose = false; private final static int EGL_OPENGL_ES2_BIT = 4; public enum ConfigType { /** * RGB565, 0 alpha, 16 depth, 0 stencil */ FASTEST, /** * RGB???, 0 alpha, >=16 depth, 0 stencil */ BEST, /** * Turn off config chooser and use hardcoded * setEGLContextClientVersion(2); setEGLConfigChooser(5, 6, 5, 0, 16, * 0); */ LEGACY } public AndroidConfigChooser(ConfigType type) { this.type = type; } /** * Gets called by the GLSurfaceView class to return the best config */ @Override public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { logger.info("GLSurfaceView asks for egl config, returning: "); logEGLConfig(choosenConfig, display, egl); return choosenConfig; } /** * findConfig is used to locate the best config and init the chooser with * * @param egl * @param display * @return true if successfull, false if no config was found */ public boolean findConfig(EGL10 egl, EGLDisplay display) { if (type == ConfigType.BEST) { ComponentSizeChooser compChooser = new ComponentSizeChooser(8, 8, 8, 8, 32, 0); choosenConfig = compChooser.chooseConfig(egl, display); if (choosenConfig == null) { compChooser = new ComponentSizeChooser(8, 8, 8, 0, 32, 0); choosenConfig = compChooser.chooseConfig(egl, display); if (choosenConfig == null) { compChooser = new ComponentSizeChooser(8, 8, 8, 8, 16, 0); choosenConfig = compChooser.chooseConfig(egl, display); if (choosenConfig == null) { compChooser = new ComponentSizeChooser(8, 8, 8, 0, 16, 0); choosenConfig = compChooser.chooseConfig(egl, display); } } } logger.info("JME3 using best EGL configuration available here: "); } else { ComponentSizeChooser compChooser = new ComponentSizeChooser(5, 6, 5, 0, 16, 0); choosenConfig = compChooser.chooseConfig(egl, display); logger.info("JME3 using fastest EGL configuration available here: "); } if (choosenConfig != null) { logger.info("JME3 using choosen config: "); logEGLConfig(choosenConfig, display, egl); pixelFormat = getPixelFormat(choosenConfig, display, egl); clientOpenGLESVersion = getOpenGLVersion(choosenConfig, display, egl); return true; } else { logger.severe("###ERROR### Unable to get a valid OpenGL ES 2.0 config, nether Fastest nor Best found! Bug. Please report this."); clientOpenGLESVersion = 1; pixelFormat = PixelFormat.UNKNOWN; return false; } } private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl) { int[] value = new int[1]; int result = PixelFormat.RGB_565; egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value); if (value[0] == 8) { result = PixelFormat.RGBA_8888; /* egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value); if (value[0] == 8) { result = PixelFormat.RGBA_8888; } else { result = PixelFormat.RGB_888; }*/ } if (verbose) { logger.log(Level.INFO, "Using PixelFormat {0}", result); } //return result; TODO Test pixelformat return PixelFormat.TRANSPARENT; } private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl) { int[] value = new int[1]; int result = 1; egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value); // Check if conf is OpenGL ES 2.0 if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) { result = 2; } return result; } /** * log output with egl config details * * @param conf * @param display * @param egl */ public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl) { int[] value = new int[1]; egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value); logger.info(String.format("EGL_RED_SIZE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_GREEN_SIZE, value); logger.info(String.format("EGL_GREEN_SIZE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_BLUE_SIZE, value); logger.info(String.format("EGL_BLUE_SIZE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value); logger.info(String.format("EGL_ALPHA_SIZE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_DEPTH_SIZE, value); logger.info(String.format("EGL_DEPTH_SIZE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_STENCIL_SIZE, value); logger.info(String.format("EGL_STENCIL_SIZE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value); logger.info(String.format("EGL_RENDERABLE_TYPE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_SURFACE_TYPE, value); logger.info(String.format("EGL_SURFACE_TYPE = %d", value[0])); } public int getClientOpenGLESVersion() { return clientOpenGLESVersion; } public void setClientOpenGLESVersion(int clientOpenGLESVersion) { this.clientOpenGLESVersion = clientOpenGLESVersion; } public int getPixelFormat() { return pixelFormat; } private abstract class BaseConfigChooser implements EGLConfigChooser { private boolean bClientOpenGLESVersionSet; public BaseConfigChooser(int[] configSpec) { bClientOpenGLESVersionSet = false; mConfigSpec = filterConfigSpec(configSpec); } public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { int[] num_config = new int[1]; if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config)) { throw new IllegalArgumentException("eglChooseConfig failed"); } int numConfigs = num_config[0]; if (numConfigs <= 0) { //throw new IllegalArgumentException("No configs match configSpec"); return null; } EGLConfig[] configs = new EGLConfig[numConfigs]; if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config)) { throw new IllegalArgumentException("eglChooseConfig#2 failed"); } EGLConfig config = chooseConfig(egl, display, configs); //if (config == null) { // throw new IllegalArgumentException("No config chosen"); //} return config; } abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs); protected int[] mConfigSpec; private int[] filterConfigSpec(int[] configSpec) { if (bClientOpenGLESVersionSet == true) { return configSpec; } /* * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we * know the configSpec is well formed. */ int len = configSpec.length; int[] newConfigSpec = new int[len + 2]; System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1); newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE; newConfigSpec[len] = 4; /* * EGL_OPENGL_ES2_BIT */ newConfigSpec[len + 1] = EGL10.EGL_NONE; bClientOpenGLESVersionSet = true; return newConfigSpec; } } /** * Choose a configuration with exactly the specified r,g,b,a sizes, and at * least the specified depth and stencil sizes. */ private class ComponentSizeChooser extends BaseConfigChooser { private int[] mValue; // Subclasses can adjust these values: protected int mRedSize; protected int mGreenSize; protected int mBlueSize; protected int mAlphaSize; protected int mDepthSize; protected int mStencilSize; public ComponentSizeChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize) { super(new int[]{ EGL10.EGL_RED_SIZE, redSize, EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE, blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize, EGL10.EGL_DEPTH_SIZE, depthSize, EGL10.EGL_STENCIL_SIZE, stencilSize, EGL10.EGL_NONE}); mValue = new int[1]; mRedSize = redSize; mGreenSize = greenSize; mBlueSize = blueSize; mAlphaSize = alphaSize; mDepthSize = depthSize; mStencilSize = stencilSize; } @Override public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { for (EGLConfig config : configs) { int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); if ((d >= mDepthSize) && (s >= mStencilSize)) { int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0); int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0); int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); if ((r == mRedSize) && (g == mGreenSize) && (b == mBlueSize) && (a == mAlphaSize)) { return config; } } } return null; } private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) { if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { return mValue[0]; } return defaultValue; } } }