v3.2.3: implemented mostly complete new iOS inset support

This commit is contained in:
Evan Debenham
2025-08-30 17:32:57 -04:00
committed by Evan Debenham
parent 0a6a93ec47
commit 452f944678
7 changed files with 64 additions and 24 deletions

View File

@@ -50,9 +50,6 @@ public class Game implements ApplicationListener {
public static int width;
public static int height;
//number of pixels from bottom of view before rendering starts
public static int bottomInset;
// Density: mdpi=1, hdpi=1.5, xhdpi=2...
public static float density = 1;
@@ -136,7 +133,6 @@ public class Game implements ApplicationListener {
Vertexbuffer.reload();
}
height -= bottomInset;
if (height != Game.height || width != Game.width) {
Game.width = width;

View File

@@ -172,7 +172,7 @@ public class NoosaScript extends Script {
Gdx.gl20.glScissor(
Math.round(camera.x * xScale),
Math.round((Game.height - camera.screenHeight - camera.y) * yScale) + Game.bottomInset,
Math.round((Game.height - camera.screenHeight - camera.y) * yScale),
Math.round(camera.screenWidth * xScale),
Math.round(camera.screenHeight * yScale));
} else {

View File

@@ -64,7 +64,7 @@ public class TextInput extends Component {
//use a custom viewport here to ensure stage camera matches game camera
Viewport viewport = new Viewport() {};
viewport.setWorldSize(Game.width, Game.height);
viewport.setScreenBounds(0, Game.bottomInset, Game.width, Game.height);
viewport.setScreenBounds(0, 0, Game.width, Game.height);
viewport.setCamera(new OrthographicCamera());
//TODO this is needed for the moment as Spritebatch switched to using VAOs in libGDX v1.13.1
// This results in HARD crashes atm, whereas old vertex arrays work fine

View File

@@ -66,7 +66,7 @@ public class DeviceCompat {
//...and in the Y dimension
public static float getRealPixelScaleY(){
return ((Gdx.graphics.getBackBufferHeight()-Game.bottomInset) / (float)Game.height );
return (Gdx.graphics.getBackBufferHeight() / (float)Game.height );
}
}

View File

@@ -427,6 +427,14 @@ public class GameScene extends PixelScene {
toolbar.setRect( insets.left, uiCamera.height - toolbar.height() - insets.bottom, uiCamera.width - insets.right, toolbar.height() );
}
//TODO this is pretty barebones, could be minimized or avoided perhaps?
if (insets.bottom > 0){
SkinnedBlock blackBar = new SkinnedBlock(uiCamera.width, insets.bottom, TextureCache.createSolid(0xFF000000));
blackBar.camera = uiCamera;
blackBar.y = uiCamera.height - insets.bottom;
add(blackBar);
}
layoutTags();
switch (InterlevelScene.mode) {

View File

@@ -45,6 +45,7 @@ import org.robovm.apple.foundation.NSMutableDictionary;
import org.robovm.apple.foundation.NSObject;
import org.robovm.apple.foundation.NSString;
import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIInterfaceOrientation;
import java.io.File;
@@ -106,9 +107,9 @@ public class IOSLauncher extends IOSApplication.Delegate {
//if the application has a short status bar (no notch), then hide it
//TODO we do this check elsewhere now, can this be removed?
if (statusBarHeight <= 24) {
//if (statusBarHeight <= 24) {
UIApplication.getSharedApplication().setStatusBarHidden(true);
}
//}
config.useHaptics = true;
config.useAccelerometer = false;
@@ -167,6 +168,12 @@ public class IOSLauncher extends IOSApplication.Delegate {
return new IOSApplication(new ShatteredPixelDungeon(new IOSPlatformSupport()), config);
}
@Override
public void didChangStatusBarOrientation(UIApplication application, UIInterfaceOrientation oldStatusBarOrientation) {
super.didChangStatusBarOrientation(application, oldStatusBarOrientation);
ShatteredPixelDungeon.seamlessResetScene();
}
public static void main(String[] argv) {
NSAutoreleasePool pool = new NSAutoreleasePool();
UIApplication.main(argv, null, IOSLauncher.class);

View File

@@ -29,17 +29,18 @@ import com.badlogic.gdx.backends.iosrobovm.objectal.OALSimpleAudio;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
import com.watabou.input.ControllerHandler;
import com.watabou.noosa.Game;
import com.watabou.utils.PlatformSupport;
import com.watabou.utils.RectF;
import org.robovm.apple.audiotoolbox.AudioServices;
import org.robovm.apple.coregraphics.CGRect;
import org.robovm.apple.systemconfiguration.SCNetworkReachability;
import org.robovm.apple.systemconfiguration.SCNetworkReachabilityFlags;
import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIInterfaceOrientation;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -49,10 +50,11 @@ public class IOSPlatformSupport extends PlatformSupport {
@Override
public void updateDisplaySize() {
//non-zero safe insets on left/top/right means device has a notch, show status bar
//TODO turn this into a setting instead?
if (Gdx.graphics.getSafeInsetTop() != 0
|| Gdx.graphics.getSafeInsetLeft() != 0
|| Gdx.graphics.getSafeInsetRight() != 0){
UIApplication.getSharedApplication().setStatusBarHidden(false);
//UIApplication.getSharedApplication().setStatusBarHidden(false);
} else {
UIApplication.getSharedApplication().setStatusBarHidden(true);
}
@@ -60,27 +62,54 @@ public class IOSPlatformSupport extends PlatformSupport {
@Override
public boolean supportsFullScreen() {
//fullscreen is always enabled on iOS
return false;
//iOS supports drawing into the gesture safe area
//TODO do we want this to control status bar visibility as well, or make that separate?
return Gdx.graphics.getSafeInsetBottom() > 0;
}
@Override
public RectF getSafeInsets(int level) {
//TODO currently returns all insets all the time. Needs testing based on particular iOS quirks
// we roughly want:
// ignore bottom home indicator insets in fullsceen
// ignore side insets in landscape for side that isn't notch
// older notch is large, compact dynamic island is not (maybe? Probably need UI adjustments then)
return super.getSafeInsets(level);
RectF insets = super.getSafeInsets(INSET_ALL);
//iOS gives us ALL insets by default, and so we need to filter from there:
//ignore the home indicator if we're in fullscreen
if (!supportsFullScreen() || SPDSettings.fullscreen()){
insets.bottom = 0;
} else {
//otherwise bottom inset is pretty big, halve it
insets.bottom /= 2;
}
//only cutouts can be on top/left/right, which are never blocking
if (level == INSET_BLK){
insets.left = insets.top = insets.right = 0;
} else if (level == INSET_LRG){
//Dynamic Island counts as a 'small cutout', we have to use status bar height to get it =I
CGRect statusBarFrame = UIApplication.getSharedApplication().getStatusBarFrame();
double statusBarHeight = Math.min(statusBarFrame.getWidth(), statusBarFrame.getHeight());
if (statusBarHeight >= 51){ //magic number BS for larger status bar caused by island
insets.left = insets.top = insets.right = 0;
}
}
//if we are in landscape, the display cutout is only actually on one side, so cancel the other
if (Game.width > Game.height){
if (UIApplication.getSharedApplication().getStatusBarOrientation().equals(UIInterfaceOrientation.LandscapeLeft)){
insets.left = 0;
} else {
insets.right = 0;
}
}
//TODO if we want to support status bar on-off, then we need a check here to set top inset to 0
return insets;
}
@Override
public void updateSystemUI() {
int prevInset = Game.bottomInset;
updateDisplaySize();
if (prevInset != Game.bottomInset) {
ShatteredPixelDungeon.seamlessResetScene();
}
}
@Override