Skip to content

Commit

Permalink
Change how retina resolutions are handled
Browse files Browse the repository at this point in the history
This is a breaking change, but makes the API consistent with core.
Fixes #3789 (resize() being triggered with same dimensions)
Fixes touch mapping on older iOS versions when screen is rotated
  • Loading branch information
Darkyenus committed Mar 11, 2016
1 parent 0edef77 commit 22667bb
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 149 deletions.
Expand Up @@ -16,8 +16,20 @@

package com.badlogic.gdx.backends.iosrobovm;

import java.io.File;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Audio;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.LifecycleListener;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.backends.iosrobovm.objectal.OALAudioSession;
import com.badlogic.gdx.backends.iosrobovm.objectal.OALSimpleAudio;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Clipboard;
import org.robovm.apple.coregraphics.CGRect;
import org.robovm.apple.foundation.Foundation;
import org.robovm.apple.foundation.NSMutableDictionary;
Expand All @@ -31,26 +43,11 @@
import org.robovm.apple.uikit.UIInterfaceOrientation;
import org.robovm.apple.uikit.UIPasteboard;
import org.robovm.apple.uikit.UIScreen;
import org.robovm.apple.uikit.UIUserInterfaceIdiom;
import org.robovm.apple.uikit.UIViewController;
import org.robovm.apple.uikit.UIWindow;
import org.robovm.rt.bro.Bro;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Audio;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.LifecycleListener;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.backends.iosrobovm.objectal.OALAudioSession;
import com.badlogic.gdx.backends.iosrobovm.objectal.OALSimpleAudio;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Clipboard;
import java.io.File;

