From: christoph.widulle Date: Fri, 31 Dec 2010 04:08:42 +0000 (+0000) Subject: [added] ResolutionStrategy X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=e495dd75c8912910bbba5907fbcd5347c962c410;p=mikumikustudio%2Flibgdx-mikumikustudio.git [added] ResolutionStrategy --- diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidApplication.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidApplication.java index 993def6a7..d30bdd548 100644 --- a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidApplication.java +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidApplication.java @@ -19,10 +19,12 @@ import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.util.Log; +import android.view.Gravity; import android.view.View; import android.view.Window; import android.view.WindowManager; +import android.widget.FrameLayout; import com.badlogic.gdx.Application; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Audio; @@ -31,206 +33,229 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Graphics; import com.badlogic.gdx.Input; import com.badlogic.gdx.Version; +import com.badlogic.gdx.backends.android.surfaceview.FillResolutionStrategy; import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceViewCupcake; +import com.badlogic.gdx.backends.android.surfaceview.ResolutionStrategy; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.GL11; /** * An implementation of the {@link Application} interface for Android. Create an {@link Activity} that derives from this class. In - * the {@link Activity#onCreate(Bundle)} method call the {@link #initialize(ApplicationListener,boolean)} method specifying the + * the {@link Activity#onCreate(Bundle)} method call the {@link #initialize(ApplicationListener, boolean)} method specifying the * configuration for the GLSurfaceView. - * + * * @author mzechner */ public class AndroidApplication extends Activity implements Application { - static { - Version.loadLibrary(); - } - - protected AndroidGraphics graphics; - protected AndroidInput input; - protected AndroidAudio audio; - protected AndroidFiles files; - protected ApplicationListener listener; - protected Handler handler; - protected boolean firstResume = true; - - /** - * This method has to be called in the {@link Activity#onCreate(Bundle)} method. It sets up all the things necessary to get - * input, render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 - * context which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be - * used when OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the - * {@link Graphics#isGL20Available()} method. Sleep time in touch event handler is 0, so no sleeping is performed. - * - * @param listener the {@link ApplicationListener} implementing the program logic - * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available. - */ - public void initialize (ApplicationListener listener, boolean useGL2IfAvailable) { - initialize(listener, useGL2IfAvailable, 0); - } - - /** - * This method has to be called in the {@link Activity#onCreate(Bundle)} method. It sets up all the things necessary to get - * input, render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 - * context which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be - * used when OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the - * {@link Graphics#isGL20Available()} method. sleepTime specifies the number of milliseconds to sleep in the touch event - * handler. This may be used on <= 1.6 Android devices. Note that it will not solve the CPU usage problem of the event handler - * of the Android system. Things will still slow down. - * - * @param listener the {@link ApplicationListener} implementing the program logic - * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available. - * @param sleepTime specifies the number of milliseconds to sleep in the touch event handler - */ - public void initialize (ApplicationListener listener, boolean useGL2IfAvailable, int sleepTime) { - graphics = new AndroidGraphics(this, useGL2IfAvailable); - input = new AndroidInput(this, graphics.view, sleepTime); - audio = new AndroidAudio(this); - files = new AndroidFiles(this.getAssets()); - this.listener = listener; - this.handler = new Handler(); - - Gdx.app = this; - Gdx.input = this.getInput(); - Gdx.audio = this.getAudio(); - Gdx.files = this.getFiles(); - Gdx.graphics = this.getGraphics(); - - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - setContentView(graphics.getView()); - } - - /** - * This method has to be called in the {@link Activity#onCreate(Bundle)} method. It sets up all the things necessary to get - * input, render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 - * context which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be - * used when OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the - * {@link Graphics#isGL20Available()} method. sleepTime specifies the number of milliseconds to sleep in the touch event - * handler. This may be used on <= 1.6 Android devices. Note that it will not solve the CPU usage problem of the event handler - * of the Android system. Things will still slow down. - * - * Note: you have to add the returned view to your layout! - * - * @param listener the {@link ApplicationListener} implementing the program logic - * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available. - * @param sleepTime specifies the number of milliseconds to sleep in the touch event handler - * @return the GLSurfaceView of the application - */ - public View initializeForView (ApplicationListener listener, boolean useGL2IfAvailable, int sleepTime) { - graphics = new AndroidGraphics(this, useGL2IfAvailable); - input = new AndroidInput(this, graphics.view, sleepTime); - audio = new AndroidAudio(this); - files = new AndroidFiles(this.getAssets()); - this.listener = listener; - this.handler = new Handler(); - - Gdx.app = this; - Gdx.input = this.getInput(); - Gdx.audio = this.getAudio(); - Gdx.files = this.getFiles(); - Gdx.graphics = this.getGraphics(); - - return graphics.getView(); - } - - @Override protected void onPause () { - graphics.pause(); - - if (isFinishing()) { - graphics.clearManagedCaches(); - graphics.destroy(); - } - - if (graphics != null && graphics.view != null) { - if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake)graphics.view).onPause(); - if (graphics.view instanceof android.opengl.GLSurfaceView) ((android.opengl.GLSurfaceView)graphics.view).onPause(); - } - - if (audio != null) audio.pause(); - super.onPause(); - } - - @Override protected void onResume () { - Gdx.app = this; - Gdx.input = this.getInput(); - Gdx.audio = this.getAudio(); - Gdx.files = this.getFiles(); - Gdx.graphics = this.getGraphics(); - - if (graphics != null && graphics.view != null) { - if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake)graphics.view).onResume(); - if (graphics.view instanceof android.opengl.GLSurfaceView) ((android.opengl.GLSurfaceView)graphics.view).onResume(); - } - - if (audio != null) audio.resume(); - if (!firstResume) - graphics.resume(); - else - firstResume = false; - super.onResume(); - } - - @Override protected void onDestroy () { - audio.dispose(); - super.onDestroy(); - } - - /** - * {@inheritDoc} - */ - @Override public Audio getAudio () { - return audio; - } - - /** - * {@inheritDoc} - */ - @Override public Files getFiles () { - return files; - } - - /** - * {@inheritDoc} - */ - @Override public Graphics getGraphics () { - return graphics; - } - - /** - * {@inheritDoc} - */ - @Override public Input getInput () { - return input; - } - - /** - * {@inheritDoc} - */ - @Override public void log (String tag, String message) { - Log.d(tag, message); - } - - /** - * {@inheritDoc} - */ - @Override public ApplicationType getType () { - return ApplicationType.Android; - } - - /** - * {@inheritDoc} - */ - @Override public int getVersion () { - return Build.VERSION.SDK.charAt(0) - '0'; - } - - @Override public long getJavaHeap () { - return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); - } - - @Override public long getNativeHeap () { - return Debug.getNativeHeapAllocatedSize(); - } + static { + Version.loadLibrary(); + } + + protected AndroidGraphics graphics; + protected AndroidInput input; + protected AndroidAudio audio; + protected AndroidFiles files; + protected ApplicationListener listener; + protected Handler handler; + protected boolean firstResume = true; + + /** + * This method has to be called in the {@link Activity#onCreate(Bundle)} method. It sets up all the things necessary to get + * input, render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 + * context which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be + * used when OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the + * {@link Graphics#isGL20Available()} method. Sleep time in touch event handler is 0, so no sleeping is performed. + * + * @param listener the {@link ApplicationListener} implementing the program logic + * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available. + */ + public void initialize(ApplicationListener listener, boolean useGL2IfAvailable) { + initialize(listener, useGL2IfAvailable, new FillResolutionStrategy(), 0); + } + + /** + * This method has to be called in the {@link Activity#onCreate(Bundle)} method. It sets up all the things necessary to get + * input, render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 + * context which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be + * used when OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the + * {@link Graphics#isGL20Available()} method. sleepTime specifies the number of milliseconds to sleep in the touch event + * handler. This may be used on <= 1.6 Android devices. Note that it will not solve the CPU usage problem of the event handler + * of the Android system. Things will still slow down. + * + * @param listener the {@link ApplicationListener} implementing the program logic + * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available. + * @param sleepTime specifies the number of milliseconds to sleep in the touch event handler + */ + public void initialize(ApplicationListener listener, boolean useGL2IfAvailable, ResolutionStrategy resolutionStrategy, int sleepTime) { + graphics = new AndroidGraphics(this, useGL2IfAvailable, resolutionStrategy); + input = new AndroidInput(this, graphics.view, sleepTime); + audio = new AndroidAudio(this); + files = new AndroidFiles(this.getAssets()); + this.listener = listener; + this.handler = new Handler(); + + Gdx.app = this; + Gdx.input = this.getInput(); + Gdx.audio = this.getAudio(); + Gdx.files = this.getFiles(); + Gdx.graphics = this.getGraphics(); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + setContentView(graphics.getView(), createLayoutParams()); + } + + protected FrameLayout.LayoutParams createLayoutParams() { + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.FILL_PARENT); + layoutParams.gravity = Gravity.CENTER; + return layoutParams; + } + + /** + * This method has to be called in the {@link Activity#onCreate(Bundle)} method. It sets up all the things necessary to get + * input, render via OpenGL and so on. If useGL20IfAvailable is set the AndroidApplication will try to create an OpenGL ES 2.0 + * context which can then be used via {@link Graphics#getGL20()}. The {@link GL10} and {@link GL11} interfaces should not be + * used when OpenGL ES 2.0 is enabled. To query whether enabling OpenGL ES 2.0 was successful use the + * {@link Graphics#isGL20Available()} method. sleepTime specifies the number of milliseconds to sleep in the touch event + * handler. This may be used on <= 1.6 Android devices. Note that it will not solve the CPU usage problem of the event handler + * of the Android system. Things will still slow down. + *

+ * Note: you have to add the returned view to your layout! + * + * @param listener the {@link ApplicationListener} implementing the program logic + * @param useGL2IfAvailable whether to use OpenGL ES 2.0 if its available. + * @param sleepTime specifies the number of milliseconds to sleep in the touch event handler + * @return the GLSurfaceView of the application + */ + public View initializeForView(ApplicationListener listener, boolean useGL2IfAvailable, ResolutionStrategy resolutionStrategy, int sleepTime) { + graphics = new AndroidGraphics(this, useGL2IfAvailable, resolutionStrategy); + input = new AndroidInput(this, graphics.view, sleepTime); + audio = new AndroidAudio(this); + files = new AndroidFiles(this.getAssets()); + this.listener = listener; + this.handler = new Handler(); + + Gdx.app = this; + Gdx.input = this.getInput(); + Gdx.audio = this.getAudio(); + Gdx.files = this.getFiles(); + Gdx.graphics = this.getGraphics(); + + return graphics.getView(); + } + + @Override + protected void onPause() { + graphics.pause(); + + if (isFinishing()) { + graphics.clearManagedCaches(); + graphics.destroy(); + } + + if (graphics != null && graphics.view != null) { + if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake) graphics.view).onPause(); + if (graphics.view instanceof android.opengl.GLSurfaceView) + ((android.opengl.GLSurfaceView) graphics.view).onPause(); + } + + if (audio != null) audio.pause(); + super.onPause(); + } + + @Override + protected void onResume() { + Gdx.app = this; + Gdx.input = this.getInput(); + Gdx.audio = this.getAudio(); + Gdx.files = this.getFiles(); + Gdx.graphics = this.getGraphics(); + + if (graphics != null && graphics.view != null) { + if (graphics.view instanceof GLSurfaceViewCupcake) ((GLSurfaceViewCupcake) graphics.view).onResume(); + if (graphics.view instanceof android.opengl.GLSurfaceView) + ((android.opengl.GLSurfaceView) graphics.view).onResume(); + } + + if (audio != null) audio.resume(); + if (!firstResume) + graphics.resume(); + else + firstResume = false; + super.onResume(); + } + + @Override + protected void onDestroy() { + audio.dispose(); + super.onDestroy(); + } + + /** + * {@inheritDoc} + */ + @Override + public Audio getAudio() { + return audio; + } + + /** + * {@inheritDoc} + */ + @Override + public Files getFiles() { + return files; + } + + /** + * {@inheritDoc} + */ + @Override + public Graphics getGraphics() { + return graphics; + } + + /** + * {@inheritDoc} + */ + @Override + public Input getInput() { + return input; + } + + /** + * {@inheritDoc} + */ + @Override + public void log(String tag, String message) { + Log.d(tag, message); + } + + /** + * {@inheritDoc} + */ + @Override + public ApplicationType getType() { + return ApplicationType.Android; + } + + /** + * {@inheritDoc} + */ + @Override + public int getVersion() { + return Build.VERSION.SDK.charAt(0) - '0'; + } + + @Override + public long getJavaHeap() { + return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); + } + + @Override + public long getNativeHeap() { + return Debug.getNativeHeapAllocatedSize(); + } } diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidGraphics.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidGraphics.java index 9585ee8d2..0fe57eeef 100644 --- a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidGraphics.java +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidGraphics.java @@ -13,13 +13,6 @@ package com.badlogic.gdx.backends.android; -import java.io.InputStream; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; - import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -29,496 +22,519 @@ import android.os.Build; import android.util.DisplayMetrics; import android.view.Display; import android.view.View; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Graphics; -import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceView20; -import com.badlogic.gdx.backends.android.surfaceview.GLSurfaceViewCupcake; +import com.badlogic.gdx.backends.android.surfaceview.*; import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.GL10; -import com.badlogic.gdx.graphics.GL11; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.GLCommon; -import com.badlogic.gdx.graphics.Mesh; -import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.*; import com.badlogic.gdx.graphics.Pixmap.Format; -import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.Texture.TextureWrap; -import com.badlogic.gdx.graphics.TextureData; import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.math.WindowedMean; import com.badlogic.gdx.utils.GdxRuntimeException; import com.badlogic.gdx.utils.MathUtils; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import java.io.InputStream; + /** * An implementation of {@link Graphics} for Android. - * + * * @author mzechner */ public final class AndroidGraphics implements Graphics, Renderer { - final View view; - int width; - int height; - AndroidApplication app; - GLCommon gl; - GL10 gl10; - GL11 gl11; - GL20 gl20; - - private long lastFrameTime = System.nanoTime(); - private float deltaTime = 0; - private long frameStart = System.nanoTime(); - private int frames = 0; - private int fps; - private WindowedMean mean = new WindowedMean(5); - - volatile boolean created = false; - volatile boolean running = false; - volatile boolean pause = false; - volatile boolean resume = false; - volatile boolean destroy = false; - - private float ppiX = 0; - private float ppiY = 0; - private float ppcX = 0; - private float ppcY = 0; - - public AndroidGraphics (AndroidApplication activity, boolean useGL2IfAvailable) { - view = createGLSurfaceView(activity, useGL2IfAvailable); - this.app = activity; - } - - private View createGLSurfaceView (Activity activity, boolean useGL2) { - EGLConfigChooser configChooser = getEglConfigChooser(); - - if (useGL2 && checkGL20()) { - GLSurfaceView20 view = new GLSurfaceView20(activity); - if (configChooser != null) view.setEGLConfigChooser(configChooser); - view.setRenderer(this); - return view; - } else { - if (Integer.parseInt(android.os.Build.VERSION.SDK) <= 4) { - GLSurfaceViewCupcake view = new GLSurfaceViewCupcake(activity); - if (configChooser != null) view.setEGLConfigChooser(configChooser); - view.setRenderer(this); - return view; - } else { - android.opengl.GLSurfaceView view = new android.opengl.GLSurfaceView(activity); - if (configChooser != null) view.setEGLConfigChooser(configChooser); - view.setRenderer(this); - return view; - } - } - } - - private EGLConfigChooser getEglConfigChooser () { - if (!Build.DEVICE.equalsIgnoreCase("GT-I7500")) - return null; - else - return new android.opengl.GLSurfaceView.EGLConfigChooser() { - - public EGLConfig chooseConfig (EGL10 egl, EGLDisplay display) { - - // Ensure that we get a 16bit depth-buffer. Otherwise, we'll fall - // back to Pixelflinger on some device (read: Samsung I7500) - int[] attributes = new int[] {EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE}; - EGLConfig[] configs = new EGLConfig[1]; - int[] result = new int[1]; - egl.eglChooseConfig(display, attributes, configs, 1, result); - return configs[0]; - } - }; - } - - private void updatePpi () { - DisplayMetrics metrics = new DisplayMetrics(); - app.getWindowManager().getDefaultDisplay().getMetrics(metrics); - - ppiX = metrics.xdpi; - ppiY = metrics.ydpi; - ppcX = metrics.xdpi / 2.54f; - ppcY = metrics.ydpi / 2.54f; - } - - private boolean checkGL20 () { - EGL10 egl = (EGL10)EGLContext.getEGL(); - EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - - int[] version = new int[2]; - egl.eglInitialize(display, version); - - int EGL_OPENGL_ES2_BIT = 4; - int[] configAttribs = {EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, EGL10.EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE}; - - EGLConfig[] configs = new EGLConfig[10]; - int[] num_config = new int[1]; - egl.eglChooseConfig(display, configAttribs, configs, 10, num_config); - egl.eglTerminate(display); - return num_config[0] > 0; - } - - /** - * {@inheritDoc} - */ - @Override public GL10 getGL10 () { - return gl10; - } - - /** - * {@inheritDoc} - */ - @Override public GL11 getGL11 () { - return gl11; - } - - /** - * {@inheritDoc} - */ - @Override public GL20 getGL20 () { - return gl20; - } - - /** - * {@inheritDoc} - */ - @Override public int getHeight () { - return height; - } - - /** - * {@inheritDoc} - */ - @Override public int getWidth () { - return width; - } - - /** - * {@inheritDoc} - */ - @Override public boolean isGL11Available () { - return gl11 != null; - } - - /** - * {@inheritDoc} - */ - @Override public boolean isGL20Available () { - return gl20 != null; - } - - private static boolean isPowerOfTwo (int value) { - return ((value != 0) && (value & (value - 1)) == 0); - } - - /** - * {@inheritDoc} - */ - @Override public Pixmap newPixmap (int width, int height, Format format) { - return new AndroidPixmap(width, height, format); - } - - /** - * {@inheritDoc} - */ - @Override public Pixmap newPixmap (InputStream in) { - Bitmap bitmap = BitmapFactory.decodeStream(in); - if (bitmap == null) throw new GdxRuntimeException("Couldn't load Pixmap from InputStream"); - return new AndroidPixmap(bitmap); - } - - /** - * {@inheritDoc} - */ - @Override public Pixmap newPixmap (FileHandle file) { - return newPixmap(file.read()); - } - - /** - * {@inheritDoc} - */ - @Override public Pixmap newPixmap (Object nativePixmap) { - return new AndroidPixmap((Bitmap)nativePixmap); - } - - /** - * This instantiates the GL10, GL11 and GL20 instances. Includes the check for certain devices that pretend to support GL11 but - * fuck up vertex buffer objects. This includes the pixelflinger which segfaults when buffers are deleted as well as the - * Motorola CLIQ and the Samsung Behold II. - * - * @param gl - */ - private void setupGL (javax.microedition.khronos.opengles.GL10 gl) { - if (gl10 != null || gl20 != null) return; - - if (view instanceof GLSurfaceView20) { - gl20 = new AndroidGL20(); - this.gl = gl20; - } else { - gl10 = new AndroidGL10(gl); - this.gl = gl10; - if (gl instanceof javax.microedition.khronos.opengles.GL11) { - String renderer = gl.glGetString(GL10.GL_RENDERER); - if (!renderer.toLowerCase().contains("pixelflinger") - && !(android.os.Build.MODEL.equals("MB200") || android.os.Build.MODEL.equals("MB220") || android.os.Build.MODEL - .contains("Behold"))) { - gl11 = new AndroidGL11((javax.microedition.khronos.opengles.GL11)gl); - gl10 = gl11; - } - } - } - - Gdx.gl = this.gl; - Gdx.gl10 = gl10; - Gdx.gl11 = gl11; - Gdx.gl20 = gl20; - - Gdx.app.log("AndroidGraphics", "OGL renderer: " + gl.glGetString(GL10.GL_RENDERER)); - Gdx.app.log("AndroidGraphics", "OGL vendor: " + gl.glGetString(GL10.GL_VENDOR)); - Gdx.app.log("AndroidGraphics", "OGL version: " + gl.glGetString(GL10.GL_VERSION)); - Gdx.app.log("AndroidGraphics", "OGL extensions: " + gl.glGetString(GL10.GL_EXTENSIONS)); - } - - @Override public void onSurfaceChanged (javax.microedition.khronos.opengles.GL10 gl, int width, int height) { - this.width = width; - this.height = height; - updatePpi(); - app.listener.resize(width, height); - } - - @Override public void onSurfaceCreated (javax.microedition.khronos.opengles.GL10 gl, EGLConfig config) { - setupGL(gl); - logConfig(config); - updatePpi(); - - Mesh.invalidateAllMeshes(); - AndroidTexture.invalidateAllTextures(); - ShaderProgram.invalidateAllShaderPrograms(); - FrameBuffer.invalidateAllFrameBuffers(); - - Display display = app.getWindowManager().getDefaultDisplay(); - this.width = display.getWidth(); - this.height = display.getHeight(); - mean = new WindowedMean(5); - this.lastFrameTime = System.nanoTime(); - - gl.glViewport(0, 0, this.width, this.height); - - if (created == false) { - app.listener.create(); - created = true; - synchronized (this) { - running = true; - } - } - } - - private void logConfig (EGLConfig config) { - EGL10 egl = (EGL10)EGLContext.getEGL(); - EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - int r = getAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); - int g = getAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0); - int b = getAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0); - int a = getAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); - int d = getAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); - int s = getAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); - - Gdx.app.log("AndroidGraphics", "framebuffer: (" + r + ", " + g + ", " + b + ", " + a + ")"); - Gdx.app.log("AndroidGraphics", "depthbuffer: (" + d + ")"); - Gdx.app.log("AndroidGraphics", "stencilbuffer: (" + s + ")"); - } - - int[] value = new int[1]; - - private int getAttrib (EGL10 egl, EGLDisplay display, EGLConfig config, int attrib, int defValue) { - if (egl.eglGetConfigAttrib(display, config, attrib, value)) { - return value[0]; - } - return defValue; - } - - Object synch = new Object(); - - void resume () { - synchronized (synch) { - running = true; - resume = true; - } - } - - void pause () { - synchronized (synch) { - running = false; - pause = true; - while (pause) { - try { - synch.wait(); - } catch (InterruptedException ignored) { - } - } - } - } - - void destroy () { - synchronized (synch) { - running = false; - destroy = true; - - while (destroy) { - try { - synch.wait(); - } catch (InterruptedException ex) { - } - } - } - } - - @Override public void onDrawFrame (javax.microedition.khronos.opengles.GL10 gl) { - long time = System.nanoTime(); - deltaTime = (time - lastFrameTime) / 1000000000.0f; - lastFrameTime = time; - mean.addValue(deltaTime); - - boolean lrunning = false; - boolean lpause = false; - boolean ldestroy = false; - boolean lresume = false; - - synchronized (synch) { - lrunning = running; - lpause = pause; - ldestroy = destroy; - lresume = resume; - - if (resume) { - resume = false; - } - - if (pause) { - pause = false; - synch.notifyAll(); - } - - if (destroy) { - destroy = false; - synch.notifyAll(); - } - } - - if (lresume) { - app.listener.resume(); - Gdx.app.log("AndroidGraphics", "resumed"); - } - - if (lrunning) { - app.input.processEvents(); - app.listener.render(); - } - - if (lpause) { - app.listener.pause(); - Gdx.app.log("AndroidGraphics", "paused"); - } - - if (ldestroy) { - app.listener.dispose(); - Gdx.app.log("AndroidGraphics", "destroyed"); - } - - if (time - frameStart > 1000000000) { - fps = frames; - frames = 0; - frameStart = time; - } - frames++; - } - - /** - * {@inheritDoc} - */ - @Override public float getDeltaTime () { - return mean.getMean() == 0 ? deltaTime : mean.getMean(); - } - - /** - * {@inheritDoc} - */ - @Override public GraphicsType getType () { - return GraphicsType.AndroidGL; - } - - /** - * {@inheritDoc} - */ - @Override public int getFramesPerSecond () { - return fps; - } - - @Override public Texture newUnmanagedTexture (int width, int height, Format format, TextureFilter minFilter, - TextureFilter magFilter, TextureWrap uWrap, TextureWrap vWrap) { - if (gl != gl20 && (!MathUtils.isPowerOfTwo(width) || !MathUtils.isPowerOfTwo(height))) - throw new GdxRuntimeException("Dimensions have to be a power of two"); - - Bitmap.Config config = AndroidPixmap.getInternalFormat(format); - Bitmap bitmap = Bitmap.createBitmap(width, height, config); - Texture texture = null; - texture = new AndroidTexture(this, bitmap, minFilter, magFilter, uWrap, vWrap, false, null); - bitmap.recycle(); - return texture; - } - - @Override public Texture newUnmanagedTexture (Pixmap pixmap, TextureFilter minFilter, TextureFilter magFilter, - TextureWrap uWrap, TextureWrap vWrap) { - - if (gl != gl20 && (!MathUtils.isPowerOfTwo(pixmap.getWidth()) || !MathUtils.isPowerOfTwo(pixmap.getHeight()))) - throw new GdxRuntimeException("Dimensions have to be a power of two"); - - return new AndroidTexture(this, (Bitmap)pixmap.getNativePixmap(), minFilter, magFilter, uWrap, vWrap, false, null); - } - - @Override public Texture newTexture (FileHandle file, TextureFilter minFilter, TextureFilter magFilter, TextureWrap uWrap, - TextureWrap vWrap) { - return new AndroidTexture(this, (Bitmap)null, minFilter, magFilter, uWrap, vWrap, true, file); - } - - @Override public Texture newTexture (TextureData textureData, TextureFilter minFilter, TextureFilter magFilter, - TextureWrap uWrap, TextureWrap vWrap) { - return new AndroidTexture(this, textureData, minFilter, magFilter, uWrap, vWrap); - } - - public void clearManagedCaches () { - Mesh.clearAllMeshes(); - AndroidTexture.clearAllTextures(); - ShaderProgram.clearAllShaderPrograms(); - FrameBuffer.clearAllFrameBuffers(); - } - - public View getView () { - return view; - } - - /** - * {@inheritDoc} - */ - @Override public GLCommon getGLCommon () { - return gl; - } - - @Override public float getPpiX () { - return ppiX; - } - - @Override public float getPpiY () { - return ppiY; - } - - @Override public float getPpcX () { - return ppcX; - } - - @Override public float getPpcY () { - return ppcY; - } + final View view; + int width; + int height; + AndroidApplication app; + GLCommon gl; + GL10 gl10; + GL11 gl11; + GL20 gl20; + + private long lastFrameTime = System.nanoTime(); + private float deltaTime = 0; + private long frameStart = System.nanoTime(); + private int frames = 0; + private int fps; + private WindowedMean mean = new WindowedMean(5); + + volatile boolean created = false; + volatile boolean running = false; + volatile boolean pause = false; + volatile boolean resume = false; + volatile boolean destroy = false; + + private float ppiX = 0; + private float ppiY = 0; + private float ppcX = 0; + private float ppcY = 0; + + public AndroidGraphics(AndroidApplication activity, boolean useGL2IfAvailable, ResolutionStrategy resolutionStrategy) { + view = createGLSurfaceView(activity, useGL2IfAvailable, resolutionStrategy); + this.app = activity; + } + + private View createGLSurfaceView(Activity activity, boolean useGL2, ResolutionStrategy resolutionStrategy) { + EGLConfigChooser configChooser = getEglConfigChooser(); + + if (useGL2 && checkGL20()) { + GLSurfaceView20 view = new GLSurfaceView20(activity, resolutionStrategy); + if (configChooser != null) view.setEGLConfigChooser(configChooser); + view.setRenderer(this); + return view; + } else { + if (Integer.parseInt(android.os.Build.VERSION.SDK) <= 4) { + GLSurfaceViewCupcake view = new GLSurfaceViewCupcake(activity, resolutionStrategy); + if (configChooser != null) view.setEGLConfigChooser(configChooser); + view.setRenderer(this); + return view; + } else { + android.opengl.GLSurfaceView view = new DefaultGLSurfaceView(activity, resolutionStrategy); + if (configChooser != null) view.setEGLConfigChooser(configChooser); + view.setRenderer(this); + return view; + } + } + } + + private EGLConfigChooser getEglConfigChooser() { + if (!Build.DEVICE.equalsIgnoreCase("GT-I7500")) + return null; + else + return new android.opengl.GLSurfaceView.EGLConfigChooser() { + + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + + // Ensure that we get a 16bit depth-buffer. Otherwise, we'll fall + // back to Pixelflinger on some device (read: Samsung I7500) + int[] attributes = new int[]{EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE}; + EGLConfig[] configs = new EGLConfig[1]; + int[] result = new int[1]; + egl.eglChooseConfig(display, attributes, configs, 1, result); + return configs[0]; + } + }; + } + + private void updatePpi() { + DisplayMetrics metrics = new DisplayMetrics(); + app.getWindowManager().getDefaultDisplay().getMetrics(metrics); + + ppiX = metrics.xdpi; + ppiY = metrics.ydpi; + ppcX = metrics.xdpi / 2.54f; + ppcY = metrics.ydpi / 2.54f; + } + + private boolean checkGL20() { + EGL10 egl = (EGL10) EGLContext.getEGL(); + EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + int[] version = new int[2]; + egl.eglInitialize(display, version); + + int EGL_OPENGL_ES2_BIT = 4; + int[] configAttribs = {EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, EGL10.EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE}; + + EGLConfig[] configs = new EGLConfig[10]; + int[] num_config = new int[1]; + egl.eglChooseConfig(display, configAttribs, configs, 10, num_config); + egl.eglTerminate(display); + return num_config[0] > 0; + } + + /** + * {@inheritDoc} + */ + @Override + public GL10 getGL10() { + return gl10; + } + + /** + * {@inheritDoc} + */ + @Override + public GL11 getGL11() { + return gl11; + } + + /** + * {@inheritDoc} + */ + @Override + public GL20 getGL20() { + return gl20; + } + + /** + * {@inheritDoc} + */ + @Override + public int getHeight() { + return height; + } + + /** + * {@inheritDoc} + */ + @Override + public int getWidth() { + return width; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isGL11Available() { + return gl11 != null; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isGL20Available() { + return gl20 != null; + } + + private static boolean isPowerOfTwo(int value) { + return ((value != 0) && (value & (value - 1)) == 0); + } + + /** + * {@inheritDoc} + */ + @Override + public Pixmap newPixmap(int width, int height, Format format) { + return new AndroidPixmap(width, height, format); + } + + /** + * {@inheritDoc} + */ + @Override + public Pixmap newPixmap(InputStream in) { + Bitmap bitmap = BitmapFactory.decodeStream(in); + if (bitmap == null) throw new GdxRuntimeException("Couldn't load Pixmap from InputStream"); + return new AndroidPixmap(bitmap); + } + + /** + * {@inheritDoc} + */ + @Override + public Pixmap newPixmap(FileHandle file) { + return newPixmap(file.read()); + } + + /** + * {@inheritDoc} + */ + @Override + public Pixmap newPixmap(Object nativePixmap) { + return new AndroidPixmap((Bitmap) nativePixmap); + } + + /** + * This instantiates the GL10, GL11 and GL20 instances. Includes the check for certain devices that pretend to support GL11 but + * fuck up vertex buffer objects. This includes the pixelflinger which segfaults when buffers are deleted as well as the + * Motorola CLIQ and the Samsung Behold II. + * + * @param gl + */ + private void setupGL(javax.microedition.khronos.opengles.GL10 gl) { + if (gl10 != null || gl20 != null) return; + + if (view instanceof GLSurfaceView20) { + gl20 = new AndroidGL20(); + this.gl = gl20; + } else { + gl10 = new AndroidGL10(gl); + this.gl = gl10; + if (gl instanceof javax.microedition.khronos.opengles.GL11) { + String renderer = gl.glGetString(GL10.GL_RENDERER); + if (!renderer.toLowerCase().contains("pixelflinger") + && !(android.os.Build.MODEL.equals("MB200") || android.os.Build.MODEL.equals("MB220") || android.os.Build.MODEL + .contains("Behold"))) { + gl11 = new AndroidGL11((javax.microedition.khronos.opengles.GL11) gl); + gl10 = gl11; + } + } + } + + Gdx.gl = this.gl; + Gdx.gl10 = gl10; + Gdx.gl11 = gl11; + Gdx.gl20 = gl20; + + Gdx.app.log("AndroidGraphics", "OGL renderer: " + gl.glGetString(GL10.GL_RENDERER)); + Gdx.app.log("AndroidGraphics", "OGL vendor: " + gl.glGetString(GL10.GL_VENDOR)); + Gdx.app.log("AndroidGraphics", "OGL version: " + gl.glGetString(GL10.GL_VERSION)); + Gdx.app.log("AndroidGraphics", "OGL extensions: " + gl.glGetString(GL10.GL_EXTENSIONS)); + } + + @Override + public void onSurfaceChanged(javax.microedition.khronos.opengles.GL10 gl, int width, int height) { + this.width = width; + this.height = height; + updatePpi(); + app.listener.resize(width, height); + } + + @Override + public void onSurfaceCreated(javax.microedition.khronos.opengles.GL10 gl, EGLConfig config) { + setupGL(gl); + logConfig(config); + updatePpi(); + + Mesh.invalidateAllMeshes(); + AndroidTexture.invalidateAllTextures(); + ShaderProgram.invalidateAllShaderPrograms(); + FrameBuffer.invalidateAllFrameBuffers(); + + Display display = app.getWindowManager().getDefaultDisplay(); + this.width = display.getWidth(); + this.height = display.getHeight(); + mean = new WindowedMean(5); + this.lastFrameTime = System.nanoTime(); + + gl.glViewport(0, 0, this.width, this.height); + + if (created == false) { + app.listener.create(); + created = true; + synchronized (this) { + running = true; + } + } + } + + private void logConfig(EGLConfig config) { + EGL10 egl = (EGL10) EGLContext.getEGL(); + EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + int r = getAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); + int g = getAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0); + int b = getAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0); + int a = getAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); + int d = getAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); + int s = getAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); + + Gdx.app.log("AndroidGraphics", "framebuffer: (" + r + ", " + g + ", " + b + ", " + a + ")"); + Gdx.app.log("AndroidGraphics", "depthbuffer: (" + d + ")"); + Gdx.app.log("AndroidGraphics", "stencilbuffer: (" + s + ")"); + } + + int[] value = new int[1]; + + private int getAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attrib, int defValue) { + if (egl.eglGetConfigAttrib(display, config, attrib, value)) { + return value[0]; + } + return defValue; + } + + Object synch = new Object(); + + void resume() { + synchronized (synch) { + running = true; + resume = true; + } + } + + void pause() { + synchronized (synch) { + running = false; + pause = true; + while (pause) { + try { + synch.wait(); + } catch (InterruptedException ignored) { + } + } + } + } + + void destroy() { + synchronized (synch) { + running = false; + destroy = true; + + while (destroy) { + try { + synch.wait(); + } catch (InterruptedException ex) { + } + } + } + } + + @Override + public void onDrawFrame(javax.microedition.khronos.opengles.GL10 gl) { + long time = System.nanoTime(); + deltaTime = (time - lastFrameTime) / 1000000000.0f; + lastFrameTime = time; + mean.addValue(deltaTime); + + boolean lrunning = false; + boolean lpause = false; + boolean ldestroy = false; + boolean lresume = false; + + synchronized (synch) { + lrunning = running; + lpause = pause; + ldestroy = destroy; + lresume = resume; + + if (resume) { + resume = false; + } + + if (pause) { + pause = false; + synch.notifyAll(); + } + + if (destroy) { + destroy = false; + synch.notifyAll(); + } + } + + if (lresume) { + app.listener.resume(); + Gdx.app.log("AndroidGraphics", "resumed"); + } + + if (lrunning) { + app.input.processEvents(); + app.listener.render(); + } + + if (lpause) { + app.listener.pause(); + Gdx.app.log("AndroidGraphics", "paused"); + } + + if (ldestroy) { + app.listener.dispose(); + Gdx.app.log("AndroidGraphics", "destroyed"); + } + + if (time - frameStart > 1000000000) { + fps = frames; + frames = 0; + frameStart = time; + } + frames++; + } + + /** + * {@inheritDoc} + */ + @Override + public float getDeltaTime() { + return mean.getMean() == 0 ? deltaTime : mean.getMean(); + } + + /** + * {@inheritDoc} + */ + @Override + public GraphicsType getType() { + return GraphicsType.AndroidGL; + } + + /** + * {@inheritDoc} + */ + @Override + public int getFramesPerSecond() { + return fps; + } + + @Override + public Texture newUnmanagedTexture(int width, int height, Format format, TextureFilter minFilter, + TextureFilter magFilter, TextureWrap uWrap, TextureWrap vWrap) { + if (gl != gl20 && (!MathUtils.isPowerOfTwo(width) || !MathUtils.isPowerOfTwo(height))) + throw new GdxRuntimeException("Dimensions have to be a power of two"); + + Bitmap.Config config = AndroidPixmap.getInternalFormat(format); + Bitmap bitmap = Bitmap.createBitmap(width, height, config); + Texture texture = null; + texture = new AndroidTexture(this, bitmap, minFilter, magFilter, uWrap, vWrap, false, null); + bitmap.recycle(); + return texture; + } + + @Override + public Texture newUnmanagedTexture(Pixmap pixmap, TextureFilter minFilter, TextureFilter magFilter, + TextureWrap uWrap, TextureWrap vWrap) { + + if (gl != gl20 && (!MathUtils.isPowerOfTwo(pixmap.getWidth()) || !MathUtils.isPowerOfTwo(pixmap.getHeight()))) + throw new GdxRuntimeException("Dimensions have to be a power of two"); + + return new AndroidTexture(this, (Bitmap) pixmap.getNativePixmap(), minFilter, magFilter, uWrap, vWrap, false, null); + } + + @Override + public Texture newTexture(FileHandle file, TextureFilter minFilter, TextureFilter magFilter, TextureWrap uWrap, + TextureWrap vWrap) { + return new AndroidTexture(this, (Bitmap) null, minFilter, magFilter, uWrap, vWrap, true, file); + } + + @Override + public Texture newTexture(TextureData textureData, TextureFilter minFilter, TextureFilter magFilter, + TextureWrap uWrap, TextureWrap vWrap) { + return new AndroidTexture(this, textureData, minFilter, magFilter, uWrap, vWrap); + } + + public void clearManagedCaches() { + Mesh.clearAllMeshes(); + AndroidTexture.clearAllTextures(); + ShaderProgram.clearAllShaderPrograms(); + FrameBuffer.clearAllFrameBuffers(); + } + + public View getView() { + return view; + } + + /** + * {@inheritDoc} + */ + @Override + public GLCommon getGLCommon() { + return gl; + } + + @Override + public float getPpiX() { + return ppiX; + } + + @Override + public float getPpiY() { + return ppiY; + } + + @Override + public float getPpcX() { + return ppcX; + } + + @Override + public float getPpcY() { + return ppcY; + } } diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/DefaultGLSurfaceView.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/DefaultGLSurfaceView.java new file mode 100644 index 000000000..973ac7262 --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/DefaultGLSurfaceView.java @@ -0,0 +1,27 @@ +package com.badlogic.gdx.backends.android.surfaceview; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; + +public class DefaultGLSurfaceView extends GLSurfaceView { + + + final ResolutionStrategy resolutionStrategy; + + public DefaultGLSurfaceView(Context context, ResolutionStrategy resolutionStrategy) { + super(context); + this.resolutionStrategy = resolutionStrategy; + } + + public DefaultGLSurfaceView(Context context, AttributeSet attrs, ResolutionStrategy resolutionStrategy) { + super(context, attrs); + this.resolutionStrategy = resolutionStrategy; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ResolutionStrategy.MeasuredDimension measures = resolutionStrategy.calcMeasures(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(measures.width, measures.height); + } +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/FillResolutionStrategy.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/FillResolutionStrategy.java new file mode 100644 index 000000000..e64e56bd1 --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/FillResolutionStrategy.java @@ -0,0 +1,16 @@ +package com.badlogic.gdx.backends.android.surfaceview; + +import android.view.View; + +public class FillResolutionStrategy implements ResolutionStrategy { + + + @Override + public MeasuredDimension calcMeasures(int widthMeasureSpec, int heightMeasureSpec) { + + final int width = View.MeasureSpec.getSize(widthMeasureSpec); + final int height = View.MeasureSpec.getSize(heightMeasureSpec); + + return new MeasuredDimension(width, height); + } +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/FixedResolutionStrategy.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/FixedResolutionStrategy.java new file mode 100644 index 000000000..ef0a7a5d1 --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/FixedResolutionStrategy.java @@ -0,0 +1,17 @@ +package com.badlogic.gdx.backends.android.surfaceview; + +public class FixedResolutionStrategy implements ResolutionStrategy { + + private final int width; + private final int height; + + public FixedResolutionStrategy(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public MeasuredDimension calcMeasures(int widthMeasureSpec, int heightMeasureSpec) { + return new MeasuredDimension(width, height); + } +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceView20.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceView20.java index 236de4504..0fc17771f 100644 --- a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceView20.java +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceView20.java @@ -26,218 +26,230 @@ package com.badlogic.gdx.backends.android.surfaceview; * governing permissions and limitations under the License. */ -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; - import android.content.Context; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; import android.util.Log; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; + /** * A simple GLSurfaceView sub-class that demonstrate how to perform OpenGL ES 2.0 rendering into a GL Surface. Note the following * important details: - * + *

* - The class must use a custom context factory to enable 2.0 rendering. See ContextFactory class definition below. - * + *

* - The class must use a custom EGLConfigChooser to be able to select an EGLConfig that supports 2.0. This is done by providing a * config specification to eglChooseConfig() that has the attribute EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT * flag set. See ConfigChooser class definition below. - * + *

* - The class must select the surface's format, then choose an EGLConfig that matches it exactly (with regards to * red/green/blue/alpha channels bit depths). Failure to do so would result in an EGL_BAD_MATCH error. */ public class GLSurfaceView20 extends GLSurfaceView { - static String TAG = "GL2JNIView"; - private static final boolean DEBUG = false; - - public GLSurfaceView20 (Context context) { - super(context); - init(false, 16, 0); - } - - public GLSurfaceView20 (Context context, boolean translucent, int depth, int stencil) { - super(context); - init(translucent, depth, stencil); - } - - private void init (boolean translucent, int depth, int stencil) { - - /* - * By default, GLSurfaceView() creates a RGB_565 opaque surface. If we want a translucent one, we should change the - * surface's format here, using PixelFormat.TRANSLUCENT for GL Surfaces is interpreted as any 32-bit surface with alpha by - * SurfaceFlinger. - */ - if (translucent) { - this.getHolder().setFormat(PixelFormat.TRANSLUCENT); - } - - /* - * Setup the context factory for 2.0 rendering. See ContextFactory class definition below - */ - setEGLContextFactory(new ContextFactory()); - - /* - * We need to choose an EGLConfig that matches the format of our surface exactly. This is going to be done in our custom - * config chooser. See ConfigChooser class definition below. - */ - setEGLConfigChooser(translucent ? new ConfigChooser(8, 8, 8, 8, depth, stencil) : new ConfigChooser(5, 6, 5, 0, depth, - stencil)); - - /* Set the renderer responsible for frame rendering */ - } - - static class ContextFactory implements GLSurfaceView.EGLContextFactory { - private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - - public EGLContext createContext (EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { - Log.w(TAG, "creating OpenGL ES 2.0 context"); - checkEglError("Before eglCreateContext", egl); - int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; - EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); - checkEglError("After eglCreateContext", egl); - return context; - } - - public void destroyContext (EGL10 egl, EGLDisplay display, EGLContext context) { - egl.eglDestroyContext(display, context); - } - } - - static void checkEglError (String prompt, EGL10 egl) { - int error; - while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { - Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); - } - } - - private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { - - public ConfigChooser (int r, int g, int b, int a, int depth, int stencil) { - mRedSize = r; - mGreenSize = g; - mBlueSize = b; - mAlphaSize = a; - mDepthSize = depth; - mStencilSize = stencil; - } - - /* - * This EGL config specification is used to specify 2.0 rendering. We use a minimum size of 4 bits for red/green/blue, but - * will perform actual matching in chooseConfig() below. - */ - private static int EGL_OPENGL_ES2_BIT = 4; - private static int[] s_configAttribs2 = {EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE}; - - public EGLConfig chooseConfig (EGL10 egl, EGLDisplay display) { - - /* - * Get the number of minimally matching EGL configurations - */ - int[] num_config = new int[1]; - egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); - - int numConfigs = num_config[0]; - - if (numConfigs <= 0) { - throw new IllegalArgumentException("No configs match configSpec"); - } - - /* - * Allocate then read the array of minimally matching EGL configs - */ - EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); - - if (DEBUG) { - printConfigs(egl, display, configs); - } - /* - * Now return the "best" one - */ - return chooseConfig(egl, display, configs); - } - - 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); - - // We need at least mDepthSize and mStencilSize bits - if (d < mDepthSize || s < mStencilSize) continue; - - // We want an *exact* match for red/green/blue/alpha - 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; - } - - private void printConfigs (EGL10 egl, EGLDisplay display, EGLConfig[] configs) { - int numConfigs = configs.length; - Log.w(TAG, String.format("%d configurations", numConfigs)); - for (int i = 0; i < numConfigs; i++) { - Log.w(TAG, String.format("Configuration %d:\n", i)); - printConfig(egl, display, configs[i]); - } - } - - private void printConfig (EGL10 egl, EGLDisplay display, EGLConfig config) { - int[] attributes = {EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, EGL10.EGL_BLUE_SIZE, EGL10.EGL_GREEN_SIZE, - EGL10.EGL_RED_SIZE, EGL10.EGL_DEPTH_SIZE, EGL10.EGL_STENCIL_SIZE, EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_CONFIG_ID, - EGL10.EGL_LEVEL, EGL10.EGL_MAX_PBUFFER_HEIGHT, EGL10.EGL_MAX_PBUFFER_PIXELS, EGL10.EGL_MAX_PBUFFER_WIDTH, - EGL10.EGL_NATIVE_RENDERABLE, EGL10.EGL_NATIVE_VISUAL_ID, EGL10.EGL_NATIVE_VISUAL_TYPE, - 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, - EGL10.EGL_SAMPLES, EGL10.EGL_SAMPLE_BUFFERS, EGL10.EGL_SURFACE_TYPE, EGL10.EGL_TRANSPARENT_TYPE, - EGL10.EGL_TRANSPARENT_RED_VALUE, EGL10.EGL_TRANSPARENT_GREEN_VALUE, EGL10.EGL_TRANSPARENT_BLUE_VALUE, 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, - 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, - 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, - 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, - EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE, EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE, 0x3042 // EGL10.EGL_CONFORMANT - }; - String[] names = {"EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE", "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE", - "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE", "EGL_CONFIG_CAVEAT", "EGL_CONFIG_ID", "EGL_LEVEL", "EGL_MAX_PBUFFER_HEIGHT", - "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH", "EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID", - "EGL_NATIVE_VISUAL_TYPE", "EGL_PRESERVED_RESOURCES", "EGL_SAMPLES", "EGL_SAMPLE_BUFFERS", "EGL_SURFACE_TYPE", - "EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE", "EGL_TRANSPARENT_GREEN_VALUE", "EGL_TRANSPARENT_BLUE_VALUE", - "EGL_BIND_TO_TEXTURE_RGB", "EGL_BIND_TO_TEXTURE_RGBA", "EGL_MIN_SWAP_INTERVAL", "EGL_MAX_SWAP_INTERVAL", - "EGL_LUMINANCE_SIZE", "EGL_ALPHA_MASK_SIZE", "EGL_COLOR_BUFFER_TYPE", "EGL_RENDERABLE_TYPE", "EGL_CONFORMANT"}; - int[] value = new int[1]; - for (int i = 0; i < attributes.length; i++) { - int attribute = attributes[i]; - String name = names[i]; - if (egl.eglGetConfigAttrib(display, config, attribute, value)) { - Log.w(TAG, String.format(" %s: %d\n", name, value[0])); - } else { - // Log.w(TAG, String.format(" %s: failed\n", name)); - while (egl.eglGetError() != EGL10.EGL_SUCCESS) - ; - } - } - } - - // Subclasses can adjust these values: - protected int mRedSize; - protected int mGreenSize; - protected int mBlueSize; - protected int mAlphaSize; - protected int mDepthSize; - protected int mStencilSize; - private int[] mValue = new int[1]; - } + static String TAG = "GL2JNIView"; + private static final boolean DEBUG = false; + + final ResolutionStrategy resolutionStrategy; + + public GLSurfaceView20(Context context, ResolutionStrategy resolutionStrategy) { + super(context); + this.resolutionStrategy = resolutionStrategy; + init(false, 16, 0); + } + + public GLSurfaceView20(Context context, boolean translucent, int depth, int stencil, ResolutionStrategy resolutionStrategy) { + super(context); + this.resolutionStrategy = resolutionStrategy; + init(translucent, depth, stencil); + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ResolutionStrategy.MeasuredDimension measures = resolutionStrategy.calcMeasures(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(measures.width, measures.height); + } + + private void init(boolean translucent, int depth, int stencil) { + + /* + * By default, GLSurfaceView() creates a RGB_565 opaque surface. If we want a translucent one, we should change the + * surface's format here, using PixelFormat.TRANSLUCENT for GL Surfaces is interpreted as any 32-bit surface with alpha by + * SurfaceFlinger. + */ + if (translucent) { + this.getHolder().setFormat(PixelFormat.TRANSLUCENT); + } + + /* + * Setup the context factory for 2.0 rendering. See ContextFactory class definition below + */ + setEGLContextFactory(new ContextFactory()); + + /* + * We need to choose an EGLConfig that matches the format of our surface exactly. This is going to be done in our custom + * config chooser. See ConfigChooser class definition below. + */ + setEGLConfigChooser(translucent ? new ConfigChooser(8, 8, 8, 8, depth, stencil) : new ConfigChooser(5, 6, 5, 0, depth, + stencil)); + + /* Set the renderer responsible for frame rendering */ + } + + + static class ContextFactory implements GLSurfaceView.EGLContextFactory { + private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + + public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { + Log.w(TAG, "creating OpenGL ES 2.0 context"); + checkEglError("Before eglCreateContext", egl); + int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; + EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); + checkEglError("After eglCreateContext", egl); + return context; + } + + public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { + egl.eglDestroyContext(display, context); + } + } + + static void checkEglError(String prompt, EGL10 egl) { + int error; + while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { + Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); + } + } + + private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { + + public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { + mRedSize = r; + mGreenSize = g; + mBlueSize = b; + mAlphaSize = a; + mDepthSize = depth; + mStencilSize = stencil; + } + + /* + * This EGL config specification is used to specify 2.0 rendering. We use a minimum size of 4 bits for red/green/blue, but + * will perform actual matching in chooseConfig() below. + */ + private static int EGL_OPENGL_ES2_BIT = 4; + private static int[] s_configAttribs2 = {EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE}; + + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + + /* + * Get the number of minimally matching EGL configurations + */ + int[] num_config = new int[1]; + egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); + + int numConfigs = num_config[0]; + + if (numConfigs <= 0) { + throw new IllegalArgumentException("No configs match configSpec"); + } + + /* + * Allocate then read the array of minimally matching EGL configs + */ + EGLConfig[] configs = new EGLConfig[numConfigs]; + egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); + + if (DEBUG) { + printConfigs(egl, display, configs); + } + /* + * Now return the "best" one + */ + return chooseConfig(egl, display, configs); + } + + 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); + + // We need at least mDepthSize and mStencilSize bits + if (d < mDepthSize || s < mStencilSize) continue; + + // We want an *exact* match for red/green/blue/alpha + 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; + } + + private void printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { + int numConfigs = configs.length; + Log.w(TAG, String.format("%d configurations", numConfigs)); + for (int i = 0; i < numConfigs; i++) { + Log.w(TAG, String.format("Configuration %d:\n", i)); + printConfig(egl, display, configs[i]); + } + } + + private void printConfig(EGL10 egl, EGLDisplay display, EGLConfig config) { + int[] attributes = {EGL10.EGL_BUFFER_SIZE, EGL10.EGL_ALPHA_SIZE, EGL10.EGL_BLUE_SIZE, EGL10.EGL_GREEN_SIZE, + EGL10.EGL_RED_SIZE, EGL10.EGL_DEPTH_SIZE, EGL10.EGL_STENCIL_SIZE, EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_CONFIG_ID, + EGL10.EGL_LEVEL, EGL10.EGL_MAX_PBUFFER_HEIGHT, EGL10.EGL_MAX_PBUFFER_PIXELS, EGL10.EGL_MAX_PBUFFER_WIDTH, + EGL10.EGL_NATIVE_RENDERABLE, EGL10.EGL_NATIVE_VISUAL_ID, EGL10.EGL_NATIVE_VISUAL_TYPE, + 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, + EGL10.EGL_SAMPLES, EGL10.EGL_SAMPLE_BUFFERS, EGL10.EGL_SURFACE_TYPE, EGL10.EGL_TRANSPARENT_TYPE, + EGL10.EGL_TRANSPARENT_RED_VALUE, EGL10.EGL_TRANSPARENT_GREEN_VALUE, EGL10.EGL_TRANSPARENT_BLUE_VALUE, 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, + 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, + 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, + 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, + EGL10.EGL_LUMINANCE_SIZE, EGL10.EGL_ALPHA_MASK_SIZE, EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RENDERABLE_TYPE, 0x3042 // EGL10.EGL_CONFORMANT + }; + String[] names = {"EGL_BUFFER_SIZE", "EGL_ALPHA_SIZE", "EGL_BLUE_SIZE", "EGL_GREEN_SIZE", "EGL_RED_SIZE", + "EGL_DEPTH_SIZE", "EGL_STENCIL_SIZE", "EGL_CONFIG_CAVEAT", "EGL_CONFIG_ID", "EGL_LEVEL", "EGL_MAX_PBUFFER_HEIGHT", + "EGL_MAX_PBUFFER_PIXELS", "EGL_MAX_PBUFFER_WIDTH", "EGL_NATIVE_RENDERABLE", "EGL_NATIVE_VISUAL_ID", + "EGL_NATIVE_VISUAL_TYPE", "EGL_PRESERVED_RESOURCES", "EGL_SAMPLES", "EGL_SAMPLE_BUFFERS", "EGL_SURFACE_TYPE", + "EGL_TRANSPARENT_TYPE", "EGL_TRANSPARENT_RED_VALUE", "EGL_TRANSPARENT_GREEN_VALUE", "EGL_TRANSPARENT_BLUE_VALUE", + "EGL_BIND_TO_TEXTURE_RGB", "EGL_BIND_TO_TEXTURE_RGBA", "EGL_MIN_SWAP_INTERVAL", "EGL_MAX_SWAP_INTERVAL", + "EGL_LUMINANCE_SIZE", "EGL_ALPHA_MASK_SIZE", "EGL_COLOR_BUFFER_TYPE", "EGL_RENDERABLE_TYPE", "EGL_CONFORMANT"}; + int[] value = new int[1]; + for (int i = 0; i < attributes.length; i++) { + int attribute = attributes[i]; + String name = names[i]; + if (egl.eglGetConfigAttrib(display, config, attribute, value)) { + Log.w(TAG, String.format(" %s: %d\n", name, value[0])); + } else { + // Log.w(TAG, String.format(" %s: failed\n", name)); + while (egl.eglGetError() != EGL10.EGL_SUCCESS) + ; + } + } + } + + // Subclasses can adjust these values: + protected int mRedSize; + protected int mGreenSize; + protected int mBlueSize; + protected int mAlphaSize; + protected int mDepthSize; + protected int mStencilSize; + private int[] mValue = new int[1]; + } } diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceViewCupcake.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceViewCupcake.java index fda6e9540..e9f183be7 100644 --- a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceViewCupcake.java +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceViewCupcake.java @@ -165,22 +165,33 @@ public class GLSurfaceViewCupcake extends SurfaceView implements SurfaceHolder.C */ public final static int DEBUG_LOG_GL_CALLS = 2; + final ResolutionStrategy resolutionStrategy; + /** * Standard View constructor. In order to render something, you must call {@link #setRenderer} to register a renderer. */ - public GLSurfaceViewCupcake (Context context) { + public GLSurfaceViewCupcake (Context context, ResolutionStrategy resolutionStrategy) { super(context); + this.resolutionStrategy = resolutionStrategy; init(); } /** * Standard View constructor. In order to render something, you must call {@link #setRenderer} to register a renderer. */ - public GLSurfaceViewCupcake (Context context, AttributeSet attrs) { + public GLSurfaceViewCupcake (Context context, AttributeSet attrs, ResolutionStrategy resolutionStrategy) { super(context, attrs); + this.resolutionStrategy = resolutionStrategy; init(); } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ResolutionStrategy.MeasuredDimension measures = resolutionStrategy.calcMeasures(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(measures.width, measures.height); + } + private void init () { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/RatioResolutionStrategy.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/RatioResolutionStrategy.java new file mode 100644 index 000000000..802231a10 --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/RatioResolutionStrategy.java @@ -0,0 +1,38 @@ +package com.badlogic.gdx.backends.android.surfaceview; + +import android.view.View; + +public class RatioResolutionStrategy implements ResolutionStrategy { + + private final float ratio; + + public RatioResolutionStrategy(float ratio) { + this.ratio = ratio; + } + + public RatioResolutionStrategy(final float width, final float height) { + this.ratio = width / height; + } + + @Override + public MeasuredDimension calcMeasures(int widthMeasureSpec, int heightMeasureSpec) { + + final int specWidth = View.MeasureSpec.getSize(widthMeasureSpec); + final int specHeight = View.MeasureSpec.getSize(heightMeasureSpec); + + final float desiredRatio = ratio; + final float realRatio = (float) specWidth / specHeight; + + int width; + int height; + if (realRatio < desiredRatio) { + width = specWidth; + height = Math.round(width / desiredRatio); + } else { + height = specHeight; + width = Math.round(height * desiredRatio); + } + + return new MeasuredDimension(width, height); + } +} diff --git a/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/ResolutionStrategy.java b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/ResolutionStrategy.java new file mode 100644 index 000000000..cc6785186 --- /dev/null +++ b/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/ResolutionStrategy.java @@ -0,0 +1,23 @@ +package com.badlogic.gdx.backends.android.surfaceview; + +public interface ResolutionStrategy { + + + public MeasuredDimension calcMeasures( final int widthMeasureSpec, final int heightMeasureSpec); + + + public static class MeasuredDimension { + public final int width; + public final int height; + + public MeasuredDimension(int width, int height) { + this.width = width; + this.height = height; + } + + } + + + + +}