package org.andengine.opengl.view;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import org.andengine.engine.options.ConfigChooserOptions;
import android.opengl.GLSurfaceView;
/**
* (c) 2011 Zynga Inc.
*
* @author Nicolas Gramlich <ngramlich@zynga.com>
* @since 15:31:48 - 04.08.2011
*/
public class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
// ===========================================================
// Constants
// ===========================================================
private static final int[] BUFFER = new int[1];
private static final int MULTISAMPLE_COUNT = 2; // TODO Could be made variable?
private static final int EGL_GLES2_BIT = 4;
private static final int EGL_COVERAGE_BUFFERS_NV = 0x30E0;
private static final int EGL_COVERAGE_SAMPLES_NV = 0x30E1;
private final int[] mMultiSampleEGLConfig;
private final int[] mNvidiaCoverageMultiSampleEGLConfig;
private final int[] mDefaultEGLConfig;
// ===========================================================
// Fields
// ===========================================================
private final boolean mRequestedMultiSampling;
private boolean mActualMultiSampling;
private boolean mActualCoverageMultiSampling;
private final int mRequestedRedSize;
private final int mRequestedGreenSize;
private final int mRequestedBlueSize;
private final int mRequestedAlphaSize;
private final int mRequestedDepthSize;
private final int mRequestedStencilSize;
private int mActualRedSize = -1;
private int mActualGreenSize = -1;
private int mActualBlueSize = -1;
private int mActualAlphaSize = -1;
private int mActualDepthSize = -1;
private int mActualStencilSize = -1;
// ===========================================================
// Constructors
// ===========================================================
public ConfigChooser(final ConfigChooserOptions pConfigChooserOptions) {
this(pConfigChooserOptions.getRequestedRedSize(), pConfigChooserOptions.getRequestedGreenSize(), pConfigChooserOptions.getRequestedBlueSize(), pConfigChooserOptions.getRequestedAlphaSize(), pConfigChooserOptions.getRequestedDepthSize(), pConfigChooserOptions.getRequestedStencilSize(), pConfigChooserOptions.isRequestedMultiSampling());
}
public ConfigChooser(final int pRequestedRedSize, final int pRequestedGreenSize, final int pRequestedBlueSize, final int pRequestedAlphaSize, final int pRequestedDepthSize, final int pRequestedStencilSize, final boolean pRequestedMultiSampling) {
this.mRequestedRedSize = pRequestedRedSize;
this.mRequestedGreenSize = pRequestedGreenSize;
this.mRequestedBlueSize = pRequestedBlueSize;
this.mRequestedAlphaSize = pRequestedAlphaSize;
this.mRequestedDepthSize = pRequestedDepthSize;
this.mRequestedStencilSize = pRequestedStencilSize;
this.mRequestedMultiSampling = pRequestedMultiSampling;
this.mMultiSampleEGLConfig = new int[] {
EGL10.EGL_RED_SIZE, pRequestedRedSize,
EGL10.EGL_GREEN_SIZE, pRequestedGreenSize,
EGL10.EGL_BLUE_SIZE, pRequestedBlueSize,
EGL10.EGL_ALPHA_SIZE, pRequestedAlphaSize,
EGL10.EGL_DEPTH_SIZE, pRequestedDepthSize,
EGL10.EGL_STENCIL_SIZE, pRequestedStencilSize,
EGL10.EGL_RENDERABLE_TYPE, ConfigChooser.EGL_GLES2_BIT,
EGL10.EGL_SAMPLE_BUFFERS, 1,
EGL10.EGL_SAMPLES, ConfigChooser.MULTISAMPLE_COUNT,
EGL10.EGL_NONE
};
this.mNvidiaCoverageMultiSampleEGLConfig = new int[] {
EGL10.EGL_RED_SIZE, pRequestedRedSize,
EGL10.EGL_GREEN_SIZE, pRequestedGreenSize,
EGL10.EGL_BLUE_SIZE, pRequestedBlueSize,
EGL10.EGL_ALPHA_SIZE, pRequestedAlphaSize,
EGL10.EGL_DEPTH_SIZE, pRequestedDepthSize,
EGL10.EGL_STENCIL_SIZE, pRequestedStencilSize,
EGL10.EGL_RENDERABLE_TYPE, ConfigChooser.EGL_GLES2_BIT,
ConfigChooser.EGL_COVERAGE_BUFFERS_NV, 1,
ConfigChooser.EGL_COVERAGE_SAMPLES_NV, ConfigChooser.MULTISAMPLE_COUNT,
EGL10.EGL_NONE
};
this.mDefaultEGLConfig = new int[] {
EGL10.EGL_RED_SIZE, pRequestedRedSize,
EGL10.EGL_GREEN_SIZE, pRequestedGreenSize,
EGL10.EGL_BLUE_SIZE, pRequestedBlueSize,
EGL10.EGL_ALPHA_SIZE, pRequestedAlphaSize,
EGL10.EGL_DEPTH_SIZE, pRequestedDepthSize,
EGL10.EGL_STENCIL_SIZE, pRequestedStencilSize,
EGL10.EGL_RENDERABLE_TYPE, ConfigChooser.EGL_GLES2_BIT,
EGL10.EGL_NONE
};
}
// ===========================================================
// Getter & Setter
// ===========================================================
public boolean isRequestedMultiSampling() {
return this.mRequestedMultiSampling;
}
public boolean isActualMultiSampling() {
return this.mActualMultiSampling;
}
public boolean isActualCoverageMultiSampling() {
return this.mActualCoverageMultiSampling;
}
public int getRequestedRedSize() {
return this.mRequestedRedSize;
}
public int getActualRedSize() {
return this.mActualRedSize;
}
public int getRequestedGreenSize() {
return this.mRequestedGreenSize;
}
public int getActualGreenSize() {
return this.mActualGreenSize;
}
public int getRequestedSize() {
return this.mRequestedBlueSize;
}
public int getActualBlueSize() {
return this.mActualBlueSize;
}
public int getRequestedAlphaSize() {
return this.mRequestedAlphaSize;
}
public int getActualAlphaSize() {
return this.mActualAlphaSize;
}
public int getRequestedDepthSize() {
return this.mRequestedDepthSize;
}
public int getActualDepthSize() {
return this.mActualDepthSize;
}
public int getRequestedStencilSize() {
return this.mRequestedStencilSize;
}
public int getActualStencilSize() {
return this.mActualStencilSize;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public EGLConfig chooseConfig(final EGL10 pEGL, final EGLDisplay pEGLDisplay) {
try {
return this.chooseConfig(pEGL, pEGLDisplay, ConfigChooserMatcher.STRICT);
} catch (final IllegalArgumentException e) {
}
try {
return this.chooseConfig(pEGL, pEGLDisplay, ConfigChooserMatcher.LOOSE_STENCIL);
} catch (final IllegalArgumentException e) {
}
try {
return this.chooseConfig(pEGL, pEGLDisplay, ConfigChooserMatcher.LOOSE_DEPTH_AND_STENCIL);
} catch (final IllegalArgumentException e) {
}
return this.chooseConfig(pEGL, pEGLDisplay, ConfigChooserMatcher.ANY);
}
private EGLConfig chooseConfig(final EGL10 pEGL, final EGLDisplay pEGLDisplay, final ConfigChooserMatcher pConfigChooserMatcher) throws IllegalArgumentException {
ConfigChooser.BUFFER[0] = 0;
int eglConfigCount;
if (this.mRequestedMultiSampling) {
eglConfigCount = this.getEGLConfigCount(pEGL, pEGLDisplay, this.mMultiSampleEGLConfig);
if (eglConfigCount > 0) {
this.mActualMultiSampling = true;
return this.findEGLConfig(pEGL, pEGLDisplay, this.mMultiSampleEGLConfig, eglConfigCount, pConfigChooserMatcher);
}
eglConfigCount = this.getEGLConfigCount(pEGL, pEGLDisplay, this.mNvidiaCoverageMultiSampleEGLConfig);
if (eglConfigCount > 0) {
this.mActualCoverageMultiSampling = true;
return this.findEGLConfig(pEGL, pEGLDisplay, this.mNvidiaCoverageMultiSampleEGLConfig, eglConfigCount, pConfigChooserMatcher);
}
}
eglConfigCount = this.getEGLConfigCount(pEGL, pEGLDisplay, this.mDefaultEGLConfig);
if (eglConfigCount > 0) {
return this.findEGLConfig(pEGL, pEGLDisplay, this.mDefaultEGLConfig, eglConfigCount, pConfigChooserMatcher);
} else {
throw new IllegalArgumentException("No " + EGLConfig.class.getSimpleName() + " found!");
}
}
// ===========================================================
// Methods
// ===========================================================
private int getEGLConfigCount(final EGL10 pEGL, final EGLDisplay pEGLDisplay, final int[] pEGLConfigAttributes) {
if (pEGL.eglChooseConfig(pEGLDisplay, pEGLConfigAttributes, null, 0, ConfigChooser.BUFFER) == false) {
throw new IllegalArgumentException("EGLCONFIG_FALLBACK failed!");
}
return ConfigChooser.BUFFER[0];
}
private EGLConfig findEGLConfig(final EGL10 pEGL, final EGLDisplay pEGLDisplay, final int[] pEGLConfigAttributes, final int pEGLConfigCount, final ConfigChooserMatcher pConfigChooserMatcher) {
final EGLConfig[] eglConfigs = new EGLConfig[pEGLConfigCount];
if (!pEGL.eglChooseConfig(pEGLDisplay, pEGLConfigAttributes, eglConfigs, pEGLConfigCount, ConfigChooser.BUFFER)) {
throw new IllegalArgumentException("findEGLConfig failed!");
}
return this.findEGLConfig(pEGL, pEGLDisplay, eglConfigs, pConfigChooserMatcher);
}
private EGLConfig findEGLConfig(final EGL10 pEGL, final EGLDisplay pEGLDisplay, final EGLConfig[] pEGLConfigs, final ConfigChooserMatcher pConfigChooserMatcher) {
for (int i = 0; i < pEGLConfigs.length; ++i) {
final EGLConfig config = pEGLConfigs[i];
if (config != null) {
final int redSize = this.getConfigAttrib(pEGL, pEGLDisplay, config, EGL10.EGL_RED_SIZE, 0);
final int greenSize = this.getConfigAttrib(pEGL, pEGLDisplay, config, EGL10.EGL_GREEN_SIZE, 0);
final int blueSize = this.getConfigAttrib(pEGL, pEGLDisplay, config, EGL10.EGL_BLUE_SIZE, 0);
final int alphaSize = this.getConfigAttrib(pEGL, pEGLDisplay, config, EGL10.EGL_ALPHA_SIZE, 0);
final int depthSize = this.getConfigAttrib(pEGL, pEGLDisplay, config, EGL10.EGL_DEPTH_SIZE, 0);
final int stencilSize = this.getConfigAttrib(pEGL, pEGLDisplay, config, EGL10.EGL_STENCIL_SIZE, 0);
if (pConfigChooserMatcher.matches(this.mRequestedRedSize, redSize, this.mRequestedGreenSize, greenSize, this.mRequestedBlueSize, blueSize, this.mRequestedAlphaSize, alphaSize, this.mRequestedDepthSize, depthSize, this.mRequestedStencilSize, stencilSize)) {
this.mActualRedSize = redSize;
this.mActualGreenSize = greenSize;
this.mActualBlueSize = blueSize;
this.mActualAlphaSize = alphaSize;
this.mActualDepthSize = depthSize;
this.mActualStencilSize = stencilSize;
return config;
}
}
}
throw new IllegalArgumentException("No EGLConfig found!");
}
private int getConfigAttrib(final EGL10 pEGL, final EGLDisplay pEGLDisplay, final EGLConfig pEGLConfig, final int pAttribute, final int pDefaultValue) {
if (pEGL.eglGetConfigAttrib(pEGLDisplay, pEGLConfig, pAttribute, ConfigChooser.BUFFER)) {
return ConfigChooser.BUFFER[0];
} else {
return pDefaultValue;
}
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}