public class IOSApplication implements Application {

Expand Down Expand Up @@ -100,9 +97,9 @@ public void willTerminate (UIApplication application) {
int logLevel = Application.LOG_DEBUG;

/** The display scale factor (1.0f for normal; 2.0f to use retina coordinates/dimensions). */
float displayScaleFactor;
float pixelsPerPoint;

private CGRect lastScreenBounds = null;
private IOSScreenBounds lastScreenBounds = null;

Array<Runnable> runnables = new Array<Runnable>();
Array<Runnable> executedRunnables = new Array<Runnable>();
Expand All @@ -121,35 +118,16 @@ final boolean didFinishLaunching (UIApplication uiApp, UIApplicationLaunchOption
UIApplication.getSharedApplication().setIdleTimerDisabled(config.preventScreenDimming);

Gdx.app.debug("IOSApplication", "iOS version: " + UIDevice.getCurrentDevice().getSystemVersion());
// fix the scale factor if we have a retina device (NOTE: iOS screen sizes are in "points" not pixels by default!)

Gdx.app.debug("IOSApplication", "Running in " + (Bro.IS_64BIT ? "64-bit" : "32-bit") + " mode");

float scale = (float)(getIosVersion() >= 8 ? UIScreen.getMainScreen().getNativeScale() : UIScreen.getMainScreen()
.getScale());
if (scale >= 2.0f) {
Gdx.app.debug("IOSApplication", "scale: " + scale);
if (UIDevice.getCurrentDevice().getUserInterfaceIdiom() == UIUserInterfaceIdiom.Pad) {
// it's an iPad!
displayScaleFactor = config.displayScaleLargeScreenIfRetina * scale;
} else {
// it's an iPod or iPhone
displayScaleFactor = config.displayScaleSmallScreenIfRetina * scale;
}
} else {
// no retina screen: no scaling!
if (UIDevice.getCurrentDevice().getUserInterfaceIdiom() == UIUserInterfaceIdiom.Pad) {
// it's an iPad!
displayScaleFactor = config.displayScaleLargeScreenIfNonRetina;
} else {
// it's an iPod or iPhone
displayScaleFactor = config.displayScaleSmallScreenIfNonRetina;
}
}
// iOS counts in "points" instead of pixels. Points are logical pixels
pixelsPerPoint = (float)(getIosVersion() >= 8 ?
UIScreen.getMainScreen().getNativeScale() : UIScreen.getMainScreen().getScale());
Gdx.app.debug("IOSApplication", "Pixels per point: " + pixelsPerPoint);

// setup libgdx
this.input = new IOSInput(this);
this.graphics = new IOSGraphics(scale, this, config, input, config.useGL30);
this.graphics = new IOSGraphics(this, config, input, config.useGL30);
Gdx.gl = Gdx.gl20 = graphics.gl20;
Gdx.gl30 = graphics.gl30;
this.files = new IOSFiles();
Expand Down Expand Up @@ -189,11 +167,9 @@ public UIWindow getUIWindow () {
return uiWindow;
}

/** GL View spans whole screen, that is, even under the status bar. iOS can also rotate the screen, which is not handled
* consistently over iOS versions. This method returns, in pixels, rectangle in which libGDX draws.
*
* @return dimensions of space we draw to, adjusted for device orientation */
protected CGRect getBounds () {
/** @see IOSScreenBounds for detailed explanation
* @return logical dimensions of space we draw to, adjusted for device orientation */
protected IOSScreenBounds computeBounds () {
final CGRect screenBounds = UIScreen.getMainScreen().getBounds();
final CGRect statusBarFrame = uiApp.getStatusBarFrame();
final UIInterfaceOrientation statusBarOrientation = uiApp.getStatusBarOrientation();
Expand All @@ -208,34 +184,43 @@ protected CGRect getBounds () {
case LandscapeLeft:
case LandscapeRight:
if (screenHeight > screenWidth) {
debug("IOSApplication", "Switching reported width and height (w=" + screenWidth + " h=" + screenHeight + ")");
if (logLevel >= LOG_DEBUG)
debug("IOSApplication", "Switching reported width and height (original was w=" + screenWidth + " h="
+ screenHeight + ")");
double tmp = screenHeight;
// noinspection SuspiciousNameCombination
screenHeight = screenWidth;
screenWidth = tmp;
}
}

// update width/height depending on display scaling selected
screenWidth *= displayScaleFactor;
screenHeight *= displayScaleFactor;

if (statusBarHeight != 0.0) {
debug("IOSApplication", "Status bar is visible (height = " + statusBarHeight + ")");
statusBarHeight *= displayScaleFactor;
if (logLevel >= LOG_DEBUG) debug("IOSApplication", "Status bar is visible (height = " + statusBarHeight + ")");
screenHeight -= statusBarHeight;
} else {
debug("IOSApplication", "Status bar is not visible");
if (logLevel >= LOG_DEBUG) debug("IOSApplication", "Status bar is not visible");
}

debug("IOSApplication", "Total computed bounds are w=" + screenWidth + " h=" + screenHeight);
final int offsetX = 0;
final int offsetY = (int)Math.round(statusBarHeight);

final int width = (int)Math.round(screenWidth);
final int height = (int)Math.round(screenHeight);

final int backBufferWidth = (int)Math.round(screenWidth * pixelsPerPoint);
final int backBufferHeight = (int)Math.round(screenHeight * pixelsPerPoint);

if (logLevel >= LOG_DEBUG)
debug("IOSApplication", "Computed bounds are x=" + offsetX + " y=" + offsetY + " w=" + width + " h=" + height + " bbW= "
+ backBufferWidth + " bbH= " + backBufferHeight);

return lastScreenBounds = new CGRect(0.0, statusBarHeight, screenWidth, screenHeight);
return lastScreenBounds = new IOSScreenBounds(offsetX, offsetY, width, height, backBufferWidth, backBufferHeight);
}

protected CGRect getCachedBounds () {
/** @return area of screen in UIKit points on which libGDX draws, with 0,0 being upper left corner */
public IOSScreenBounds getScreenBounds () {
if (lastScreenBounds == null)
return getBounds();
return computeBounds();
else
return lastScreenBounds;
}
Expand Down
Expand Up @@ -44,39 +44,6 @@ public class IOSApplicationConfiguration {
/** number of frames per second, 60 is default **/
public int preferredFramesPerSecond = 60;

/** Scale factor to use on large screens with retina display, i.e. iPad 3+ (has no effect on non-retina screens).
* <ul>
* <li>1.0 = no scaling (everything is in pixels)
* <li>0.5 = LibGDX will behave as you would only have half the pixels. I.e. instead of 2048x1536 you will work in 1024x768.
* This looks pixel perfect and will save you the trouble to create bigger graphics for the retina display.
* <li>any other value: scales the screens according to your scale factor. A scale factor oof 0.75, 0.8, 1.2, 1.5 etc. works
* very well without any artifacts!
* </ul> */
public float displayScaleLargeScreenIfRetina = 1.0f;
/** Scale factor to use on small screens with retina display, i.e. iPhone 4+, iPod 4+ (has no effect on non-retina screens).
* <ul>
* <li>1.0 = no scaling (everything is in pixels)
* <li>0.5 = LibGDX will behave as you would only have half the pixels. I.e. instead of 960x640 you will work in 480x320. This
* looks pixel perfect and will save you the trouble to create bigger graphics for the retina display.
* <li>any other value: scales the screens according to your scale factor. A scale factor of 0.75, 0.8, 1.2, 1.5 etc. works
* very well without any artifacts!
* </ul> */
public float displayScaleSmallScreenIfRetina = 1.0f;
/** Scale factor to use on large screens without retina display, i.e. iPad 1+2 (has no effect on retina screens).
* <ul>
* <li>1.0 = no scaling (everything is in pixels)
* <li>any other value: scales the screens according to your scale factor. A scale factor of 0.75, 0.8, 1.2, 1.5 etc. works
* very well without any artifacts!
* </ul> */
public float displayScaleLargeScreenIfNonRetina = 1.0f;
/** Scale factor to use on small screens without retina display, i.e. iPhone 1-3, iPod 1-3 (has no effect on retina screens).
* <ul>
* <li>1.0 = no scaling (everything is in pixels)
* <li>any other value: scales the screens according to your scale factor. A scale factor of 0.75, 0.8, 1.2, 1.5 etc. works
* very well without any artifacts!
* </ul> */
public float displayScaleSmallScreenIfNonRetina = 1.0f;

/** whether to use the accelerometer, default true **/
public boolean useAccelerometer = true;
/** the update interval to poll the accelerometer with, in seconds **/
Expand Down
Expand Up @@ -17,7 +17,17 @@
package com.badlogic.gdx.backends.iosrobovm;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics;
import com.badlogic.gdx.LifecycleListener;
import com.badlogic.gdx.backends.iosrobovm.custom.HWMachine;
import com.badlogic.gdx.graphics.Cursor;
import com.badlogic.gdx.graphics.Cursor.SystemCursor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.glutils.GLVersion;
import com.badlogic.gdx.utils.Array;
import org.robovm.apple.coregraphics.CGRect;
import org.robovm.apple.foundation.NSObject;
import org.robovm.apple.glkit.GLKView;
Expand All @@ -39,25 +49,13 @@
import org.robovm.rt.bro.annotation.Callback;
import org.robovm.rt.bro.annotation.Pointer;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics;
import com.badlogic.gdx.LifecycleListener;
import com.badlogic.gdx.backends.iosrobovm.custom.HWMachine;
import com.badlogic.gdx.graphics.Cursor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Cursor.SystemCursor;
import com.badlogic.gdx.utils.Array;

public class IOSGraphics extends NSObject implements Graphics, GLKViewDelegate, GLKViewControllerDelegate {

private static final String tag = "IOSGraphics";

static class IOSUIViewController extends GLKViewController {
final IOSApplication app;
final IOSGraphics graphics;
boolean created = false;

IOSUIViewController (IOSApplication app, IOSGraphics graphics) {
this.app = app;
Expand Down Expand Up @@ -110,12 +108,13 @@ public boolean shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation or
public void viewDidLayoutSubviews () {
super.viewDidLayoutSubviews();
// get the view size and update graphics
CGRect bounds = app.getBounds();
graphics.width = (int)bounds.getWidth();
graphics.height = (int)bounds.getHeight();
graphics.makeCurrent();
if (graphics.created) {
app.listener.resize(graphics.width, graphics.height);
final IOSScreenBounds oldBounds = graphics.screenBounds;
final IOSScreenBounds newBounds = app.computeBounds();
graphics.screenBounds = newBounds;
// Layout may happen without bounds changing, don't trigger resize in that case
if (graphics.created && (newBounds.width != oldBounds.width || newBounds.height != oldBounds.height)) {
graphics.makeCurrent();
app.listener.resize(newBounds.width, newBounds.height);
}
}

Expand All @@ -127,19 +126,11 @@ private static boolean shouldAutorotateToInterfaceOrientation (IOSUIViewControll
}
}

static class IOSUIView extends GLKView {

public IOSUIView (CGRect frame, EAGLContext context) {
super(frame, context);
}
}

IOSApplication app;
IOSInput input;
GL20 gl20;
GL30 gl30;
int width;
int height;
IOSScreenBounds screenBounds;
long lastFrameTime;
float deltaTime;
long framesStart;
Expand All @@ -165,13 +156,11 @@ public IOSUIView (CGRect frame, EAGLContext context) {
GLKView view;
IOSUIViewController viewController;

public IOSGraphics (float scale, IOSApplication app, IOSApplicationConfiguration config, IOSInput input, boolean useGLES30) {
public IOSGraphics (IOSApplication app, IOSApplicationConfiguration config, IOSInput input, boolean useGLES30) {
this.config = config;

final CGRect bounds = app.getBounds();
// setup view and OpenGL
width = (int)bounds.getWidth();
height = (int)bounds.getHeight();
screenBounds = app.computeBounds();

if (useGLES30) {
context = new EAGLContext(EAGLRenderingAPI.OpenGLES3);
Expand All @@ -186,7 +175,7 @@ public IOSGraphics (float scale, IOSApplication app, IOSApplicationConfiguration
gl30 = null;
}

view = new GLKView(new CGRect(0, 0, bounds.getWidth(), bounds.getHeight()), context) {
view = new GLKView(new CGRect(0, 0, screenBounds.width, screenBounds.height), context) {
@Method(selector = "touchesBegan:withEvent:")
public void touchesBegan (@Pointer long touches, UIEvent event) {
IOSGraphics.this.input.onTouch(touches);
Expand Down Expand Up @@ -256,7 +245,7 @@ public void draw (CGRect rect) {
IOSDevice device = IOSDevice.getDevice(machineString);
if (device == null) app.error(tag, "Machine ID: " + machineString + " not found, please report to LibGDX");
int ppi = device != null ? device.ppi : 163;
density = device != null ? device.ppi/160f : scale;
density = device != null ? device.ppi/160f : app.pixelsPerPoint;
ppiX = ppi;
ppiY = ppi;
ppcX = ppiX / 2.54f;
Expand Down Expand Up @@ -306,6 +295,8 @@ public void draw (GLKView view, CGRect rect) {
gl20.glViewport(IOSGLES20.x, IOSGLES20.y, IOSGLES20.width, IOSGLES20.height);

if (!created) {
final int width = screenBounds.width;
final int height = screenBounds.height;
gl20.glViewport(0, 0, width, height);
app.listener.create();
app.listener.resize(width, height);
Expand Down Expand Up @@ -363,22 +354,27 @@ public GL20 getGL20 () {

@Override
public int getWidth () {
return width;
return screenBounds.width;
}

@Override
public int getHeight () {
return height;
return screenBounds.height;
}

@Override
public int getBackBufferWidth() {
return width;
public int getBackBufferWidth () {
return screenBounds.backBufferWidth;
}

@Override
public int getBackBufferHeight() {
return height;
public int getBackBufferHeight () {
return screenBounds.backBufferHeight;
}

/** @return amount of pixels per point */
public float getBackBufferScale() {
return app.pixelsPerPoint;
}

@Override
Expand Down

0 comments on commit 22667bb

Please sign in to comment.