diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java index acd65d4c7..cd50dff37 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java @@ -11,7 +11,6 @@ import static org.lwjgl.glfw.CallbackBridge.windowWidth; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; -import android.graphics.SurfaceTexture; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -21,18 +20,18 @@ import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.TextureView; import android.view.View; import android.view.ViewGroup; -import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import net.kdt.pojavlaunch.customcontrols.ControlLayout; import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad; import net.kdt.pojavlaunch.prefs.LauncherPreferences; +import net.kdt.pojavlaunch.surfaceprovider.SurfaceCallbacks; +import net.kdt.pojavlaunch.surfaceprovider.SurfaceProvider; +import net.kdt.pojavlaunch.surfaceprovider.SurfaceViewSurfaceProvider; +import net.kdt.pojavlaunch.surfaceprovider.TextureViewSurfaceProvider; import net.kdt.pojavlaunch.utils.JREUtils; import net.kdt.pojavlaunch.utils.MCOptionUtils; import net.kdt.pojavlaunch.utils.MathUtils; @@ -45,7 +44,7 @@ import fr.spse.gamepad_remapper.RemapperView; /** * Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft */ -public class MinecraftGLSurface extends View implements GrabListener { +public class MinecraftGLSurface extends View implements GrabListener, SurfaceCallbacks { /* Gamepad object for gamepad inputs, instantiated on need */ private Gamepad mGamepad = null; /* The RemapperView.Builder object allows you to set which buttons to remap */ @@ -79,8 +78,10 @@ public class MinecraftGLSurface extends View implements GrabListener { /* Surface ready listener, used by the activity to launch minecraft */ SurfaceReadyListener mSurfaceReadyListener = null; final Object mSurfaceReadyListenerLock = new Object(); - /* View holding the surface, either a SurfaceView or a TextureView */ - View mSurface; + /* Whether the surfaceCreated() method of the interface was called already. If it wasn't, it starts the game, only updates the surface otherwise */ + private boolean mIsCreateCalled = false; + /* The current SurfaceProvider, used to resize the screen and provides all the calls to manage the surface */ + private SurfaceProvider mSurfaceProvider; /* List of hotbarKeys, used when clicking on the hotbar */ private static final int[] HOTBAR_KEYS = { @@ -148,69 +149,12 @@ public class MinecraftGLSurface extends View implements GrabListener { /** Initialize the view and all its settings */ public void start(){ if(LauncherPreferences.PREF_USE_ALTERNATE_SURFACE){ - SurfaceView surfaceView = new SurfaceView(getContext()); - mSurface = surfaceView; - - surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { - private boolean isCalled = false; - @Override - public void surfaceCreated(@NonNull SurfaceHolder holder) { - if(isCalled) { - JREUtils.setupBridgeWindow(surfaceView.getHolder().getSurface()); - return; - } - isCalled = true; - - realStart(surfaceView.getHolder().getSurface()); - } - - @Override - public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { - refreshSize(); - } - - @Override - public void surfaceDestroyed(@NonNull SurfaceHolder holder) {} - }); - - ((ViewGroup)getParent()).addView(surfaceView); + mSurfaceProvider = new SurfaceViewSurfaceProvider(getContext()); }else{ - TextureView textureView = new TextureView(getContext()); - textureView.setOpaque(true); - textureView.setAlpha(1.0f); - mSurface = textureView; - - textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { - private boolean isCalled = false; - @Override - public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) { - Surface tSurface = new Surface(surface); - if(isCalled) { - JREUtils.setupBridgeWindow(tSurface); - return; - } - isCalled = true; - - realStart(tSurface); - } - - @Override - public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) { - refreshSize(); - } - - @Override - public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) { - return true; - } - - @Override - public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {} - }); - - ((ViewGroup)getParent()).addView(textureView); + mSurfaceProvider = new TextureViewSurfaceProvider(getContext()); } - + mSurfaceProvider.initialize(this); + ((ViewGroup)getParent()).addView(mSurfaceProvider.getView()); } @@ -560,24 +504,12 @@ public class MinecraftGLSurface extends View implements GrabListener { public void refreshSize(){ windowWidth = Tools.getDisplayFriendlyRes(Tools.currentDisplayMetrics.widthPixels, mScaleFactor); windowHeight = Tools.getDisplayFriendlyRes(Tools.currentDisplayMetrics.heightPixels, mScaleFactor); - if(mSurface == null){ - Log.w("MGLSurface", "Attempt to refresh size on null surface"); + if(mSurfaceProvider == null){ + Log.w("MGLSurface", "Attempt to refresh size on null surface provider"); return; } - if(LauncherPreferences.PREF_USE_ALTERNATE_SURFACE){ - SurfaceView view = (SurfaceView) mSurface; - if(view.getHolder() != null){ - view.getHolder().setFixedSize(windowWidth, windowHeight); - } - }else{ - TextureView view = (TextureView)mSurface; - if(view.getSurfaceTexture() != null){ - view.getSurfaceTexture().setDefaultBufferSize(windowWidth, windowHeight); - } - } - + mSurfaceProvider.changeRenderSize(windowWidth, windowHeight); CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight); - } private void realStart(Surface surface){ @@ -630,6 +562,29 @@ public class MinecraftGLSurface extends View implements GrabListener { } } + @Override + public void surfaceCreated(Surface surface, int width, int height) { + if(mIsCreateCalled) { + JREUtils.setupBridgeWindow(surface); + return; + } + mIsCreateCalled = true; + + realStart(surface); + } + + @Override + public void surfaceSizeChanged(int width, int height) { + refreshSize(); + } + + @Override + public void surfaceDestroyed() { + if(mIsCreateCalled) { + JREUtils.destroyEGLSurface(); + } + } + /** A small interface called when the listener is ready for the first time */ public interface SurfaceReadyListener { void isReady(); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceCallbacks.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceCallbacks.java new file mode 100644 index 000000000..40c6fb22c --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceCallbacks.java @@ -0,0 +1,9 @@ +package net.kdt.pojavlaunch.surfaceprovider; + +import android.view.Surface; + +public interface SurfaceCallbacks { + void surfaceCreated(Surface surface, int width, int height); + void surfaceSizeChanged(int width, int height); + void surfaceDestroyed(); +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceProvider.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceProvider.java new file mode 100644 index 000000000..43b73701b --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceProvider.java @@ -0,0 +1,11 @@ +package net.kdt.pojavlaunch.surfaceprovider; + +import android.view.Surface; +import android.view.View; + +public interface SurfaceProvider { + void initialize(SurfaceCallbacks callbacks); + void changeRenderSize(int width, int height); + Surface getSurface(); + View getView(); +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceViewSurfaceProvider.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceViewSurfaceProvider.java new file mode 100644 index 000000000..8f6894cc4 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/SurfaceViewSurfaceProvider.java @@ -0,0 +1,58 @@ +package net.kdt.pojavlaunch.surfaceprovider; + +import android.content.Context; +import android.graphics.Rect; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; + +import androidx.annotation.NonNull; + +public class SurfaceViewSurfaceProvider implements SurfaceProvider, SurfaceHolder.Callback { + private final SurfaceView mSurfaceView; + private SurfaceCallbacks mCallbacks; + + + public SurfaceViewSurfaceProvider(Context context) { + mSurfaceView = new SurfaceView(context); + mSurfaceView.getHolder().addCallback(this); + } + + @Override + public void initialize(SurfaceCallbacks callbacks) { + this.mCallbacks = callbacks; + } + + @Override + public void changeRenderSize(int width, int height) { + if(mSurfaceView != null && mSurfaceView.getHolder() != null) mSurfaceView.getHolder().setFixedSize(width, height); + } + + @Override + public Surface getSurface() { + if(mSurfaceView != null && mSurfaceView.getHolder() != null) return mSurfaceView.getHolder().getSurface(); + return null; + } + + @Override + public View getView() { + return mSurfaceView; + } + + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + Rect surfaceRect = holder.getSurfaceFrame(); + if(mCallbacks != null) mCallbacks.surfaceCreated(holder.getSurface(), surfaceRect.right, surfaceRect.bottom); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + if(mCallbacks != null) mCallbacks.surfaceSizeChanged(width, height); + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + if(mCallbacks != null) mCallbacks.surfaceDestroyed(); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/TextureViewSurfaceProvider.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/TextureViewSurfaceProvider.java new file mode 100644 index 000000000..e351c1d5b --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/surfaceprovider/TextureViewSurfaceProvider.java @@ -0,0 +1,67 @@ +package net.kdt.pojavlaunch.surfaceprovider; + +import android.content.Context; +import android.graphics.SurfaceTexture; +import android.view.Surface; +import android.view.TextureView; +import android.view.View; + +import androidx.annotation.NonNull; + +public class TextureViewSurfaceProvider implements SurfaceProvider, TextureView.SurfaceTextureListener{ + private final TextureView mTextureView; + private SurfaceCallbacks mCallbacks; + private Surface mSurface; + + + public TextureViewSurfaceProvider(Context context) { + mTextureView = new TextureView(context); + mTextureView.setSurfaceTextureListener(this); + mTextureView.setOpaque(true); + mTextureView.setAlpha(1.0f); + } + + @Override + public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) { + this.mSurface = new Surface(surface); + if(mCallbacks != null) mCallbacks.surfaceCreated(this.mSurface, width, height); + } + + @Override + public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) { + if(mCallbacks != null) mCallbacks.surfaceSizeChanged(width, height); + } + + @Override + public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) { + mSurface = null; + if(mCallbacks != null) mCallbacks.surfaceDestroyed(); + return true; + } + + @Override + public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {} + + @Override + public void initialize(SurfaceCallbacks callbacks) { + this.mCallbacks = callbacks; + } + + @Override + public void changeRenderSize(int width, int height) { + SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); + if(surfaceTexture != null) { + surfaceTexture.setDefaultBufferSize(width, height); + } + } + + @Override + public Surface getSurface() { + return mSurface; + } + + @Override + public View getView() { + return mTextureView; + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java index be6524d55..113fe3bd5 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java @@ -551,6 +551,8 @@ public class JREUtils { public static native boolean dlopen(String libPath); public static native void setLdLibraryPath(String ldLibraryPath); public static native void setupBridgeWindow(Object surface); + + public static native void destroyEGLSurface(); public static native void releaseBridgeWindow(); public static native void setupExitTrap(Context context); // Obtain AWT screen pixels to render on Android SurfaceView diff --git a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c index c7f722fc4..31b0e9949 100644 --- a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c +++ b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c @@ -164,6 +164,14 @@ void gl_setup_window() { } } +void gl_destroy_window() { + if(pojav_environ->mainWindowBundle != NULL) { + __android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is not NULL, killing the EGL window"); + pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW; + pojav_environ->mainWindowBundle->newNativeSurface = NULL; // this will cause the window to be switched out for a Pbuffer, until we have a new one + } +} + void gl_swap_interval(int swapInterval) { if(pojav_environ->force_vsync) swapInterval = 1; diff --git a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.h b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.h index bb8fbbd47..3fa5166b2 100644 --- a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.h +++ b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.h @@ -21,6 +21,7 @@ render_window_t* gl_init_context(render_window_t* share); void gl_make_current(render_window_t* bundle); void gl_swap_buffers(); void gl_setup_window(); +void gl_destroy_window(); void gl_swap_interval(int swapInterval); diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index e8eeb5773..59259cfd9 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -643,6 +643,13 @@ JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_setupBridgeWindow } } +JNIEXPORT void JNICALL +Java_net_kdt_pojavlaunch_utils_JREUtils_destroyEGLSurface(JNIEnv *env, jclass clazz) { + if(pojav_environ->config_renderer == RENDERER_GL4ES) { + gl_destroy_window(); + } +} + JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_releaseBridgeWindow(JNIEnv *env, jclass clazz) { @@ -1033,4 +1040,3 @@ void pojavSwapInterval(int interval) { } break; } } -