Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ checkstyle = "13.3.0"
jacoco = "0.8.12"
lwjgl3 = "3.4.1"
angle = "2026-05-09"
libjglios = "0.2"
libjglios = "0.3"
saferalloc = "0.0.8"
nifty = "1.4.3"
spotbugs = "4.9.8"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ public void reshape(int width, int height) {
app.reshape(width, height);
}

@Override
public void reshape(int logicalWidth, int logicalHeight, int framebufferWidth, int framebufferHeight) {
app.reshape(logicalWidth, logicalHeight, framebufferWidth, framebufferHeight);
}

@Override
public void rescale(float x, float y) {
app.rescale(x, y);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ public void loadSettings(AppSettings settings) {
if (inputHandler.getView().getWidth() != 0 && inputHandler.getView().getHeight() != 0) {
scaleX = settings.getWidth() / (float)inputHandler.getView().getWidth();
scaleY = settings.getHeight() / (float)inputHandler.getView().getHeight();
currentMouseState.setStartPosition(inputHandler.getView().getWidth()/2, inputHandler.getView().getHeight()/2);
currentMouseState.setStartPosition(
getJmeX(inputHandler.getView().getWidth() / 2f),
getJmeY(inputHandler.getView().getHeight() / 2f));
}

if (logger.isLoggable(Level.FINE)) {
Expand Down
156 changes: 112 additions & 44 deletions jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,10 @@
import android.content.DialogInterface;
import android.content.pm.ConfigurationInfo;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.text.InputType;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.EditText;
Expand All @@ -58,6 +55,7 @@
import com.jme3.input.controls.SoftTextDialogInputListener;
import com.jme3.input.dummy.DummyKeyInput;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.renderer.Caps;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
Expand All @@ -68,6 +66,7 @@
import com.jme3.texture.FrameBuffer.FrameBufferTarget;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.image.ColorSpace;
import com.jme3.ui.Picture;
Expand Down Expand Up @@ -99,6 +98,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
protected AndroidInputHandler androidInput;
protected long minFrameDuration = 0; // No FPS cap
protected long lastUpdateTime = 0;
private int logicalWidth = 1;
private int logicalHeight = 1;
private int framebufferWidth = 1;
private int framebufferHeight = 1;
private final Vector2f displayScale = new Vector2f(1f, 1f);
private float appliedDisplayScaleMode = Float.NaN;
private Application application;
private Material blitMaterial;
private Picture blitGeometry;
Expand Down Expand Up @@ -452,16 +457,62 @@ public void onSurfaceChanged(GL10 gl, int width, int height) {
new Object[] { width, height }
);
}
// update the application settings with the new resolution
settings.setResolution(width, height);
// Reload settings in androidInput so the correct touch event scaling can be
// calculated in case the surface resolution is different than the view.
androidInput.loadSettings(settings);
framebufferWidth = Math.max(width, 1);
framebufferHeight = Math.max(height, 1);
updateDisplayScaleMetrics();
// if the application has already been initialized (ie renderable is set)
// then call reshape so the app can adjust to the new resolution.
if (renderable.get()) {
logger.log(Level.FINE, "App already initialized, calling reshape");
listener.reshape(width, height);
listener.reshape(logicalWidth, logicalHeight, getRenderFramebufferWidth(), getRenderFramebufferHeight());
listener.rescale(displayScale.x, displayScale.y);
}
}

private float getAndroidDisplayDensity() {
if (androidInput != null && androidInput.getView() != null
&& androidInput.getView().getResources() != null) {
android.util.DisplayMetrics metrics = androidInput.getView().getResources().getDisplayMetrics();
if (metrics != null) {
if (metrics.density > 0f) {
return metrics.density;
}
if (metrics.densityDpi > 0) {
return metrics.densityDpi / 160f;
}
}
}
return 1f;
}

private void updateDisplayScaleMetrics() {
float density = DisplayScaleUtils.sanitizeScale(getAndroidDisplayDensity());
displayScale.set(density, density);
appliedDisplayScaleMode = settings.getDisplayScaleMode();
if (DisplayScaleUtils.isNativePixelsMode(appliedDisplayScaleMode)) {
logicalWidth = framebufferWidth;
logicalHeight = framebufferHeight;
} else {
logicalWidth = Math.max(Math.round(framebufferWidth / density), 1);
logicalHeight = Math.max(Math.round(framebufferHeight / density), 1);
}
settings.setResolution(logicalWidth, logicalHeight);
// Reload settings in androidInput so the correct touch event scaling can be
// calculated in case the surface resolution is different than the view.
if (androidInput != null) {
androidInput.loadSettings(settings);
}
}

private void applyDisplayScaleModeIfNeeded() {
if (Float.compare(settings.getDisplayScaleMode(), appliedDisplayScaleMode) == 0) {
return;
}

updateDisplayScaleMetrics();
if (renderable.get()) {
listener.reshape(logicalWidth, logicalHeight, getRenderFramebufferWidth(), getRenderFramebufferHeight());
listener.rescale(displayScale.x, displayScale.y);
}
}

Expand All @@ -475,15 +526,21 @@ public void onDrawFrame(GL10 gl) {

if (!renderable.get()) {
if (created.get()) {
applyDisplayScaleModeIfNeeded();
logger.fine("GL Surface is setup, initializing application");
listener.initialize();
if (framebufferWidth > 0 && framebufferHeight > 0) {
listener.reshape(logicalWidth, logicalHeight, getRenderFramebufferWidth(), getRenderFramebufferHeight());
listener.rescale(displayScale.x, displayScale.y);
}
renderable.set(true);
}
} else {
if (!created.get()) {
throw new IllegalStateException("onDrawFrame without create");
}

applyDisplayScaleModeIfNeeded();
if (!renderFrameWithBlitSrgbConversion()) {
listener.update();
}
Expand Down Expand Up @@ -549,12 +606,43 @@ private boolean useBlitSrgbConversion() {
return settings.isGammaCorrection() && application != null;
}

private boolean useBlitFrameBuffer() {
float mode = settings.getDisplayScaleMode();
return application != null && (useBlitSrgbConversion()
|| DisplayScaleUtils.isDisabledMode(mode) || DisplayScaleUtils.isEmulatedScaleMode(mode));
}

private int getRenderFramebufferWidth() {
float mode = settings.getDisplayScaleMode();
if (DisplayScaleUtils.isDisabledMode(mode)) {
return Math.max(logicalWidth, 1);
}
if (DisplayScaleUtils.isEmulatedScaleMode(mode)) {
return Math.max(Math.round(framebufferWidth * mode), 1);
}
return Math.max(framebufferWidth, 1);
}

private int getRenderFramebufferHeight() {
float mode = settings.getDisplayScaleMode();
if (DisplayScaleUtils.isDisabledMode(mode)) {
return Math.max(logicalHeight, 1);
}
if (DisplayScaleUtils.isEmulatedScaleMode(mode)) {
return Math.max(Math.round(framebufferHeight * mode), 1);
}
return Math.max(framebufferHeight, 1);
}

private int getLinearFrameBufferSampleCount() {
int samples = Math.max(settings.getSamples(), 1);
if (samples > 1 && renderer != null && !renderer.getCaps().contains(Caps.TextureMultisample)) {
if (samples > 1 && renderer != null
&& (!renderer.getCaps().contains(Caps.TextureMultisample)
|| !renderer.getCaps().contains(Caps.OpenGL32))) {
if (!multisampleTextureWarningIssued) {
logger.warning("sRGB blit conversion requires multisampled textures for MSAA. "
+ "Falling back to a single-sample linear framebuffer.");
logger.log(Level.WARNING,
"Display scale blit requested {0}x MSAA, but this backend cannot sample multisample textures for the blit path. Falling back to a single-sample linear framebuffer.",
samples);
multisampleTextureWarningIssued = true;
}
return 1;
Expand All @@ -563,13 +651,13 @@ private int getLinearFrameBufferSampleCount() {
}

private void rebuildLinearFrameBufferIfNeeded() {
if (!useBlitSrgbConversion()) {
if (!useBlitFrameBuffer()) {
destroyLinearFrameBufferResources();
return;
}

int width = Math.max(settings.getWidth(), 1);
int height = Math.max(settings.getHeight(), 1);
int width = getRenderFramebufferWidth();
int height = getRenderFramebufferHeight();
int samples = getLinearFrameBufferSampleCount();

if (linearFrameBuffer != null && linearFrameBuffer.getWidth() == width
Expand All @@ -585,6 +673,8 @@ private void rebuildLinearFrameBufferIfNeeded() {

Texture2D colorTexture = new Texture2D(
new Image(getLinearFrameBufferColorFormat(), width, height, null, ColorSpace.Linear));
colorTexture.setMagFilter(Texture.MagFilter.Bilinear);
colorTexture.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
if (samples > 1) {
colorTexture.getImage().setMultiSamples(samples);
}
Expand All @@ -610,7 +700,7 @@ private Format getLinearFrameBufferColorFormat() {
}

private boolean ensureBlitResources() {
if (!useBlitSrgbConversion()) {
if (!useBlitFrameBuffer()) {
return false;
}

Expand All @@ -622,10 +712,10 @@ private boolean ensureBlitResources() {

if (blitMaterial == null) {
blitMaterial = new Material(assetManager, BLIT_MATERIAL);
blitMaterial.setBoolean("Srgb", true);
blitMaterial.getAdditionalRenderState().setDepthTest(false);
blitMaterial.getAdditionalRenderState().setDepthWrite(false);
}
blitMaterial.setBoolean("Srgb", useBlitSrgbConversion());

if (blitGeometry == null) {
blitGeometry = new Picture("Linear to sRGB Blit");
Expand Down Expand Up @@ -667,7 +757,7 @@ private void destroyLinearFrameBufferResources() {
}

private boolean renderFrameWithBlitSrgbConversion() {
if (!useBlitSrgbConversion()) {
if (!useBlitFrameBuffer()) {
return false;
}

Expand Down Expand Up @@ -699,8 +789,8 @@ private boolean renderFrameWithBlitSrgbConversion() {
Camera previousCamera = renderManager.getCurrentCamera();
try {
renderer.setFrameBuffer(null);
int blitWidth = linearFrameBuffer.getWidth();
int blitHeight = linearFrameBuffer.getHeight();
int blitWidth = Math.max(getFramebufferWidth(), 1);
int blitHeight = Math.max(getFramebufferHeight(), 1);
if (blitCamera.getWidth() != blitWidth || blitCamera.getHeight() != blitHeight) {
blitCamera.resize(blitWidth, blitHeight, true);
}
Expand Down Expand Up @@ -811,16 +901,9 @@ public void onClick(DialogInterface dialog, int whichButton) {
);
}

/**
* Returns the height of the input surface.
*
* @return the height (in pixels)
*/
@Override
public int getFramebufferHeight() {
Rect rect = getSurfaceFrame();
int result = rect.height();
return result;
return framebufferHeight;
}

/**
Expand All @@ -830,9 +913,7 @@ public int getFramebufferHeight() {
*/
@Override
public int getFramebufferWidth() {
Rect rect = getSurfaceFrame();
int result = rect.width();
return result;
return framebufferWidth;
}

/**
Expand All @@ -855,19 +936,6 @@ public int getWindowYPosition() {
throw new UnsupportedOperationException("not implemented yet");
}

/**
* Retrieves the dimensions of the input surface. Note: do not modify the
* returned object.
*
* @return the dimensions (in pixels, left and top are 0)
*/
private Rect getSurfaceFrame() {
SurfaceView view = (SurfaceView) androidInput.getView();
SurfaceHolder holder = view.getHolder();
Rect result = holder.getSurfaceFrame();
return result;
}

@Override
public Displays getDisplays() {
// TODO Auto-generated method stub
Expand Down
7 changes: 6 additions & 1 deletion jme3-core/src/main/java/com/jme3/app/LegacyApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -593,8 +593,13 @@ public void startCanvas(boolean waitFor) {
*/
@Override
public void reshape(int w, int h) {
reshape(w, h, w, h);
}

@Override
public void reshape(int logicalWidth, int logicalHeight, int framebufferWidth, int framebufferHeight) {
if (renderManager != null) {
renderManager.notifyReshape(w, h);
renderManager.notifyReshape(logicalWidth, logicalHeight, framebufferWidth, framebufferHeight);
}
}

Expand Down
Loading