Make a universal interfice for things thet provide surfaces

This commit is contained in:
artdeell
2023-06-01 17:59:52 +03:00
parent e7ad1b1a40
commit de9dbdc4dc
9 changed files with 202 additions and 85 deletions

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}
}