diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 97ee083..0079e54 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -34,6 +34,7 @@ android:launchMode="singleInstance" android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation" android:preferMinimalPostProcessing="true" + android:screenOrientation="landscape" android:exported="true" > @@ -43,6 +44,19 @@ + + diff --git a/android/app/src/main/java/de/ladkau/questshock/QuestShockActivity.java b/android/app/src/main/java/de/ladkau/questshock/QuestShockActivity.java index 1f32120..43ba14b 100644 --- a/android/app/src/main/java/de/ladkau/questshock/QuestShockActivity.java +++ b/android/app/src/main/java/de/ladkau/questshock/QuestShockActivity.java @@ -6,6 +6,8 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.SurfaceHolder; import androidx.core.app.ActivityCompat; @@ -89,6 +91,20 @@ public class QuestShockActivity extends SDLActivity { } super.surfaceChanged(holder, format, width, height); } + + // Diagnostic only (see OpenGL.cc's matching log) - Android's real, + // legitimate signal for "this View's laid-out size actually + // changed" is onSizeChanged(), fired by the framework itself, not + // something we have to poll or guess about. If Quest's Home shell + // settles a freshly-launched panel into its final size via + // a genuine later layout pass, this is where that would show up - + // confirming whether a real event exists to hook, before writing + // any fix around it. + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + Log.i(TAG, "GameSurface.onSizeChanged() " + oldw + "x" + oldh + " -> " + w + "x" + h); + } } @Override diff --git a/android/engine-patches/06-android-resize-event.patch b/android/engine-patches/06-android-resize-event.patch new file mode 100644 index 0000000..3639206 --- /dev/null +++ b/android/engine-patches/06-android-resize-event.patch @@ -0,0 +1,27 @@ +--- a/src/Libraries/INPUT/Source/sdl_events.c ++++ b/src/Libraries/INPUT/Source/sdl_events.c +@@ -737,7 +737,24 @@ + break; + + case SDL_WINDOWEVENT_MOVED: ++ break; ++ + case SDL_WINDOWEVENT_RESIZED: ++#ifdef __ANDROID__ ++ // Android's SDL video backend (Android_SendResize() in ++ // src/video/android/SDL_androidvideo.c) only ever sends ++ // RESIZED for surface-driven resizes - e.g. the Quest Home ++ // shell settling the 2D panel into its requested ++ // defaultWidth/defaultHeight after activity launch - never ++ // SIZE_CHANGED (unlike desktop platforms, where an ++ // app-driven SDL_SetWindowSize() triggers both, handled ++ // above). Without this, opengl_resize() never re-runs after ++ // that late resize, leaving the GL viewport stuck at ++ // whatever (smaller) size the window first reported, ++ // rendered into one corner of the now-larger surface. ++ if (can_use_opengl()) ++ opengl_resize(ev.window.data1, ev.window.data2); ++#endif + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED: diff --git a/android/engine-patches/07-android-size-diagnostics.patch b/android/engine-patches/07-android-size-diagnostics.patch new file mode 100644 index 0000000..e603b5a --- /dev/null +++ b/android/engine-patches/07-android-size-diagnostics.patch @@ -0,0 +1,24 @@ +--- a/src/MacSrc/OpenGL.cc ++++ b/src/MacSrc/OpenGL.cc +@@ -332,6 +332,21 @@ + + int width, height; + SDL_GetWindowSize(window, &width, &height); ++#ifdef __ANDROID__ ++ // Temporary diagnostic: the reported panel/surface size is correct ++ // (confirmed via SDLSurface's own "Window size" log and a Java-side ++ // onSizeChanged() probe showing no later relayout), but the rendered ++ // content still only fills a small corner of it. That means the ++ // divergence is somewhere below the Java/Activity layer - between what ++ // SDL_GetWindowSize() (the value used for opengl_resize() below) reports ++ // and what SDL/EGL/gl4es actually believe the live drawable size is. ++ // Compare all three directly instead of guessing further. ++ int drawable_w, drawable_h, output_w, output_h; ++ SDL_GL_GetDrawableSize(window, &drawable_w, &drawable_h); ++ SDL_GetRendererOutputSize(renderer, &output_w, &output_h); ++ INFO("Android size diag: SDL_GetWindowSize=%dx%d SDL_GL_GetDrawableSize=%dx%d SDL_GetRendererOutputSize=%dx%d", ++ width, height, drawable_w, drawable_h, output_w, output_h); ++#endif + opengl_resize(width, height); + + // Now make the palettes diff --git a/android/engine-patches/08-android-logcat-link.patch b/android/engine-patches/08-android-logcat-link.patch new file mode 100644 index 0000000..97d54fc --- /dev/null +++ b/android/engine-patches/08-android-logcat-link.patch @@ -0,0 +1,10 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -440,6 +440,7 @@ + ${FLUIDSYNTH_LIBRARIES} + ${OPENGL_LIBRARIES} + ${ALSA_LIBRARIES} ++ $<$:log> + ) + + # Turn on address sanitizing if wanted (desktop only - not meaningful for diff --git a/android/engine-patches/09-android-logcat-output.patch b/android/engine-patches/09-android-logcat-output.patch new file mode 100644 index 0000000..f17c707 --- /dev/null +++ b/android/engine-patches/09-android-logcat-output.patch @@ -0,0 +1,45 @@ +--- a/src/Libraries/LG/Source/LOG/src/log.c ++++ b/src/Libraries/LG/Source/LOG/src/log.c +@@ -28,6 +28,10 @@ + + #include "log.h" + ++#ifdef __ANDROID__ ++#include ++#endif ++ + static struct { + void *udata; + log_LockFn lock; +@@ -99,6 +103,23 @@ + time_t t = time(NULL); + struct tm *lt = localtime(&t); + ++#ifdef __ANDROID__ ++ /* Plain stdout/stderr isn't captured by logcat on this platform (unlike ++ e.g. gl4es's own "LIBGL"-tagged logging, which goes through this same ++ API directly) - route there instead so every existing INFO/DEBUG/WARN/ ++ ERROR call site in the engine becomes visible for on-device debugging, ++ with no changes needed at those call sites. */ ++ if (!L.quiet) { ++ static const int android_priority[] = { ++ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ++ ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL ++ }; ++ va_list args; ++ va_start(args, fmt); ++ __android_log_vprint(android_priority[level], "QuestShock", fmt, args); ++ va_end(args); ++ } ++#else + /* Log to stderr */ + if (!L.quiet) { + va_list args; +@@ -116,6 +137,7 @@ + va_end(args); + fprintf(stderr, "\n"); + } ++#endif + + /* Log to file */ + if (L.fp) { diff --git a/android/engine-patches/10-android-no-window-resize.patch b/android/engine-patches/10-android-no-window-resize.patch new file mode 100644 index 0000000..e8bf236 --- /dev/null +++ b/android/engine-patches/10-android-no-window-resize.patch @@ -0,0 +1,31 @@ +--- a/src/MacSrc/ShockBitmap.c ++++ b/src/MacSrc/ShockBitmap.c +@@ -42,11 +42,28 @@ + + SDL_RenderClear(renderer); + ++#ifndef __ANDROID__ ++ // On Android there's exactly one OS-controlled-size surface - no ++ // desktop-style window to resize, move, or toggle fullscreen on. ++ // SDL_SetWindowSize() still "succeeds" there (Android has no ++ // SetWindowSize driver hook, so SDL's generic layer just overwrites its ++ // own cached window->w/h to the requested game resolution, e.g. ++ // 640x480, and synthesizes a resize event from that) - which desyncs ++ // SDL's own notion of the window size from the real, unchanged Android ++ // surface size (e.g. 1600x1200), and that desync is exactly what then ++ // makes both SDL's internal renderer viewport and this engine's own ++ // custom GL viewport (OpenGL.cc's opengl_resize(), driven by that same ++ // now-wrong cached size) shrink to the game's resolution instead of ++ // filling the real surface - confirmed on-device via added logcat ++ // diagnostics (see android/engine-patches/07-09) showing the correct ++ // 1600x1200 size at startup, then this exact call sequence collapsing ++ // it to 640x480 the moment the splash screen sets its video mode. + extern bool fullscreenActive; + SDL_SetWindowFullscreen(window, fullscreenActive ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + + SDL_SetWindowSize(window, width, height); + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); ++#endif + + SDL_RenderSetLogicalSize(renderer, width, height); + diff --git a/res/screenshots/com.oculus.vrshell-20260723-195843.jpg b/res/screenshots/com.oculus.vrshell-20260723-195843.jpg new file mode 100644 index 0000000..7002438 Binary files /dev/null and b/res/screenshots/com.oculus.vrshell-20260723-195843.jpg differ diff --git a/res/screenshots/com.oculus.vrshell-20260724-053051.jpg b/res/screenshots/com.oculus.vrshell-20260724-053051.jpg new file mode 100644 index 0000000..cbb9199 Binary files /dev/null and b/res/screenshots/com.oculus.vrshell-20260724-053051.jpg differ