From 469ae2805cc452ce72673eca87d5f042b130ecc8 Mon Sep 17 00:00:00 2001 From: offtkp Date: Tue, 14 Nov 2023 15:30:53 +0200 Subject: [PATCH 01/21] Add initial pandroid files --- CMakeLists.txt | 34 +++- src/emulator.cpp | 2 + src/jni_driver.cpp | 11 ++ src/pandroid/.gitignore | 15 ++ src/pandroid/app/.gitignore | 1 + src/pandroid/app/build.gradle.kts | 46 +++++ src/pandroid/app/proguard-rules.pro | 21 ++ src/pandroid/app/src/main/AndroidManifest.xml | 26 +++ .../com/panda3ds/pandroid/AlberDriver.java | 10 + .../com/panda3ds/pandroid/MainActivity.java | 16 ++ src/pandroid/app/src/main/jniLibs/.gitignore | 2 + .../app/src/main/jniLibs/arm64-v8a/.gitkeep | 0 .../app/src/main/jniLibs/x86_64/.gitkeep | 0 .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 30 +++ .../app/src/main/res/layout/activity_main.xml | 18 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../app/src/main/res/values-night/themes.xml | 7 + .../app/src/main/res/values/colors.xml | 5 + .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/themes.xml | 9 + .../app/src/main/res/xml/backup_rules.xml | 13 ++ .../main/res/xml/data_extraction_rules.xml | 19 ++ src/pandroid/build.gradle.kts | 4 + src/pandroid/gradle.properties | 21 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + src/pandroid/gradlew | 185 ++++++++++++++++++ src/pandroid/gradlew.bat | 89 +++++++++ src/pandroid/settings.gradle.kts | 17 ++ 41 files changed, 782 insertions(+), 10 deletions(-) create mode 100644 src/jni_driver.cpp create mode 100644 src/pandroid/.gitignore create mode 100644 src/pandroid/app/.gitignore create mode 100644 src/pandroid/app/build.gradle.kts create mode 100644 src/pandroid/app/proguard-rules.pro create mode 100644 src/pandroid/app/src/main/AndroidManifest.xml create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/MainActivity.java create mode 100644 src/pandroid/app/src/main/jniLibs/.gitignore create mode 100644 src/pandroid/app/src/main/jniLibs/arm64-v8a/.gitkeep create mode 100644 src/pandroid/app/src/main/jniLibs/x86_64/.gitkeep create mode 100644 src/pandroid/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 src/pandroid/app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 src/pandroid/app/src/main/res/layout/activity_main.xml create mode 100644 src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 src/pandroid/app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 src/pandroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 src/pandroid/app/src/main/res/values-night/themes.xml create mode 100644 src/pandroid/app/src/main/res/values/colors.xml create mode 100644 src/pandroid/app/src/main/res/values/strings.xml create mode 100644 src/pandroid/app/src/main/res/values/themes.xml create mode 100644 src/pandroid/app/src/main/res/xml/backup_rules.xml create mode 100644 src/pandroid/app/src/main/res/xml/data_extraction_rules.xml create mode 100644 src/pandroid/build.gradle.kts create mode 100644 src/pandroid/gradle.properties create mode 100644 src/pandroid/gradle/wrapper/gradle-wrapper.jar create mode 100644 src/pandroid/gradle/wrapper/gradle-wrapper.properties create mode 100755 src/pandroid/gradlew create mode 100644 src/pandroid/gradlew.bat create mode 100644 src/pandroid/settings.gradle.kts diff --git a/CMakeLists.txt b/CMakeLists.txt index c202f80c..2a80b06a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,16 +184,18 @@ set(APPLET_SOURCE_FILES src/core/applets/applet.cpp src/core/applets/mii_selecto set(RENDERER_SW_SOURCE_FILES src/core/renderer_sw/renderer_sw.cpp) # Frontend source files -if(ENABLE_QT_GUI) - set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp) - set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp) +if(NOT ANDROID) + if(ENABLE_QT_GUI) + set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp) + set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp) - source_group("Source Files\\Qt" FILES ${FRONTEND_SOURCE_FILES}) - source_group("Header Files\\Qt" FILES ${FRONTEND_HEADER_FILES}) - include_directories(${Qt6Gui_PRIVATE_INCLUDE_DIRS}) -else() - set(FRONTEND_SOURCE_FILES src/panda_sdl/main.cpp src/panda_sdl/frontend_sdl.cpp) - set(FRONTEND_HEADER_FILES "") + source_group("Source Files\\Qt" FILES ${FRONTEND_SOURCE_FILES}) + source_group("Header Files\\Qt" FILES ${FRONTEND_HEADER_FILES}) + include_directories(${Qt6Gui_PRIVATE_INCLUDE_DIRS}) + else() + set(FRONTEND_SOURCE_FILES src/panda_sdl/main.cpp src/panda_sdl/frontend_sdl.cpp) + set(FRONTEND_HEADER_FILES "") + endif() endif() set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp @@ -378,6 +380,10 @@ if(ENABLE_VULKAN) set(ALL_SOURCES ${ALL_SOURCES} ${RENDERER_VK_SOURCE_FILES}) endif() +if(ANDROID) + set(ALL_SOURCES ${ALL_SOURCES} src/jni_driver.cpp) +endif() + if(BUILD_HYDRA_CORE) include_directories(third_party/hydra_core/include) add_library(Alber SHARED ${ALL_SOURCES} src/hydra_core.cpp) @@ -386,11 +392,19 @@ else() add_executable(Alber ${ALL_SOURCES}) endif() +if(ANDROID) + target_link_libraries(Alber PRIVATE log) +endif() + if(ENABLE_LTO OR ENABLE_USER_BUILD) set_target_properties(Alber PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() -target_link_libraries(Alber PRIVATE dynarmic SDL2-static cryptopp glad resources_console_fonts) +target_link_libraries(Alber PRIVATE dynarmic cryptopp glad resources_console_fonts) + +if(NOT ANDROID) + target_link_libraries(Alber PRIVATE SDL2-static) +endif() if(ENABLE_DISCORD_RPC AND NOT ANDROID) target_compile_definitions(Alber PUBLIC "PANDA3DS_ENABLE_DISCORD_RPC=1") diff --git a/src/emulator.cpp b/src/emulator.cpp index 81d3ac5c..cd6bbdcb 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -1,6 +1,8 @@ #include "emulator.hpp" +#ifndef __ANDROID__ #include +#endif #include diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp new file mode 100644 index 00000000..c2a00d7b --- /dev/null +++ b/src/jni_driver.cpp @@ -0,0 +1,11 @@ +#include +#include +#include "emulator.hpp" + +std::unique_ptr emulator; + +extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_Initialize(JNIEnv* env, jobject obj) { + __android_log_print(ANDROID_LOG_INFO, "Panda3DS", "Initializing Alber Driver"); + emulator = std::make_unique(); + __android_log_print(ANDROID_LOG_INFO, "Panda3DS", "Done"); +} \ No newline at end of file diff --git a/src/pandroid/.gitignore b/src/pandroid/.gitignore new file mode 100644 index 00000000..aa724b77 --- /dev/null +++ b/src/pandroid/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/src/pandroid/app/.gitignore b/src/pandroid/app/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/src/pandroid/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/src/pandroid/app/build.gradle.kts b/src/pandroid/app/build.gradle.kts new file mode 100644 index 00000000..ff8debcb --- /dev/null +++ b/src/pandroid/app/build.gradle.kts @@ -0,0 +1,46 @@ +plugins { + id("com.android.application") +} + +android { + namespace = "com.panda3ds.pandroid" + compileSdk = 33 + + defaultConfig { + applicationId = "com.panda3ds.pandroid" + minSdk = 24 + targetSdk = 33 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + ndk { + abiFilters += listOf("x86_64", "arm64-v8a") + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +dependencies { + + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.8.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") +} \ No newline at end of file diff --git a/src/pandroid/app/proguard-rules.pro b/src/pandroid/app/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/src/pandroid/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/src/pandroid/app/src/main/AndroidManifest.xml b/src/pandroid/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8047484a --- /dev/null +++ b/src/pandroid/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java new file mode 100644 index 00000000..55bcd47e --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java @@ -0,0 +1,10 @@ +package com.panda3ds.pandroid; + +public class AlberDriver { + + public static native void Initialize(); + + static { + System.loadLibrary("Alber"); + } +} \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/MainActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/MainActivity.java new file mode 100644 index 00000000..e2ab412b --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/MainActivity.java @@ -0,0 +1,16 @@ +package com.panda3ds.pandroid; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + AlberDriver.Initialize(); + } +} \ No newline at end of file diff --git a/src/pandroid/app/src/main/jniLibs/.gitignore b/src/pandroid/app/src/main/jniLibs/.gitignore new file mode 100644 index 00000000..0b469178 --- /dev/null +++ b/src/pandroid/app/src/main/jniLibs/.gitignore @@ -0,0 +1,2 @@ +# Prebuilt Alber libraries will be placed in this directory, but we don't want to push them to the repo +libAlber.so \ No newline at end of file diff --git a/src/pandroid/app/src/main/jniLibs/arm64-v8a/.gitkeep b/src/pandroid/app/src/main/jniLibs/arm64-v8a/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/pandroid/app/src/main/jniLibs/x86_64/.gitkeep b/src/pandroid/app/src/main/jniLibs/x86_64/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/pandroid/app/src/main/res/drawable/ic_launcher_background.xml b/src/pandroid/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/src/pandroid/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pandroid/app/src/main/res/drawable/ic_launcher_foreground.xml b/src/pandroid/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/src/pandroid/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/layout/activity_main.xml b/src/pandroid/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..17eab17b --- /dev/null +++ b/src/pandroid/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..6f3b755b --- /dev/null +++ b/src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..6f3b755b --- /dev/null +++ b/src/pandroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/src/pandroid/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..c209e78ecd372343283f4157dcfd918ec5165bb3 GIT binary patch literal 1404 zcmV-?1%vuhNk&F=1pok7MM6+kP&il$0000G0000-002h-06|PpNX!5L00Dqw+t%{r zzW2vH!KF=w&cMnnN@{whkTw+#mAh0SV?YL=)3MimFYCWp#fpdtz~8$hD5VPuQgtcN zXl<@<#Cme5f5yr2h%@8TWh?)bSK`O z^Z@d={gn7J{iyxL_y_%J|L>ep{dUxUP8a{byupH&!UNR*OutO~0{*T4q5R6@ApLF! z5{w?Z150gC7#>(VHFJZ-^6O@PYp{t!jH(_Z*nzTK4 zkc{fLE4Q3|mA2`CWQ3{8;gxGizgM!zccbdQoOLZc8hThi-IhN90RFT|zlxh3Ty&VG z?Fe{#9RrRnxzsu|Lg2ddugg7k%>0JeD+{XZ7>Z~{=|M+sh1MF7~ zz>To~`~LVQe1nNoR-gEzkpe{Ak^7{{ZBk2i_<+`Bq<^GB!RYG+z)h;Y3+<{zlMUYd zrd*W4w&jZ0%kBuDZ1EW&KLpyR7r2=}fF2%0VwHM4pUs}ZI2egi#DRMYZPek*^H9YK zay4Iy3WXFG(F14xYsoDA|KXgGc5%2DhmQ1gFCkrgHBm!lXG8I5h*uf{rn48Z!_@ z4Bk6TJAB2CKYqPjiX&mWoW>OPFGd$wqroa($ne7EUK;#3VYkXaew%Kh^3OrMhtjYN?XEoY`tRPQsAkH-DSL^QqyN0>^ zmC>{#F14jz4GeW{pJoRpLFa_*GI{?T93^rX7SPQgT@LbLqpNA}<@2wH;q493)G=1Y z#-sCiRNX~qf3KgiFzB3I>4Z%AfS(3$`-aMIBU+6?gbgDb!)L~A)je+;fR0jWLL-Fu z4)P{c7{B4Hp91&%??2$v9iRSFnuckHUm}or9seH6 z>%NbT+5*@L5(I9j@06@(!{ZI?U0=pKn8uwIg&L{JV14+8s2hnvbRrU|hZCd}IJu7*;;ECgO%8_*W Kmw_-CKmY()leWbG literal 0 HcmV?d00001 diff --git a/src/pandroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/src/pandroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..b2dfe3d1ba5cf3ee31b3ecc1ced89044a1f3b7a9 GIT binary patch literal 2898 zcmV-Y3$650Nk&FW3jhFDMM6+kP&il$0000G0000-002h-06|PpNWB9900E$G+qN-D z+81ABX7q?;bwx%xBg?kcwr$(C-Tex-ZCkHUw(Y9#+`E5-zuONG5fgw~E2WDng@Bc@ z24xy+R1n%~6xI#u9vJ8zREI)sb<&Il(016}Z~V1n^PU3-_H17A*Bf^o)&{_uBv}Py zulRfeE8g(g6HFhk_?o_;0@tz?1I+l+Y#Q*;RVC?(ud`_cU-~n|AX-b`JHrOIqn(-t&rOg-o`#C zh0LPxmbOAEb;zHTu!R3LDh1QO zZTf-|lJNUxi-PpcbRjw3n~n-pG;$+dIF6eqM5+L();B2O2tQ~|p{PlpNcvDbd1l%c zLtXn%lu(3!aNK!V#+HNn_D3lp z2%l+hK-nsj|Bi9;V*WIcQRTt5j90A<=am+cc`J zTYIN|PsYAhJ|=&h*4wI4ebv-C=Be#u>}%m;a{IGmJDU`0snWS&$9zdrT(z8#{OZ_Y zxwJx!ZClUi%YJjD6Xz@OP8{ieyJB=tn?>zaI-4JN;rr`JQbb%y5h2O-?_V@7pG_+y z(lqAsqYr!NyVb0C^|uclHaeecG)Sz;WV?rtoqOdAAN{j%?Uo%owya(F&qps@Id|Of zo@~Y-(YmfB+chv^%*3g4k3R0WqvuYUIA+8^SGJ{2Bl$X&X&v02>+0$4?di(34{pt* zG=f#yMs@Y|b&=HyH3k4yP&goF2LJ#tBLJNNDo6lG06r}ghC-pC4Q*=x3;|+W04zte zAl>l4kzUBQFYF(E`KJy?ZXd1tnfbH+Z~SMmA21KokJNs#eqcXWKUIC>{TuoKe^vhF z);H)o`t9j~`$h1D`#bxe@E`oE`cM9w(@)5Bp8BNukIwM>wZHfd0S;5bcXA*5KT3bj zc&_~`&{z7u{Et!Z_k78H75gXf4g8<_ul!H$eVspPeU3j&&Au=2R*Zp#M9$9s;fqwgzfiX=E_?BwVcfx3tG9Q-+<5fw z%Hs64z)@Q*%s3_Xd5>S4dg$s>@rN^ixeVj*tqu3ZV)biDcFf&l?lGwsa zWj3rvK}?43c{IruV2L`hUU0t^MemAn3U~x3$4mFDxj=Byowu^Q+#wKRPrWywLjIAp z9*n}eQ9-gZmnd9Y0WHtwi2sn6n~?i#n9VN1B*074_VbZZ=WrpkMYr{RsI ztM_8X1)J*DZejxkjOTRJ&a*lrvMKBQURNP#K)a5wIitfu(CFYV4FT?LUB$jVwJSZz zNBFTWg->Yk0j&h3e*a5>B=-xM7dE`IuOQna!u$OoxLlE;WdrNlN)1 z7**de7-hZ!(%_ZllHBLg`Ir#|t>2$*xVOZ-ADZKTN?{(NUeLU9GbuG-+Axf*AZ-P1 z0ZZ*fx+ck4{XtFsbcc%GRStht@q!m*ImssGwuK+P@%gEK!f5dHymg<9nSCXsB6 zQ*{<`%^bxB($Z@5286^-A(tR;r+p7B%^%$N5h%lb*Vlz-?DL9x;!j<5>~kmXP$E}m zQV|7uv4SwFs0jUervsxVUm>&9Y3DBIzc1XW|CUZrUdb<&{@D5yuLe%Xniw^x&{A2s z0q1+owDSfc3Gs?ht;3jw49c#mmrViUfX-yvc_B*wY|Lo7; zGh!t2R#BHx{1wFXReX*~`NS-LpSX z#TV*miO^~B9PF%O0huw!1Zv>^d0G3$^8dsC6VI!$oKDKiXdJt{mGkyA`+Gwd4D-^1qtNTUK)`N*=NTG-6}=5k6suNfdLt*dt8D| z%H#$k)z#ZRcf|zDWB|pn<3+7Nz>?WW9WdkO5(a^m+D4WRJ9{wc>Y}IN)2Kbgn;_O? zGqdr&9~|$Y0tP=N(k7^Eu;iO*w+f%W`20BNo)=Xa@M_)+o$4LXJyiw{F?a633SC{B zl~9FH%?^Rm*LVz`lkULs)%idDX^O)SxQol(3jDRyBVR!7d`;ar+D7do)jQ}m`g$TevUD5@?*P8)voa?kEe@_hl{_h8j&5eB-5FrYW&*FHVt$ z$kRF9Nstj%KRzpjdd_9wO=4zO8ritN*NPk_9avYrsF(!4))tm{Ga#OY z(r{0buexOzu7+rw8E08Gxd`LTOID{*AC1m*6Nw@osfB%0oBF5sf<~wH1kL;sd zo)k6^VyRFU`)dt*iX^9&QtWbo6yE8XXH?`ztvpiOLgI3R+=MOBQ9=rMVgi<*CU%+d1PQQ0a1U=&b0vkF207%xU0ssI2 literal 0 HcmV?d00001 diff --git a/src/pandroid/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/src/pandroid/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..4f0f1d64e58ba64d180ce43ee13bf9a17835fbca GIT binary patch literal 982 zcmV;{11bDcNk&G_0{{S5MM6+kP&il$0000G0000l001ul06|PpNU8t;00Dqo+t#w^ z^1csucXz7-Qrhzl9HuHB%l>&>1tG2^vb*E&k^T3$FG1eQZ51g$uv4V+kI`0<^1Z@N zk?Jjh$olyC%l>)Xq;7!>{iBj&BjJ`P&$fsCfpve_epJOBkTF?nu-B7D!hO=2ZR}

C%4 zc_9eOXvPbC4kzU8YowIA8cW~Uv|eB&yYwAObSwL2vY~UYI7NXPvf3b+c^?wcs~_t{ ze_m66-0)^{JdOMKPwjpQ@Sna!*?$wTZ~su*tNv7o!gXT!GRgivP}ec?5>l1!7<(rT zds|8x(qGc673zrvYIz;J23FG{9nHMnAuP}NpAED^laz3mAN1sy+NXK)!6v1FxQ;lh zOBLA>$~P3r4b*NcqR;y6pwyhZ3_PiDb|%n1gGjl3ZU}ujInlP{eks-#oA6>rh&g+!f`hv#_%JrgYPu z(U^&XLW^QX7F9Z*SRPpQl{B%x)_AMp^}_v~?j7 zapvHMKxSf*Mtyx8I}-<*UGn3)oHd(nn=)BZ`d$lDBwq_GL($_TPaS{UeevT(AJ`p0 z9%+hQb6z)U9qjbuXjg|dExCLjpS8$VKQ55VsIC%@{N5t{NsW)=hNGI`J=x97_kbz@ E0Of=7!TQj4N+cqN`nQhxvX7dAV-`K|Ub$-q+H-5I?Tx0g9jWxd@A|?POE8`3b8fO$T))xP* z(X?&brZw({`)WU&rdAs1iTa0x6F@PIxJ&&L|dpySV!ID|iUhjCcKz(@mE z!x@~W#3H<)4Ae(4eQJRk`Iz3<1)6^m)0b_4_TRZ+cz#eD3f8V;2r-1fE!F}W zEi0MEkTTx}8i1{`l_6vo0(Vuh0HD$I4SjZ=?^?k82R51bC)2D_{y8mi_?X^=U?2|F{Vr7s!k(AZC$O#ZMyavHhlQ7 zUR~QXuH~#o#>(b$u4?s~HLF*3IcF7023AlwAYudn0FV~|odGH^05AYPEfR)8p`i{n zwg3zPVp{+wOsxKc>)(pMupKF!Y2HoUqQ3|Yu|8lwR=?5zZuhG6J?H`bSNk_wPoM{u zSL{c@pY7+c2kck>`^q1^^gR0QB7Y?KUD{vz-uVX~;V-rW)PDcI)$_UjgVV?S?=oLR zf4}zz{#*R_{LkiJ#0RdQLNC^2Vp%JPEUvG9ra2BVZ92(p9h7Ka@!yf9(lj#}>+|u* z;^_?KWdzkM`6gqPo9;;r6&JEa)}R3X{(CWv?NvgLeOTq$cZXqf7|sPImi-7cS8DCN zGf;DVt3Am`>hH3{4-WzH43Ftx)SofNe^-#|0HdCo<+8Qs!}TZP{HH8~z5n`ExcHuT zDL1m&|DVpIy=xsLO>8k92HcmfSKhflQ0H~9=^-{#!I1g(;+44xw~=* zxvNz35vfsQE)@)Zsp*6_GjYD};Squ83<_?^SbALb{a`j<0Gn%6JY!zhp=Fg}Ga2|8 z52e1WU%^L1}15Ex0fF$e@eCT(()_P zvV?CA%#Sy08_U6VPt4EtmVQraWJX` zh=N|WQ>LgrvF~R&qOfB$!%D3cGv?;Xh_z$z7k&s4N)$WYf*k=|*jCEkO19{h_(%W4 zPuOqbCw`SeAX*R}UUsbVsgtuG?xs(#Ikx9`JZoQFz0n*7ZG@Fv@kZk`gzO$HoA9kN z8U5{-yY zvV{`&WKU2$mZeoBmiJrEdzUZAv1sRxpePdg1)F*X^Y)zp^Y*R;;z~vOv-z&)&G)JQ{m!C9cmziu1^nHA z`#`0c>@PnQ9CJKgC5NjJD8HM3|KC(g5nnCq$n0Gsu_DXk36@ql%npEye|?%RmG)

FJ$wK}0tWNB{uH;AM~i literal 0 HcmV?d00001 diff --git a/src/pandroid/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/src/pandroid/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..948a3070fe34c611c42c0d3ad3013a0dce358be0 GIT binary patch literal 1900 zcmV-y2b1_xNk&Fw2LJ$9MM6+kP&il$0000G0001A003VA06|PpNH75a00DqwTbm-~ zullQTcXxO9ki!OCRx^i?oR|n!<8G0=kI^!JSjFi-LL*`V;ET0H2IXfU0*i>o6o6Gy zRq6Ap5(_{XLdXcL-MzlN`ugSdZY_`jXhcENAu)N_0?GhF))9R;E`!bo9p?g?SRgw_ zEXHhFG$0{qYOqhdX<(wE4N@es3VIo$%il%6xP9gjiBri+2pI6aY4 zJbgh-Ud|V%3O!IcHKQx1FQH(_*TK;1>FQWbt^$K1zNn^cczkBs=QHCYZ8b&l!UV{K z{L0$KCf_&KR^}&2Fe|L&?1I7~pBENnCtCuH3sjcx6$c zwqkNkru);ie``q+_QI;IYLD9OV0ZxkuyBz|5<$1BH|vtey$> z5oto4=l-R-Aaq`Dk0}o9N0VrkqW_#;!u{!bJLDq%0092{Ghe=F;(kn} z+sQ@1=UlX30+2nWjkL$B^b!H2^QYO@iFc0{(-~yXj2TWz?VG{v`Jg zg}WyYnwGgn>{HFaG7E~pt=)sOO}*yd(UU-D(E&x{xKEl6OcU?pl)K%#U$dn1mDF19 zSw@l8G!GNFB3c3VVK0?uyqN&utT-D5%NM4g-3@Sii9tSXKtwce~uF zS&Jn746EW^wV~8zdQ1XC28~kXu8+Yo9p!<8h&(Q({J*4DBglPdpe4M_mD8AguZFn~ ztiuO~{6Bx?SfO~_ZV(GIboeR9~hAym{{fV|VM=77MxDrbW6`ujX z<3HF(>Zr;#*uCvC*bpoSr~C$h?_%nXps@A)=l_;({Fo#6Y1+Zv`!T5HB+)#^-Ud_; zBwftPN=d8Vx)*O1Mj+0oO=mZ+NVH*ptNDC-&zZ7Hwho6UQ#l-yNvc0Cm+2$$6YUk2D2t#vdZX-u3>-Be1u9gtTBiMB^xwWQ_rgvGpZ6(C@e23c!^K=>ai-Rqu zhqT`ZQof;9Bu!AD(i^PCbYV%yha9zuoKMp`U^z;3!+&d@Hud&_iy!O-$b9ZLcSRh? z)R|826w}TU!J#X6P%@Zh=La$I6zXa#h!B;{qfug}O%z@K{EZECu6zl)7CiNi%xti0 zB{OKfAj83~iJvmpTU|&q1^?^cIMn2RQ?jeSB95l}{DrEPTW{_gmU_pqTc)h@4T>~& zluq3)GM=xa(#^VU5}@FNqpc$?#SbVsX!~RH*5p0p@w z;~v{QMX0^bFT1!cXGM8K9FP+=9~-d~#TK#ZE{4umGT=;dfvWi?rYj;^l_Zxywze`W z^Cr{55U@*BalS}K%Czii_80e0#0#Zkhlij4-~I@}`-JFJ7$5{>LnoJSs??J8kWVl6|8A}RCGAu9^rAsfCE=2}tHwl93t0C?#+jMpvr7O3`2=tr{Hg$=HlnjVG^ewm|Js0J*kfPa6*GhtB>`fN!m#9J(sU!?(OSfzY*zS(FJ<-Vb zfAIg+`U)YaXv#sY(c--|X zEB+TVyZ%Ie4L$gi#Fc++`h6%vzsS$pjz9aLt+ZL(g;n$Dzy5=m=_TV(3H8^C{r0xd zp#a%}ht55dOq?yhwYPrtp-m1xXp;4X;)NhxxUpgP%XTLmO zcjaFva^}dP3$&sfFTIR_jC=2pHh9kpI@2(6V*GQo7Ws)`j)hd+tr@P~gR*2gO@+1? zG<`_tB+LJuF|SZ9tIec;h%}}6WClT`L>HSW?E{Hp1h^+mlbf_$9zA>!ug>NALJsO{ mU%z=YwVD?}XMya)Bp;vlyE5&E_6!fzx9pwrdz474!~g(M6R?N? literal 0 HcmV?d00001 diff --git a/src/pandroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/src/pandroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..1b9a6956b3acdc11f40ce2bb3f6efbd845cc243f GIT binary patch literal 3918 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�(p-{x$&=IACIfoAR!za)F-^da-t3#0Dycnp zwO~NVXwXCl;jE<}>%@xz|=8fIJAB?>+E{7)|4l${4ngA3G|=r z2Dyv;VVWSgZx9Wj>qUjleGl3Ei9K4>h!(lPS%8VOG>Xu0%6VDz^O=bjJmuP7>DeUv zrbI}MlHB^^d?{zv6d=@_ZD2lg1&G7UjnVN{1}9WkaM3H~btX0GtSzB+tZ^qRgWo4m z!GmimlG$=wgXCnr6j@m<1gAL46#T~5Bnm=2{^@>|t&`9mkEPddj zAvG~@Tv~TAm2i%VW}R-g(Z0)z-Y|szHr@rk>4MAyG*Ma*7Yh#H7(!-5>DZ@8r;_dx z{prSe<>~099F8vsYd2xff7uAS%7{S)f(|@me3t2$iy&NEc7OUEchp@9A|X;;IA>8!oX+y(BKJ$EzV* znR$z;!L$s7uy@{OT~nG#B!NRraT8(X##Ho!0r_o@gg0CA-9H^;-uE&?$2$nHv_00o z%cbuUc-tCx$Uh&EZ4Nf4Zgqv)Y6>usG3>GeQnxx_Z6+PcbX-+ysbt1hQ`K1LDpOE? zrAhIZhSN9yVIAOa22gn577tbc&i3|3V8NWy&!tw##`}9*x}gtI^h1DzZRA>UuaJG) zaZ7j)dq!O}{?#8Y7~7i6fHh4{`pL?>-18|p!S75Y#^DM>-S3)vuZG+Q7l@ek zQP~#cBpWgg#mApc_sPYjpw8odQuRokmTkzcNl`^CcKB7e&;zViV;{Y{o^Y$%7i0m# z62%#1Lq!RC?}lK>%mp}T!3Xv;L*0v*>USLm``N%>w>@fwC+#T&Tx2bN4w(20JB}oU zuSa6v^kXi0xPs?pbaOHnyiqq6By1EZY9OZ^^QA>{q-Hsd&m`pbQ%8121aWG-F5xf zlZ%;B{;C>X19|`^_?dVyCq>n+41w7|!tUS!{9rHlbhX=SZO5CQ^;!Du_E7*`GiR^Q w)2!4MKjfSAeNo!9>IaV6aUZ*?W>} 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

UmY2RIYtNPVDpE$%vda+HD#3m z&VuXJ{BK&Qe+rBa7eq}Q(bq|tn(RrJAk|ztj2(i{d>nmQnM?;HF2k&9sA6up5tmjl z7lySlzMbifH17-m-Lwa_F&e7nOH?ESi3#ckR3tsM+jsck3`oG!uMS}|eAwVXv>}qxwq?QY%QJ0}r@^;fhuUA9W z*BVl>TGo&N004@xSiwDUXUvp51sVmqO3m)=B55aPwf@0=e}cN+$-BdKxY`YrT_4)0 z_d10#i44Q*rFr8MC>*)v$EJvz``(pb{e&*6k+b zsMz%($|1+8hn8c2?P(l@;Rb&CsZeYoCI3?2!LqjbwPXW3z4G$Qfj=cT5Yb%vY0(AX oeb?AaKtwrnc|$|zzw9vfvn^aJJ!zd)XFXqqy0000001=f@-~a#s literal 0 HcmV?d00001 diff --git a/src/pandroid/app/src/main/res/values-night/themes.xml b/src/pandroid/app/src/main/res/values-night/themes.xml new file mode 100644 index 00000000..98dd320a --- /dev/null +++ b/src/pandroid/app/src/main/res/values-night/themes.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/values/colors.xml b/src/pandroid/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..c8524cd9 --- /dev/null +++ b/src/pandroid/app/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/values/strings.xml b/src/pandroid/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..40c0990f --- /dev/null +++ b/src/pandroid/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + pandroid + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/values/themes.xml b/src/pandroid/app/src/main/res/values/themes.xml new file mode 100644 index 00000000..812da8ea --- /dev/null +++ b/src/pandroid/app/src/main/res/values/themes.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file From c1162678bb5783d4b10b919de86726141019a918 Mon Sep 17 00:00:00 2001 From: offtkp Date: Tue, 28 Nov 2023 13:26:07 +0200 Subject: [PATCH 05/21] Cleanup jni_driver --- patch.patch | 118 ------------------ src/jni_driver.cpp | 78 ++++++------ .../panda3ds/pandroid/app/GameActivity.java | 2 +- 3 files changed, 40 insertions(+), 158 deletions(-) delete mode 100644 patch.patch diff --git a/patch.patch b/patch.patch deleted file mode 100644 index 98cad32b..00000000 --- a/patch.patch +++ /dev/null @@ -1,118 +0,0 @@ -diff --git a/src/host_shaders/opengl_display.frag b/src/host_shaders/opengl_display.frag -index 612671c8..1937f711 100644 ---- a/src/host_shaders/opengl_display.frag -+++ b/src/host_shaders/opengl_display.frag -@@ -1,4 +1,5 @@ --#version 410 core -+#version 300 es -+precision mediump float; - in vec2 UV; - out vec4 FragColor; - -diff --git a/src/host_shaders/opengl_display.vert b/src/host_shaders/opengl_display.vert -index 990e2f80..6917c23c 100644 ---- a/src/host_shaders/opengl_display.vert -+++ b/src/host_shaders/opengl_display.vert -@@ -1,4 +1,4 @@ --#version 410 core -+#version 300 es - out vec2 UV; - - void main() { -diff --git a/src/host_shaders/opengl_fragment_shader.frag b/src/host_shaders/opengl_fragment_shader.frag -index f6fa6c55..b0850438 100644 ---- a/src/host_shaders/opengl_fragment_shader.frag -+++ b/src/host_shaders/opengl_fragment_shader.frag -@@ -1,4 +1,5 @@ --#version 410 core -+#version 300 es -+precision mediump float; - - in vec3 v_tangent; - in vec3 v_normal; -@@ -27,7 +28,7 @@ uniform bool u_depthmapEnable; - uniform sampler2D u_tex0; - uniform sampler2D u_tex1; - uniform sampler2D u_tex2; --uniform sampler1DArray u_tex_lighting_lut; -+// uniform sampler1DArray u_tex_lighting_lut; - - uniform uint u_picaRegs[0x200 - 0x48]; - -@@ -145,9 +146,15 @@ vec4 tevCalculateCombiner(int tev_id) { - #define RR_LUT 6u - - float lutLookup(uint lut, uint light, float value) { -- if (lut >= FR_LUT && lut <= RR_LUT) lut -= 1; -- if (lut == SP_LUT) lut = light + 8; -- return texture(u_tex_lighting_lut, vec2(value, lut)).r; -+ // if (lut >= FR_LUT && lut <= RR_LUT) lut -= 1; -+ // if (lut == SP_LUT) lut = light + 8; -+ // return texture(u_tex_lighting_lut, vec2(value, lut)).r; -+ return 0.0; -+} -+ -+uint bitfieldExtract(uint val, int off, int size) { -+ uint mask = uint((1 << size) - 1); -+ return uint(val >> off) & mask; - } - - vec3 regToColor(uint reg) { -diff --git a/src/host_shaders/opengl_vertex_shader.vert b/src/host_shaders/opengl_vertex_shader.vert -index a25d7a6d..5967ccd6 100644 ---- a/src/host_shaders/opengl_vertex_shader.vert -+++ b/src/host_shaders/opengl_vertex_shader.vert -@@ -1,4 +1,4 @@ --#version 410 core -+#version 300 es - - layout(location = 0) in vec4 a_coords; - layout(location = 1) in vec4 a_quaternion; -@@ -20,7 +20,7 @@ out vec2 v_texcoord2; - flat out vec4 v_textureEnvColor[6]; - flat out vec4 v_textureEnvBufferColor; - --out float gl_ClipDistance[2]; -+// out float gl_ClipDistance[2]; - - // TEV uniforms - uniform uint u_textureEnvColor[6]; -@@ -93,6 +93,6 @@ void main() { - ); - - // There's also another, always-on clipping plane based on vertex z -- gl_ClipDistance[0] = -a_coords.z; -- gl_ClipDistance[1] = dot(clipData, a_coords); -+ // gl_ClipDistance[0] = -a_coords.z; -+ // gl_ClipDistance[1] = dot(clipData, a_coords); - } -diff --git a/third_party/opengl/opengl.hpp b/third_party/opengl/opengl.hpp -index f368f573..5ead7f63 100644 ---- a/third_party/opengl/opengl.hpp -+++ b/third_party/opengl/opengl.hpp -@@ -520,21 +520,21 @@ namespace OpenGL { - static void enableBlend() { glEnable(GL_BLEND); } - static void disableBlend() { glDisable(GL_BLEND); } - static void enableLogicOp() { glEnable(GL_COLOR_LOGIC_OP); } -- static void disableLogicOp() { glDisable(GL_COLOR_LOGIC_OP); } -+ static void disableLogicOp() { /* glDisable(GL_COLOR_LOGIC_OP); */ } - static void enableDepth() { glEnable(GL_DEPTH_TEST); } - static void disableDepth() { glDisable(GL_DEPTH_TEST); } - static void enableStencil() { glEnable(GL_STENCIL_TEST); } - static void disableStencil() { glDisable(GL_STENCIL_TEST); } - -- static void enableClipPlane(GLuint index) { glEnable(GL_CLIP_DISTANCE0 + index); } -- static void disableClipPlane(GLuint index) { glDisable(GL_CLIP_DISTANCE0 + index); } -+ static void enableClipPlane(GLuint index) { /* glEnable(GL_CLIP_DISTANCE0 + index); */ } -+ static void disableClipPlane(GLuint index) { /* glDisable(GL_CLIP_DISTANCE0 + index); */ } - - static void setDepthFunc(DepthFunc func) { glDepthFunc(static_cast(func)); } - static void setColourMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { glColorMask(r, g, b, a); } - static void setDepthMask(GLboolean mask) { glDepthMask(mask); } - - // TODO: Add a proper enum for this -- static void setLogicOp(GLenum op) { glLogicOp(op); } -+ static void setLogicOp(GLenum op) { /* glLogicOp(op); */ } - - enum Primitives { - Triangle = GL_TRIANGLES, diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp index 5cd519e6..422096d8 100644 --- a/src/jni_driver.cpp +++ b/src/jni_driver.cpp @@ -1,74 +1,74 @@ -#include -#include -#include #include -#include "renderer_gl/renderer_gl.hpp" +#include +#include + +#include + #include "emulator.hpp" +#include "renderer_gl/renderer_gl.hpp" +#include "services/hid.hpp" std::unique_ptr emulator = nullptr; +HIDService* hidService = nullptr; RendererGL* renderer = nullptr; bool romLoaded = false; extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_Initialize(JNIEnv* env, jobject obj) { - emulator = std::make_unique(); - if (emulator->getRendererType() != RendererType::OpenGL) { - throw std::runtime_error("Renderer is not OpenGL"); - } - renderer = static_cast(emulator->getRenderer()); - __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "OpenGL ES Before %d.%d", GLVersion.major, GLVersion.minor); - if (!gladLoadGLES2Loader(reinterpret_cast(eglGetProcAddress))) { + emulator = std::make_unique(); + + if (emulator->getRendererType() != RendererType::OpenGL) { + throw std::runtime_error("Renderer is not OpenGL"); + } + + renderer = static_cast(emulator->getRenderer()); + hidService = &emulator->getServiceManager().getHID(); + + if (!gladLoadGLES2Loader(reinterpret_cast(eglGetProcAddress))) { throw std::runtime_error("OpenGL ES init failed"); } - __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "OpenGL ES %d.%d", GLVersion.major, GLVersion.minor); + + __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "OpenGL ES %d.%d", GLVersion.major, GLVersion.minor); emulator->initGraphicsContext(nullptr); } extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_RunFrame(JNIEnv* env, jobject obj, jint fbo) { - renderer->setFBO(fbo); - renderer->resetStateManager(); - emulator->runFrame(); - - emulator->getServiceManager().getHID().updateInputs(emulator->getTicks()); + renderer->setFBO(fbo); + renderer->resetStateManager(); + emulator->runFrame(); + + hidService->updateInputs(emulator->getTicks()); } extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_Finalize(JNIEnv* env, jobject obj) { - emulator = nullptr; - renderer = nullptr; + emulator = nullptr; + hidService = nullptr; + renderer = nullptr; } -extern "C" JNIEXPORT jboolean JNICALL Java_com_panda3ds_pandroid_AlberDriver_HasRomLoaded(JNIEnv* env, jobject obj) { - return romLoaded; -} +extern "C" JNIEXPORT jboolean JNICALL Java_com_panda3ds_pandroid_AlberDriver_HasRomLoaded(JNIEnv* env, jobject obj) { return romLoaded; } extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_LoadRom(JNIEnv* env, jobject obj, jstring path) { - const char* pathStr = env->GetStringUTFChars(path, nullptr); - __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "Loading ROM %s", pathStr); - romLoaded = emulator->loadROM(pathStr); - env->ReleaseStringUTFChars(path, pathStr); + const char* pathStr = env->GetStringUTFChars(path, nullptr); + __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "Loading ROM %s", pathStr); + romLoaded = emulator->loadROM(pathStr); + env->ReleaseStringUTFChars(path, pathStr); } - - extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_TouchScreenDown(JNIEnv* env, jobject obj, jint x, jint y) { - emulator->getServiceManager().getHID().setTouchScreenPress((u16)x, (u16)y); -} - -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_TouchScreenUp(JNIEnv* env, jobject obj) { - emulator->getServiceManager().getHID().releaseTouchScreen(); + hidService->setTouchScreenPress((u16)x, (u16)y); } +extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_TouchScreenUp(JNIEnv* env, jobject obj) { hidService->releaseTouchScreen(); } extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_KeyUp(JNIEnv* env, jobject obj, jint keyCode) { - emulator->getServiceManager().getHID().releaseKey((u32)keyCode); + hidService->releaseKey((u32)keyCode); } extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_KeyDown(JNIEnv* env, jobject obj, jint keyCode) { - emulator->getServiceManager().getHID().pressKey((u32)keyCode); + hidService->pressKey((u32)keyCode); } extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_SetCirclepadAxis(JNIEnv* env, jobject obj, jint x, jint y) { - emulator->getServiceManager().getHID().setCirclepadX((s16)x); - emulator->getServiceManager().getHID().setCirclepadY((s16)y); + hidService->setCirclepadX((s16)x); + hidService->setCirclepadY((s16)y); } - - diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index 275797fb..60fe8724 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -38,7 +38,7 @@ public class GameActivity extends BaseActivity { return; } - pandaSurface = new PandaGlSurfaceView(this, intent.getStringExtra(Constants.EXTRA_PATH));; + pandaSurface = new PandaGlSurfaceView(this, intent.getStringExtra(Constants.EXTRA_PATH)); setContentView(R.layout.game_activity); From 200a884589238d240c63bb3bdea0632a65300cf2 Mon Sep 17 00:00:00 2001 From: offtkp Date: Tue, 28 Nov 2023 14:05:51 +0200 Subject: [PATCH 06/21] Various cleanups --- .../panda3ds/pandroid/app/GameActivity.java | 2 +- .../com/panda3ds/pandroid/math/Vector2.java | 3 ++ .../panda3ds/pandroid/utils/Constants.java | 3 ++ .../pandroid/view/PandaGlRenderer.java | 29 +++++++++---------- .../pandroid/view/PandaGlSurfaceView.java | 4 --- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index 60fe8724..5c234423 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -33,7 +33,7 @@ public class GameActivity extends BaseActivity { if(!intent.hasExtra(Constants.EXTRA_PATH)){ setContentView(new FrameLayout(this)); - Toast.makeText(this, "INVALID ROM PATH", Toast.LENGTH_LONG).show(); + Toast.makeText(this, "Invalid rom path!", Toast.LENGTH_LONG).show(); finish(); return; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java index 8d413203..9c5b45b7 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java @@ -2,9 +2,11 @@ package com.panda3ds.pandroid.math; public class Vector2 { public float x,y; + public Vector2(){ this(0.0f); } + public Vector2(float value){ this(value,value); } @@ -17,6 +19,7 @@ public class Vector2 { public float distanceTo(Vector2 vec){ return distance(x,y,vec.x, vec.y); } + public static float distance(float x, float y, float x2, float y2){ return (float) Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java index c8ba68cd..2e706530 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java @@ -18,6 +18,9 @@ public class Constants { public static final int INPUT_KEY_START = 1 << 3; public static final int INPUT_KEY_SELECT = 1 << 2; + public static final int N3DS_WIDTH = 400; + public static final int N3DS_HEIGHT = 240; + public static final String EXTRA_PATH = "path"; public static final String LOG_TAG = "Alber"; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java index 4adce575..b6be4df2 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java @@ -10,6 +10,7 @@ import android.opengl.GLSurfaceView; import android.util.Log; import com.panda3ds.pandroid.AlberDriver; +import com.panda3ds.pandroid.utils.Constants; import java.util.ArrayList; @@ -69,43 +70,41 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer { AlberDriver.RunFrame(screenFbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, screenFbo); + if (screenWidth > screenHeight) { - int topDisplayWidth = (int) ((screenHeight / 240.0) * 400); + int topDisplayWidth = (int)((screenHeight / (float)Constants.N3DS_HEIGHT) * Constants.N3DS_WIDTH); int topDisplayHeight = screenHeight; - if (topDisplayWidth > (screenWidth*0.7)){ - topDisplayWidth = (int) (screenWidth * 0.7); - topDisplayHeight = (int) ((topDisplayWidth/400.0)*240); + if (topDisplayWidth > screenWidth * 0.7){ + topDisplayWidth = (int)(screenWidth * 0.7); + topDisplayHeight = (int)((topDisplayWidth / (float)Constants.N3DS_WIDTH) * Constants.N3DS_HEIGHT); } - int bottomDisplayHeight = (int) (((screenWidth-topDisplayWidth)/320)*240); + int bottomDisplayHeight = (int)(((screenWidth - topDisplayWidth) / 320) * Constants.N3DS_HEIGHT); + int topDisplayY = screenHeight - topDisplayHeight; + int bottomDisplayY = screenHeight - bottomDisplayHeight; - int topDisplayY = screenHeight-topDisplayHeight; - int bottomDisplayY = screenHeight-bottomDisplayHeight; - - glBlitFramebuffer(0, 240, - 400, 480, + glBlitFramebuffer(0, Constants.N3DS_HEIGHT, + Constants.N3DS_WIDTH, Constants.N3DS_HEIGHT * 2, 0, topDisplayY, topDisplayWidth,topDisplayY+topDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); glBlitFramebuffer( 40, 0, - 360, 240, + 360, Constants.N3DS_HEIGHT, topDisplayWidth, bottomDisplayY, screenWidth,bottomDisplayY+bottomDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); } else { - int h = (int) ((screenWidth / 400.0) * 480); - glBlitFramebuffer(0, 0, 400, 480, 0, screenHeight - h, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); + int h = (int)((screenWidth / (float)Constants.N3DS_WIDTH) * Constants.N3DS_HEIGHT * 2); + glBlitFramebuffer(0, 0, Constants.N3DS_WIDTH, Constants.N3DS_HEIGHT * 2, 0, screenHeight - h, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); } } } public void onSurfaceChanged(GL10 unused, int width, int height) { - glViewport(0, 0, width, height); screenWidth = width; screenHeight = height; - glDisable(GL_SCISSOR_TEST); } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java index 35805657..3b5694ed 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java @@ -13,8 +13,4 @@ public class PandaGlSurfaceView extends GLSurfaceView { renderer = new PandaGlRenderer(romPath); setRenderer(renderer); } - - public PandaGlRenderer getRenderer() { - return renderer; - } } \ No newline at end of file From 9aded6e55611cc1d950156c7c4262726465a28ec Mon Sep 17 00:00:00 2001 From: offtkp Date: Tue, 28 Nov 2023 18:45:00 +0200 Subject: [PATCH 07/21] Permissions for older phones --- src/jni_driver.cpp | 2 +- src/pandroid/app/src/main/AndroidManifest.xml | 3 +++ .../main/java/com/panda3ds/pandroid/app/MainActivity.java | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp index 422096d8..6d3bd104 100644 --- a/src/jni_driver.cpp +++ b/src/jni_driver.cpp @@ -49,8 +49,8 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_panda3ds_pandroid_AlberDriver_Has extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_LoadRom(JNIEnv* env, jobject obj, jstring path) { const char* pathStr = env->GetStringUTFChars(path, nullptr); - __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "Loading ROM %s", pathStr); romLoaded = emulator->loadROM(pathStr); + __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "Loading ROM %s, result: %d", pathStr, (int)romLoaded); env->ReleaseStringUTFChars(path, pathStr); } diff --git a/src/pandroid/app/src/main/AndroidManifest.xml b/src/pandroid/app/src/main/AndroidManifest.xml index 01931edc..978edcc5 100644 --- a/src/pandroid/app/src/main/AndroidManifest.xml +++ b/src/pandroid/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + Date: Tue, 28 Nov 2023 14:54:10 -0400 Subject: [PATCH 08/21] TouchScreen input (#6) --- .../panda3ds/pandroid/app/GameActivity.java | 20 ++- .../com/panda3ds/pandroid/math/Vector2.java | 14 +- .../pandroid/view/PandaGlRenderer.java | 78 +++++---- .../pandroid/view/PandaGlSurfaceView.java | 36 +++- .../pandroid/view/PandaLayoutController.java | 2 + .../view/controller/ControllerLayout.java | 14 +- .../view/controller/ControllerNode.java | 4 + .../controller/nodes/TouchScreenNodeImpl.java | 39 +++++ .../view/renderer/ConsoleRenderer.java | 9 + .../view/renderer/layout/ConsoleLayout.java | 15 ++ .../renderer/layout/DefaultScreenLayout.java | 81 +++++++++ .../app/src/main/res/layout/game_activity.xml | 161 +++++++++--------- .../app/src/main/res/values/values.xml | 4 + 13 files changed, 349 insertions(+), 128 deletions(-) create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java create mode 100644 src/pandroid/app/src/main/res/values/values.xml diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index 5c234423..53fb1805 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -2,24 +2,20 @@ package com.panda3ds.pandroid.app; import android.content.Intent; import android.os.Bundle; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; +import android.os.Handler; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.widget.CheckBox; -import android.widget.CompoundButton; import android.widget.FrameLayout; import android.widget.Toast; import androidx.annotation.Nullable; -import com.panda3ds.pandroid.AlberDriver; import com.panda3ds.pandroid.R; import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.view.PandaGlSurfaceView; import com.panda3ds.pandroid.view.PandaLayoutController; -import com.panda3ds.pandroid.view.controller.ControllerLayout; public class GameActivity extends BaseActivity { private PandaGlSurfaceView pandaSurface; @@ -46,11 +42,21 @@ public class GameActivity extends BaseActivity { .addView(pandaSurface, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); controllerLayout = findViewById(R.id.controller_layout); + controllerLayout.initialize(); ((CheckBox)findViewById(R.id.hide_screen_controller)) .setOnCheckedChangeListener((buttonView, isChecked) -> { - controllerLayout.setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE); + findViewById(R.id.overlay_controller) + .setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE); }); + + } + + @Override + protected void onResume() { + super.onResume(); + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java index 9c5b45b7..541d45e1 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java @@ -2,13 +2,8 @@ package com.panda3ds.pandroid.math; public class Vector2 { public float x,y; - - public Vector2(){ - this(0.0f); - } - - public Vector2(float value){ - this(value,value); + public Vector2(Vector2 value){ + this(value.x,value.y); } public Vector2(float x, float y){ @@ -23,4 +18,9 @@ public class Vector2 { public static float distance(float x, float y, float x2, float y2){ return (float) Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); } + + public void set(float x, float y) { + this.x = x; + this.y = y; + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java index b6be4df2..e6adbd9f 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java @@ -6,17 +6,19 @@ import javax.microedition.khronos.opengles.GL10; import static android.opengl.GLES32.*; import android.content.res.Resources; +import android.graphics.Rect; import android.opengl.GLSurfaceView; import android.util.Log; import com.panda3ds.pandroid.AlberDriver; -import com.panda3ds.pandroid.utils.Constants; +import com.panda3ds.pandroid.view.renderer.layout.ConsoleLayout; +import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; +import com.panda3ds.pandroid.view.renderer.layout.DefaultScreenLayout; -import java.util.ArrayList; - -public class PandaGlRenderer implements GLSurfaceView.Renderer { +public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer { private final String romPath; + private ConsoleLayout displayLayout; private int screenWidth, screenHeight; private int screenTexture; public int screenFbo; @@ -24,6 +26,10 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer { PandaGlRenderer(String romPath) { super(); this.romPath = romPath; + + screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; + screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; + setLayout(new DefaultScreenLayout()); } @Override @@ -40,8 +46,6 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer { public void onSurfaceCreated(GL10 unused, EGLConfig config) { Log.i("pandroid", glGetString(GL_EXTENSIONS)); Log.w("pandroid", glGetString(GL_VERSION)); - screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; - screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -71,40 +75,48 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, screenFbo); - if (screenWidth > screenHeight) { - int topDisplayWidth = (int)((screenHeight / (float)Constants.N3DS_HEIGHT) * Constants.N3DS_WIDTH); - int topDisplayHeight = screenHeight; + Rect topScreen = displayLayout.getTopDisplayBounds(); + Rect bottomScreen = displayLayout.getBottomDisplayBounds(); - if (topDisplayWidth > screenWidth * 0.7){ - topDisplayWidth = (int)(screenWidth * 0.7); - topDisplayHeight = (int)((topDisplayWidth / (float)Constants.N3DS_WIDTH) * Constants.N3DS_HEIGHT); - } + glBlitFramebuffer( + 0, 480, + 400, 240, + topScreen.left, screenHeight - topScreen.top, + topScreen.right, screenHeight - topScreen.bottom, + GL_COLOR_BUFFER_BIT, GL_LINEAR); - int bottomDisplayHeight = (int)(((screenWidth - topDisplayWidth) / 320) * Constants.N3DS_HEIGHT); - int topDisplayY = screenHeight - topDisplayHeight; - int bottomDisplayY = screenHeight - bottomDisplayHeight; - - glBlitFramebuffer(0, Constants.N3DS_HEIGHT, - Constants.N3DS_WIDTH, Constants.N3DS_HEIGHT * 2, - 0, topDisplayY, - topDisplayWidth,topDisplayY+topDisplayHeight, - GL_COLOR_BUFFER_BIT, GL_LINEAR); - - glBlitFramebuffer( - 40, 0, - 360, Constants.N3DS_HEIGHT, - topDisplayWidth, bottomDisplayY, - screenWidth,bottomDisplayY+bottomDisplayHeight, - GL_COLOR_BUFFER_BIT, GL_LINEAR); - } else { - int h = (int)((screenWidth / (float)Constants.N3DS_WIDTH) * Constants.N3DS_HEIGHT * 2); - glBlitFramebuffer(0, 0, Constants.N3DS_WIDTH, Constants.N3DS_HEIGHT * 2, 0, screenHeight - h, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); - } + glBlitFramebuffer( + 40, 240, + 360, 0, + bottomScreen.left, screenHeight - bottomScreen.top, + bottomScreen.right, screenHeight - bottomScreen.bottom, + GL_COLOR_BUFFER_BIT, GL_LINEAR); } } public void onSurfaceChanged(GL10 unused, int width, int height) { screenWidth = width; screenHeight = height; + glDisable(GL_SCISSOR_TEST); + + displayLayout.update(screenWidth, screenHeight); + } + + @Override + public void setLayout(ConsoleLayout layout) { + displayLayout = layout; + displayLayout.setTopDisplaySourceSize(400, 240); + displayLayout.setBottomDisplaySourceSize(320, 240); + displayLayout.update(screenWidth, screenHeight); + } + + @Override + public ConsoleLayout getLayout() { + return displayLayout; + } + + @Override + public String getBackendName() { + return "OpenGL"; } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java index 3b5694ed..9f280393 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java @@ -1,10 +1,22 @@ package com.panda3ds.pandroid.view; import android.content.Context; +import android.graphics.Canvas; import android.opengl.GLSurfaceView; +import android.util.Log; -public class PandaGlSurfaceView extends GLSurfaceView { +import androidx.annotation.NonNull; + +import com.panda3ds.pandroid.math.Vector2; +import com.panda3ds.pandroid.utils.Constants; +import com.panda3ds.pandroid.view.controller.TouchEvent; +import com.panda3ds.pandroid.view.controller.nodes.TouchScreenNodeImpl; +import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; + +public class PandaGlSurfaceView extends GLSurfaceView implements TouchScreenNodeImpl { final PandaGlRenderer renderer; + private int size_width; + private int size_height; public PandaGlSurfaceView(Context context, String romPath) { super(context); @@ -13,4 +25,26 @@ public class PandaGlSurfaceView extends GLSurfaceView { renderer = new PandaGlRenderer(romPath); setRenderer(renderer); } + + public ConsoleRenderer getRenderer() { + return renderer; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + size_width = getMeasuredWidth(); + size_height = getMeasuredHeight(); + } + + @NonNull + @Override + public Vector2 getSize() { + return new Vector2(size_width, size_height); + } + + @Override + public void onTouch(TouchEvent event) { + onTouchScreenPress(renderer, event); + } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java index 63f328da..e7d9438f 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java @@ -58,5 +58,7 @@ public class PandaLayoutController extends ControllerLayout { .setJoystickListener((joystick, axisX, axisY) -> { AlberDriver.SetCirclepadAxis((int)(axisX*0x9C), (int)(axisY*0x9C)*-1); }); + + refreshChildren(); } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java index 97c8eb12..1ef93c89 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java @@ -2,14 +2,18 @@ package com.panda3ds.pandroid.view.controller; import android.content.Context; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; import com.panda3ds.pandroid.math.Vector2; +import com.panda3ds.pandroid.utils.Constants; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; public class ControllerLayout extends RelativeLayout { @@ -34,8 +38,14 @@ public class ControllerLayout extends RelativeLayout { } public void refreshChildren(){ + ArrayList nodes = new ArrayList<>(); + populateNodesArray(this, nodes); + + //Need Reverse: First view is in back and last view is in front for respect android View hierarchy + Collections.reverse(nodes); + controllerNodes.clear(); - populateNodesArray(this, controllerNodes); + controllerNodes.addAll(nodes); } private void populateNodesArray(ViewGroup group, ArrayList list){ @@ -89,7 +99,7 @@ public class ControllerLayout extends RelativeLayout { float cx = (pos.x - globalPosition[0]); float cy = (pos.y - globalPosition[1]); - if( x > cx && x < cx+size.x && y > cy && y < cy+size.y){ + if(item.isVisible() && x > cx && x < cx+size.x && y > cy && y < cy+size.y){ node = item; break; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java index 8b01fa97..a29d08a4 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java @@ -18,6 +18,10 @@ public interface ControllerNode { return new Vector2(position[0], position[1]); } + default boolean isVisible(){ + return ((View)this).isShown(); + } + @NonNull Vector2 getSize(); void onTouch(TouchEvent event); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java new file mode 100644 index 00000000..85d1ddd6 --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java @@ -0,0 +1,39 @@ +package com.panda3ds.pandroid.view.controller.nodes; + +import android.graphics.Rect; +import android.util.Log; +import android.view.View; + +import com.panda3ds.pandroid.AlberDriver; +import com.panda3ds.pandroid.R; +import com.panda3ds.pandroid.utils.Constants; +import com.panda3ds.pandroid.view.controller.ControllerNode; +import com.panda3ds.pandroid.view.controller.TouchEvent; +import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; + +public interface TouchScreenNodeImpl extends ControllerNode { + default void onTouchScreenPress(ConsoleRenderer renderer, TouchEvent event){ + + View me = (View) this; + boolean hasDownEvent = me.getTag(R.id.TagEventHasDown) != null && (boolean) me.getTag(R.id.TagEventHasDown); + + Rect bounds = renderer.getLayout().getBottomDisplayBounds();; + + if (event.getX() >= bounds.left && event.getY() >= bounds.top && event.getX() <= bounds.right && event.getY() <= bounds.bottom){ + int x = (int) (event.getX() - bounds.left); + int y = (int) (event.getY() - bounds.top); + + x = Math.round((x/(float)bounds.width())*320); + y = Math.round((y/(float)bounds.height())*240); + + AlberDriver.TouchScreenDown(x,y); + + me.setTag(R.id.TagEventHasDown, true); + } + + if (hasDownEvent && event.getAction() == TouchEvent.ACTION_UP){ + AlberDriver.TouchScreenUp(); + me.setTag(R.id.TagEventHasDown, false); + } + } +} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java new file mode 100644 index 00000000..13ad4d39 --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java @@ -0,0 +1,9 @@ +package com.panda3ds.pandroid.view.renderer; + +import com.panda3ds.pandroid.view.renderer.layout.ConsoleLayout; + +public interface ConsoleRenderer { + void setLayout(ConsoleLayout layout); + ConsoleLayout getLayout(); + String getBackendName(); +} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java new file mode 100644 index 00000000..781f0abd --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java @@ -0,0 +1,15 @@ +package com.panda3ds.pandroid.view.renderer.layout; + +import android.graphics.Rect; + +import com.panda3ds.pandroid.math.Vector2; + +public interface ConsoleLayout { + void update(int screenWidth, int screenHeight); + + void setBottomDisplaySourceSize(int width, int height); + void setTopDisplaySourceSize(int width, int height); + + Rect getBottomDisplayBounds(); + Rect getTopDisplayBounds(); +} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java new file mode 100644 index 00000000..a54db8f7 --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java @@ -0,0 +1,81 @@ +package com.panda3ds.pandroid.view.renderer.layout; + +import android.graphics.Rect; +import android.util.Size; + +import com.panda3ds.pandroid.math.Vector2; + +public class DefaultScreenLayout implements ConsoleLayout { + private final Rect topDisplay = new Rect(); + private final Rect bottomDisplay = new Rect(); + + private final Vector2 screenSize = new Vector2(1.0F, 1.0F); + private final Vector2 topSourceSize = new Vector2(1.0F, 1.0F); + private final Vector2 bottomSourceSize = new Vector2(1.0F, 1.0F); + + @Override + public void update(int screenWidth, int screenHeight) { + screenSize.set(screenWidth, screenHeight); + updateBounds(); + } + + @Override + public void setBottomDisplaySourceSize(int width, int height) { + bottomSourceSize.set(width,height); + updateBounds(); + } + @Override + public void setTopDisplaySourceSize(int width, int height) { + topSourceSize.set(width,height); + updateBounds(); + } + + private void updateBounds(){ + int screenWidth = (int) screenSize.x; + int screenHeight = (int) screenSize.y; + + if (screenWidth > screenHeight){ + + int topDisplayWidth = (int) ((screenHeight / topSourceSize.y) * topSourceSize.x); + int topDisplayHeight = screenHeight; + + if (topDisplayWidth > (screenWidth*0.7)){ + topDisplayWidth = (int) (screenWidth * 0.7); + topDisplayHeight = (int) ((topDisplayWidth/topSourceSize.x)* topSourceSize.y); + } + + int bottomDisplayHeight = (int) (((screenWidth-topDisplayWidth)/ bottomSourceSize.x)* bottomSourceSize.y); + + + topDisplay.set(0, 0, topDisplayWidth, topDisplayHeight); + bottomDisplay.set(topDisplayWidth, 0, topDisplayWidth+(screenWidth-topDisplayWidth), bottomDisplayHeight); + } else { + int topScreenHeight = (int) ((screenWidth/ topSourceSize.x) * topSourceSize.y); + topDisplay.set(0,0,screenWidth,topScreenHeight); + + int bottomDisplayHeight = (int)((screenWidth/ bottomSourceSize.x) * bottomSourceSize.y); + int bottomDisplayWidth = screenWidth; + int bottomDisplayX = 0; + + if (topScreenHeight + bottomDisplayHeight > screenHeight){ + bottomDisplayHeight = (screenHeight-topScreenHeight); + bottomDisplayWidth = (int) ((bottomDisplayHeight/ bottomSourceSize.y)*bottomSourceSize.x); + bottomDisplayX = (screenWidth-bottomDisplayX)/2; + } + + topDisplay.set(0,0, screenWidth,topScreenHeight); + bottomDisplay.set(bottomDisplayX, topScreenHeight, bottomDisplayX+bottomDisplayWidth,topScreenHeight+bottomDisplayHeight); + } + } + + + @Override + public Rect getBottomDisplayBounds() { + return bottomDisplay; + } + + @Override + public Rect getTopDisplayBounds() { + return topDisplay; + } +} diff --git a/src/pandroid/app/src/main/res/layout/game_activity.xml b/src/pandroid/app/src/main/res/layout/game_activity.xml index 64f067b2..6f6f65d7 100644 --- a/src/pandroid/app/src/main/res/layout/game_activity.xml +++ b/src/pandroid/app/src/main/res/layout/game_activity.xml @@ -4,105 +4,110 @@ android:layout_height="match_parent" android:background="#000"> - - - + android:layout_height="match_parent"/> - + + + android:layout_height="match_parent" + android:gravity="bottom" + android:padding="20dp"> - - - - - - + android:layout_height="wrap_content"> - - - - - - - - - - - - - + android:layout_height="25dp" + android:layout_gravity="left" + style="@style/ControllerSimpleButton" + android:background="@drawable/simple_card_button_left" + android:text="L"/> + + + + + + + + + + + + + + + + + android:layout_gravity="bottom|center"> - + - + - + - + + + + diff --git a/src/pandroid/app/src/main/res/values/values.xml b/src/pandroid/app/src/main/res/values/values.xml new file mode 100644 index 00000000..9a4071c7 --- /dev/null +++ b/src/pandroid/app/src/main/res/values/values.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From a40e74a15d08798ae045bae2b64324949b8e1ac3 Mon Sep 17 00:00:00 2001 From: offtkp Date: Tue, 28 Nov 2023 21:11:58 +0200 Subject: [PATCH 09/21] Remove magic numbers --- .../com/panda3ds/pandroid/utils/Constants.java | 3 ++- .../panda3ds/pandroid/view/PandaGlRenderer.java | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java index 2e706530..14d5c398 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java @@ -19,7 +19,8 @@ public class Constants { public static final int INPUT_KEY_SELECT = 1 << 2; public static final int N3DS_WIDTH = 400; - public static final int N3DS_HEIGHT = 240; + public static final int N3DS_HALF_HEIGHT = 240; + public static final int N3DS_FULL_HEIGHT = 480; public static final String EXTRA_PATH = "path"; public static final String LOG_TAG = "Alber"; diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java index e6adbd9f..0e1826d1 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java @@ -79,15 +79,16 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer Rect bottomScreen = displayLayout.getBottomDisplayBounds(); glBlitFramebuffer( - 0, 480, - 400, 240, + 0, Constants.N3DS_FULL_HEIGHT, + Constants.N3DS_WIDTH, Constants.N3DS_HALF_HEIGHT, topScreen.left, screenHeight - topScreen.top, topScreen.right, screenHeight - topScreen.bottom, GL_COLOR_BUFFER_BIT, GL_LINEAR); + // Remove the black bars on the bottom screen glBlitFramebuffer( - 40, 240, - 360, 0, + 40, Constants.N3DS_HALF_HEIGHT, + Constants.N3DS_WIDTH - 40, 0, bottomScreen.left, screenHeight - bottomScreen.top, bottomScreen.right, screenHeight - bottomScreen.bottom, GL_COLOR_BUFFER_BIT, GL_LINEAR); @@ -97,7 +98,6 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer public void onSurfaceChanged(GL10 unused, int width, int height) { screenWidth = width; screenHeight = height; - glDisable(GL_SCISSOR_TEST); displayLayout.update(screenWidth, screenHeight); } @@ -105,8 +105,8 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer @Override public void setLayout(ConsoleLayout layout) { displayLayout = layout; - displayLayout.setTopDisplaySourceSize(400, 240); - displayLayout.setBottomDisplaySourceSize(320, 240); + displayLayout.setTopDisplaySourceSize(Constants.N3DS_WIDTH, Constants.N3DS_HALF_HEIGHT); + displayLayout.setBottomDisplaySourceSize(Constants.N3DS_WIDTH - 40 - 40, Constants.N3DS_HALF_HEIGHT); displayLayout.update(screenWidth, screenHeight); } From ed0864d24f2f4675275f72beb30a768a1d58c3fb Mon Sep 17 00:00:00 2001 From: offtkp Date: Tue, 28 Nov 2023 21:41:57 +0200 Subject: [PATCH 10/21] Run clang-format on .java files --- src/pandroid/app/.gitignore | 1 - src/pandroid/app/build.gradle.kts | 4 - .../com/panda3ds/pandroid/AlberDriver.java | 29 +-- .../panda3ds/pandroid/app/BaseActivity.java | 3 +- .../panda3ds/pandroid/app/GameActivity.java | 62 +++-- .../panda3ds/pandroid/app/MainActivity.java | 80 +++---- .../com/panda3ds/pandroid/math/Vector2.java | 30 +-- .../panda3ds/pandroid/utils/Constants.java | 35 ++- .../panda3ds/pandroid/utils/PathUtils.java | 156 ++++++------- .../pandroid/view/PandaGlRenderer.java | 176 +++++++------- .../pandroid/view/PandaGlSurfaceView.java | 56 +++-- .../pandroid/view/PandaLayoutController.java | 68 +++--- .../view/controller/ControllerLayout.java | 218 +++++++++--------- .../view/controller/ControllerNode.java | 26 +-- .../pandroid/view/controller/TouchEvent.java | 32 ++- .../listeners/ButtonStateListener.java | 2 +- .../listeners/JoystickListener.java | 2 +- .../controller/nodes/BasicControllerNode.java | 14 +- .../view/controller/nodes/Button.java | 86 ++++--- .../view/controller/nodes/Joystick.java | 155 ++++++------- .../controller/nodes/TouchScreenNodeImpl.java | 37 ++- .../view/renderer/ConsoleRenderer.java | 6 +- .../view/renderer/layout/ConsoleLayout.java | 11 +- .../renderer/layout/DefaultScreenLayout.java | 116 +++++----- 24 files changed, 634 insertions(+), 771 deletions(-) delete mode 100644 src/pandroid/app/.gitignore diff --git a/src/pandroid/app/.gitignore b/src/pandroid/app/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/src/pandroid/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/src/pandroid/app/build.gradle.kts b/src/pandroid/app/build.gradle.kts index ff8debcb..276eb552 100644 --- a/src/pandroid/app/build.gradle.kts +++ b/src/pandroid/app/build.gradle.kts @@ -36,11 +36,7 @@ android { } dependencies { - implementation("androidx.appcompat:appcompat:1.6.1") implementation("com.google.android.material:material:1.8.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") - testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java index 92d276a2..81bf29a5 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java @@ -1,24 +1,19 @@ package com.panda3ds.pandroid; public class AlberDriver { + AlberDriver() { super(); } - AlberDriver() { - super(); - } + public static native void Initialize(); + public static native void RunFrame(int fbo); + public static native boolean HasRomLoaded(); + public static native void LoadRom(String path); + public static native void Finalize(); - public static native void Initialize(); - public static native void RunFrame(int fbo); - public static native boolean HasRomLoaded(); - public static native void LoadRom(String path); - public static native void Finalize(); + public static native void KeyDown(int code); + public static native void KeyUp(int code); + public static native void SetCirclepadAxis(int x, int y); + public static native void TouchScreenUp(); + public static native void TouchScreenDown(int x, int y); - public static native void KeyDown(int code); - public static native void KeyUp(int code); - public static native void SetCirclepadAxis(int x, int y); - public static native void TouchScreenUp(); - public static native void TouchScreenDown(int x, int y); - - static { - System.loadLibrary("Alber"); - } + static { System.loadLibrary("Alber"); } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/BaseActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/BaseActivity.java index 597d664b..72926b07 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/BaseActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/BaseActivity.java @@ -2,5 +2,4 @@ package com.panda3ds.pandroid.app; import androidx.appcompat.app.AppCompatActivity; -public class BaseActivity extends AppCompatActivity { -} +public class BaseActivity extends AppCompatActivity {} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index 53fb1805..e196d0d1 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -9,54 +9,48 @@ import android.view.WindowManager; import android.widget.CheckBox; import android.widget.FrameLayout; import android.widget.Toast; - import androidx.annotation.Nullable; - import com.panda3ds.pandroid.R; import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.view.PandaGlSurfaceView; import com.panda3ds.pandroid.view.PandaLayoutController; public class GameActivity extends BaseActivity { - private PandaGlSurfaceView pandaSurface; - private PandaLayoutController controllerLayout; + private PandaGlSurfaceView pandaSurface; + private PandaLayoutController controllerLayout; - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - Intent intent = getIntent(); - if(!intent.hasExtra(Constants.EXTRA_PATH)){ + Intent intent = getIntent(); + if (!intent.hasExtra(Constants.EXTRA_PATH)) { + setContentView(new FrameLayout(this)); + Toast.makeText(this, "Invalid rom path!", Toast.LENGTH_LONG).show(); + finish(); + return; + } - setContentView(new FrameLayout(this)); - Toast.makeText(this, "Invalid rom path!", Toast.LENGTH_LONG).show(); - finish(); - return; - } + pandaSurface = new PandaGlSurfaceView(this, intent.getStringExtra(Constants.EXTRA_PATH)); - pandaSurface = new PandaGlSurfaceView(this, intent.getStringExtra(Constants.EXTRA_PATH)); + setContentView(R.layout.game_activity); - setContentView(R.layout.game_activity); + ((FrameLayout) findViewById(R.id.panda_gl_frame)) + .addView(pandaSurface, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - ((FrameLayout)findViewById(R.id.panda_gl_frame)) - .addView(pandaSurface, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + controllerLayout = findViewById(R.id.controller_layout); - controllerLayout = findViewById(R.id.controller_layout); + controllerLayout.initialize(); - controllerLayout.initialize(); + ((CheckBox) findViewById(R.id.hide_screen_controller)).setOnCheckedChangeListener((buttonView, isChecked) -> { + findViewById(R.id.overlay_controller).setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE); + }); + } - ((CheckBox)findViewById(R.id.hide_screen_controller)) - .setOnCheckedChangeListener((buttonView, isChecked) -> { - findViewById(R.id.overlay_controller) - .setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE); - }); - - } - - @Override - protected void onResume() { - super.onResume(); - getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } + @Override + protected void onResume() { + super.onResume(); + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java index ef0ac63f..181cfb4e 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java @@ -1,5 +1,7 @@ package com.panda3ds.pandroid.app; +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION; import android.content.Intent; @@ -7,58 +9,50 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.widget.Toast; - import androidx.appcompat.app.AppCompatActivity; - -import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; -import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import androidx.core.app.ActivityCompat; - -import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.R; +import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.utils.PathUtils; public class MainActivity extends BaseActivity { - private static final int PICK_3DS_ROM = 2; - private static final int PERMISSION_REQUEST_CODE = 3; + private static final int PICK_3DS_ROM = 2; + private static final int PERMISSION_REQUEST_CODE = 3; - private void openFile() { - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - startActivityForResult(intent, PICK_3DS_ROM); - } + private void openFile() { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + startActivityForResult(intent, PICK_3DS_ROM); + } - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - if (!Environment.isExternalStorageManager()) { - Intent intent = new Intent(ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); - startActivity(intent); - } - } else { - ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE); - ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE); - } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (!Environment.isExternalStorageManager()) { + Intent intent = new Intent(ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); + startActivity(intent); + } + } else { + ActivityCompat.requestPermissions(this, new String[] {READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE); + ActivityCompat.requestPermissions(this, new String[] {WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE); + } - setContentView(R.layout.activity_main); + setContentView(R.layout.activity_main); - findViewById(R.id.load_rom).setOnClickListener(v->{ - openFile(); - }); - } + findViewById(R.id.load_rom).setOnClickListener(v -> { openFile(); }); + } - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == PICK_3DS_ROM) { - if (resultCode == RESULT_OK) { - String path = PathUtils.getPath(getApplicationContext(), data.getData()); - Toast.makeText(getApplicationContext(), "pandroid opening " + path, Toast.LENGTH_LONG).show(); - startActivity(new Intent(this, GameActivity.class) - .putExtra(Constants.EXTRA_PATH, path)); - } - super.onActivityResult(requestCode, resultCode, data); - } - } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == PICK_3DS_ROM) { + if (resultCode == RESULT_OK) { + String path = PathUtils.getPath(getApplicationContext(), data.getData()); + Toast.makeText(getApplicationContext(), "pandroid opening " + path, Toast.LENGTH_LONG).show(); + startActivity(new Intent(this, GameActivity.class).putExtra(Constants.EXTRA_PATH, path)); + } + super.onActivityResult(requestCode, resultCode, data); + } + } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java index 541d45e1..4208b610 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java @@ -1,26 +1,20 @@ package com.panda3ds.pandroid.math; public class Vector2 { - public float x,y; - public Vector2(Vector2 value){ - this(value.x,value.y); - } + public float x, y; + public Vector2(Vector2 value) { this(value.x, value.y); } - public Vector2(float x, float y){ - this.x = x; - this.y = y; - } + public Vector2(float x, float y) { + this.x = x; + this.y = y; + } - public float distanceTo(Vector2 vec){ - return distance(x,y,vec.x, vec.y); - } + public float distanceTo(Vector2 vec) { return distance(x, y, vec.x, vec.y); } - public static float distance(float x, float y, float x2, float y2){ - return (float) Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); - } + public static float distance(float x, float y, float x2, float y2) { return (float) Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); } - public void set(float x, float y) { - this.x = x; - this.y = y; - } + public void set(float x, float y) { + this.x = x; + this.y = y; + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java index 14d5c398..bc389987 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java @@ -1,27 +1,26 @@ package com.panda3ds.pandroid.utils; public class Constants { + public static final int INPUT_KEY_UP = 1 << 6; + public static final int INPUT_KEY_DOWN = 1 << 7; + public static final int INPUT_KEY_LEFT = 1 << 5; + public static final int INPUT_KEY_RIGHT = 1 << 4; - public static final int INPUT_KEY_UP = 1 << 6; - public static final int INPUT_KEY_DOWN = 1 << 7; - public static final int INPUT_KEY_LEFT = 1 << 5; - public static final int INPUT_KEY_RIGHT = 1 << 4; + public static final int INPUT_KEY_A = 1 << 0; + public static final int INPUT_KEY_B = 1 << 1; + public static final int INPUT_KEY_X = 1 << 10; + public static final int INPUT_KEY_Y = 1 << 11; - public static final int INPUT_KEY_A = 1 << 0; - public static final int INPUT_KEY_B = 1 << 1; - public static final int INPUT_KEY_X = 1 << 10; - public static final int INPUT_KEY_Y = 1 << 11; + public static final int INPUT_KEY_R = 1 << 8; + public static final int INPUT_KEY_L = 1 << 9; - public static final int INPUT_KEY_R = 1 << 8; - public static final int INPUT_KEY_L = 1 << 9; + public static final int INPUT_KEY_START = 1 << 3; + public static final int INPUT_KEY_SELECT = 1 << 2; - public static final int INPUT_KEY_START = 1 << 3; - public static final int INPUT_KEY_SELECT = 1 << 2; + public static final int N3DS_WIDTH = 400; + public static final int N3DS_HALF_HEIGHT = 240; + public static final int N3DS_FULL_HEIGHT = 480; - public static final int N3DS_WIDTH = 400; - public static final int N3DS_HALF_HEIGHT = 240; - public static final int N3DS_FULL_HEIGHT = 480; - - public static final String EXTRA_PATH = "path"; - public static final String LOG_TAG = "Alber"; + public static final String EXTRA_PATH = "path"; + public static final String LOG_TAG = "Alber"; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java index 0a24603c..ccf655bf 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java @@ -10,116 +10,92 @@ import android.provider.DocumentsContract; import android.provider.MediaStore; public class PathUtils { + public static String getPath(final Context context, final Uri uri) { + // DocumentProvider + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) { + if (isExternalStorageDocument(uri)) { // ExternalStorageProvider + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + String storageDefinition; - public static String getPath(final Context context, final Uri uri) { + if ("primary".equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; - // DocumentProvider - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) { + } else { + if (Environment.isExternalStorageRemovable()) { + storageDefinition = "EXTERNAL_STORAGE"; - if (isExternalStorageDocument(uri)) {// ExternalStorageProvider - final String docId = DocumentsContract.getDocumentId(uri); - final String[] split = docId.split(":"); - final String type = split[0]; - String storageDefinition; + } else { + storageDefinition = "SECONDARY_STORAGE"; + } + return System.getenv(storageDefinition) + "/" + split[1]; + } - if("primary".equalsIgnoreCase(type)){ + } else if (isDownloadsDocument(uri)) { // DownloadsProvider - return Environment.getExternalStorageDirectory() + "/" + split[1]; + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - } else { + return getDataColumn(context, contentUri, null, null); - if(Environment.isExternalStorageRemovable()){ - storageDefinition = "EXTERNAL_STORAGE"; + } else if (isMediaDocument(uri)) { // MediaProvider + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; - } else{ - storageDefinition = "SECONDARY_STORAGE"; - } + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } - return System.getenv(storageDefinition) + "/" + split[1]; - } - - } else if (isDownloadsDocument(uri)) {// DownloadsProvider + final String selection = "_id=?"; + final String[] selectionArgs = new String[] {split[1]}; - final String id = DocumentsContract.getDocumentId(uri); - final Uri contentUri = ContentUris.withAppendedId( - Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + return getDataColumn(context, contentUri, selection, selectionArgs); + } - return getDataColumn(context, contentUri, null, null); + } else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general) - } else if (isMediaDocument(uri)) {// MediaProvider - final String docId = DocumentsContract.getDocumentId(uri); - final String[] split = docId.split(":"); - final String type = split[0]; + // Return the remote address + if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); - Uri contentUri = null; - if ("image".equals(type)) { - contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - } else if ("video".equals(type)) { - contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } else if ("audio".equals(type)) { - contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - } + return getDataColumn(context, uri, null, null); - final String selection = "_id=?"; - final String[] selectionArgs = new String[]{ - split[1] - }; + } else if ("file".equalsIgnoreCase(uri.getScheme())) { // File + return uri.getPath(); + } - return getDataColumn(context, contentUri, selection, selectionArgs); - } + return null; + } - } else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore (and general) + public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + Cursor cursor = null; + final String column = "_data"; + final String[] projection = {column}; - // Return the remote address - if (isGooglePhotosUri(uri)) - return uri.getLastPathSegment(); + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } finally { + if (cursor != null) cursor.close(); + } + return null; + } - return getDataColumn(context, uri, null, null); + public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } - } else if ("file".equalsIgnoreCase(uri.getScheme())) {// File - return uri.getPath(); - } + public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } - return null; - } + public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } - public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { - - Cursor cursor = null; - final String column = "_data"; - final String[] projection = { - column - }; - - try { - cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); - if (cursor != null && cursor.moveToFirst()) { - final int column_index = cursor.getColumnIndexOrThrow(column); - return cursor.getString(column_index); - } - } finally { - if (cursor != null) - cursor.close(); - } - return null; - } - - - public static boolean isExternalStorageDocument(Uri uri) { - return "com.android.externalstorage.documents".equals(uri.getAuthority()); - } - - - public static boolean isDownloadsDocument(Uri uri) { - return "com.android.providers.downloads.documents".equals(uri.getAuthority()); - } - - public static boolean isMediaDocument(Uri uri) { - return "com.android.providers.media.documents".equals(uri.getAuthority()); - } - - public static boolean isGooglePhotosUri(Uri uri) { - return "com.google.android.apps.photos.content".equals(uri.getAuthority()); - } + public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority()); } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java index 0e1826d1..b21e3353 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java @@ -1,122 +1,116 @@ package com.panda3ds.pandroid.view; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - import static android.opengl.GLES32.*; import android.content.res.Resources; import android.graphics.Rect; import android.opengl.GLSurfaceView; import android.util.Log; - import com.panda3ds.pandroid.AlberDriver; -import com.panda3ds.pandroid.view.renderer.layout.ConsoleLayout; +import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; +import com.panda3ds.pandroid.view.renderer.layout.ConsoleLayout; import com.panda3ds.pandroid.view.renderer.layout.DefaultScreenLayout; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer { + private final String romPath; + private ConsoleLayout displayLayout; + private int screenWidth, screenHeight; + private int screenTexture; + public int screenFbo; - private final String romPath; - private ConsoleLayout displayLayout; - private int screenWidth, screenHeight; - private int screenTexture; - public int screenFbo; + PandaGlRenderer(String romPath) { + super(); + this.romPath = romPath; - PandaGlRenderer(String romPath) { - super(); - this.romPath = romPath; + screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; + screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; + setLayout(new DefaultScreenLayout()); + } - screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; - screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; - setLayout(new DefaultScreenLayout()); - } + @Override + protected void finalize() throws Throwable { + if (screenTexture != 0) { + glDeleteTextures(1, new int[] {screenTexture}, 0); + } + if (screenFbo != 0) { + glDeleteFramebuffers(1, new int[] {screenFbo}, 0); + } + super.finalize(); + } - @Override - protected void finalize() throws Throwable { - if (screenTexture != 0) { - glDeleteTextures(1, new int[]{screenTexture}, 0); - } - if (screenFbo != 0) { - glDeleteFramebuffers(1, new int[]{screenFbo}, 0); - } - super.finalize(); - } + public void onSurfaceCreated(GL10 unused, EGLConfig config) { + Log.i("pandroid", glGetString(GL_EXTENSIONS)); + Log.w("pandroid", glGetString(GL_VERSION)); - public void onSurfaceCreated(GL10 unused, EGLConfig config) { - Log.i("pandroid", glGetString(GL_EXTENSIONS)); - Log.w("pandroid", glGetString(GL_VERSION)); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + int[] generateBuffer = new int[1]; + glGenTextures(1, generateBuffer, 0); + screenTexture = generateBuffer[0]; + glBindTexture(GL_TEXTURE_2D, screenTexture); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, screenWidth, screenHeight); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); - int[] generateBuffer = new int[1]; - glGenTextures(1, generateBuffer, 0); - screenTexture = generateBuffer[0]; - glBindTexture(GL_TEXTURE_2D, screenTexture); - glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, screenWidth, screenHeight); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); + glGenFramebuffers(1, generateBuffer, 0); + screenFbo = generateBuffer[0]; + glBindFramebuffer(GL_FRAMEBUFFER, screenFbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - glGenFramebuffers(1, generateBuffer, 0); - screenFbo = generateBuffer[0]; - glBindFramebuffer(GL_FRAMEBUFFER, screenFbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + AlberDriver.Initialize(); + AlberDriver.LoadRom(romPath); + } - AlberDriver.Initialize(); - AlberDriver.LoadRom(romPath); - } + public void onDrawFrame(GL10 unused) { + if (AlberDriver.HasRomLoaded()) { + AlberDriver.RunFrame(screenFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, screenFbo); - public void onDrawFrame(GL10 unused) { - if (AlberDriver.HasRomLoaded()) { - AlberDriver.RunFrame(screenFbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBindFramebuffer(GL_READ_FRAMEBUFFER, screenFbo); + Rect topScreen = displayLayout.getTopDisplayBounds(); + Rect bottomScreen = displayLayout.getBottomDisplayBounds(); - Rect topScreen = displayLayout.getTopDisplayBounds(); - Rect bottomScreen = displayLayout.getBottomDisplayBounds(); + glBlitFramebuffer( + 0, Constants.N3DS_FULL_HEIGHT, Constants.N3DS_WIDTH, Constants.N3DS_HALF_HEIGHT, topScreen.left, screenHeight - topScreen.top, + topScreen.right, screenHeight - topScreen.bottom, GL_COLOR_BUFFER_BIT, GL_LINEAR + ); - glBlitFramebuffer( - 0, Constants.N3DS_FULL_HEIGHT, - Constants.N3DS_WIDTH, Constants.N3DS_HALF_HEIGHT, - topScreen.left, screenHeight - topScreen.top, - topScreen.right, screenHeight - topScreen.bottom, - GL_COLOR_BUFFER_BIT, GL_LINEAR); + // Remove the black bars on the bottom screen + glBlitFramebuffer( + 40, Constants.N3DS_HALF_HEIGHT, Constants.N3DS_WIDTH - 40, 0, bottomScreen.left, screenHeight - bottomScreen.top, bottomScreen.right, + screenHeight - bottomScreen.bottom, GL_COLOR_BUFFER_BIT, GL_LINEAR + ); + } + } - // Remove the black bars on the bottom screen - glBlitFramebuffer( - 40, Constants.N3DS_HALF_HEIGHT, - Constants.N3DS_WIDTH - 40, 0, - bottomScreen.left, screenHeight - bottomScreen.top, - bottomScreen.right, screenHeight - bottomScreen.bottom, - GL_COLOR_BUFFER_BIT, GL_LINEAR); - } - } + public void onSurfaceChanged(GL10 unused, int width, int height) { + screenWidth = width; + screenHeight = height; - public void onSurfaceChanged(GL10 unused, int width, int height) { - screenWidth = width; - screenHeight = height; + displayLayout.update(screenWidth, screenHeight); + } - displayLayout.update(screenWidth, screenHeight); - } + @Override + public void setLayout(ConsoleLayout layout) { + displayLayout = layout; + displayLayout.setTopDisplaySourceSize(Constants.N3DS_WIDTH, Constants.N3DS_HALF_HEIGHT); + displayLayout.setBottomDisplaySourceSize(Constants.N3DS_WIDTH - 40 - 40, Constants.N3DS_HALF_HEIGHT); + displayLayout.update(screenWidth, screenHeight); + } - @Override - public void setLayout(ConsoleLayout layout) { - displayLayout = layout; - displayLayout.setTopDisplaySourceSize(Constants.N3DS_WIDTH, Constants.N3DS_HALF_HEIGHT); - displayLayout.setBottomDisplaySourceSize(Constants.N3DS_WIDTH - 40 - 40, Constants.N3DS_HALF_HEIGHT); - displayLayout.update(screenWidth, screenHeight); - } + @Override + public ConsoleLayout getLayout() { + return displayLayout; + } - @Override - public ConsoleLayout getLayout() { - return displayLayout; - } - - @Override - public String getBackendName() { - return "OpenGL"; - } + @Override + public String getBackendName() { + return "OpenGL"; + } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java index 9f280393..f5a19efe 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java @@ -4,9 +4,7 @@ import android.content.Context; import android.graphics.Canvas; import android.opengl.GLSurfaceView; import android.util.Log; - import androidx.annotation.NonNull; - import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.view.controller.TouchEvent; @@ -14,37 +12,35 @@ import com.panda3ds.pandroid.view.controller.nodes.TouchScreenNodeImpl; import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; public class PandaGlSurfaceView extends GLSurfaceView implements TouchScreenNodeImpl { - final PandaGlRenderer renderer; - private int size_width; - private int size_height; + final PandaGlRenderer renderer; + private int size_width; + private int size_height; - public PandaGlSurfaceView(Context context, String romPath) { - super(context); - setEGLContextClientVersion(3); - setDebugFlags(DEBUG_LOG_GL_CALLS); - renderer = new PandaGlRenderer(romPath); - setRenderer(renderer); - } + public PandaGlSurfaceView(Context context, String romPath) { + super(context); + setEGLContextClientVersion(3); + setDebugFlags(DEBUG_LOG_GL_CALLS); + renderer = new PandaGlRenderer(romPath); + setRenderer(renderer); + } - public ConsoleRenderer getRenderer() { - return renderer; - } + public ConsoleRenderer getRenderer() { return renderer; } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - size_width = getMeasuredWidth(); - size_height = getMeasuredHeight(); - } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + size_width = getMeasuredWidth(); + size_height = getMeasuredHeight(); + } - @NonNull - @Override - public Vector2 getSize() { - return new Vector2(size_width, size_height); - } + @NonNull + @Override + public Vector2 getSize() { + return new Vector2(size_width, size_height); + } - @Override - public void onTouch(TouchEvent event) { - onTouchScreenPress(renderer, event); - } + @Override + public void onTouch(TouchEvent event) { + onTouchScreenPress(renderer, event); + } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java index e7d9438f..543ab840 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java @@ -2,7 +2,6 @@ package com.panda3ds.pandroid.view; import android.content.Context; import android.util.AttributeSet; - import com.panda3ds.pandroid.AlberDriver; import com.panda3ds.pandroid.R; import com.panda3ds.pandroid.utils.Constants; @@ -11,54 +10,41 @@ import com.panda3ds.pandroid.view.controller.nodes.Button; import com.panda3ds.pandroid.view.controller.nodes.Joystick; public class PandaLayoutController extends ControllerLayout { - public PandaLayoutController(Context context) { - super(context); - } + public PandaLayoutController(Context context) { super(context); } - public PandaLayoutController(Context context, AttributeSet attrs) { - super(context, attrs); - } + public PandaLayoutController(Context context, AttributeSet attrs) { super(context, attrs); } - public PandaLayoutController(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } + public PandaLayoutController(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } - public PandaLayoutController(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } + public PandaLayoutController(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } - public void initialize(){ - int[] keyButtonList = { - R.id.button_a, Constants.INPUT_KEY_A, - R.id.button_b, Constants.INPUT_KEY_B, - R.id.button_y, Constants.INPUT_KEY_Y, - R.id.button_x, Constants.INPUT_KEY_X, + public void initialize() { + int[] keyButtonList = {R.id.button_a, Constants.INPUT_KEY_A, R.id.button_b, Constants.INPUT_KEY_B, + R.id.button_y, Constants.INPUT_KEY_Y, R.id.button_x, Constants.INPUT_KEY_X, - R.id.button_left, Constants.INPUT_KEY_LEFT, - R.id.button_right, Constants.INPUT_KEY_RIGHT, - R.id.button_up, Constants.INPUT_KEY_UP, - R.id.button_down, Constants.INPUT_KEY_DOWN, + R.id.button_left, Constants.INPUT_KEY_LEFT, R.id.button_right, Constants.INPUT_KEY_RIGHT, + R.id.button_up, Constants.INPUT_KEY_UP, R.id.button_down, Constants.INPUT_KEY_DOWN, - R.id.button_start, Constants.INPUT_KEY_START, - R.id.button_select, Constants.INPUT_KEY_SELECT, + R.id.button_start, Constants.INPUT_KEY_START, R.id.button_select, Constants.INPUT_KEY_SELECT, - R.id.button_l, Constants.INPUT_KEY_L, - R.id.button_r, Constants.INPUT_KEY_R - }; + R.id.button_l, Constants.INPUT_KEY_L, R.id.button_r, Constants.INPUT_KEY_R}; - for (int i = 0; i < keyButtonList.length; i+=2){ - final int keyCode = keyButtonList[i+1]; - ((Button)findViewById(keyButtonList[i])).setStateListener((btn, pressed)->{ - if (pressed) AlberDriver.KeyDown(keyCode); - else AlberDriver.KeyUp(keyCode); - }); - } + for (int i = 0; i < keyButtonList.length; i += 2) { + final int keyCode = keyButtonList[i + 1]; + ((Button) findViewById(keyButtonList[i])).setStateListener((btn, pressed) -> { + if (pressed) + AlberDriver.KeyDown(keyCode); + else + AlberDriver.KeyUp(keyCode); + }); + } - ((Joystick)findViewById(R.id.left_analog)) - .setJoystickListener((joystick, axisX, axisY) -> { - AlberDriver.SetCirclepadAxis((int)(axisX*0x9C), (int)(axisY*0x9C)*-1); - }); + ((Joystick) findViewById(R.id.left_analog)).setJoystickListener((joystick, axisX, axisY) -> { + AlberDriver.SetCirclepadAxis((int) (axisX * 0x9C), (int) (axisY * 0x9C) * -1); + }); - refreshChildren(); - } + refreshChildren(); + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java index 1ef93c89..137bd312 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java @@ -7,150 +7,140 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; - import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.utils.Constants; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; public class ControllerLayout extends RelativeLayout { + private final HashMap activeTouchEvents = new HashMap<>(); + private final ArrayList controllerNodes = new ArrayList<>(); - private final HashMap activeTouchEvents = new HashMap<>(); - private final ArrayList controllerNodes = new ArrayList<>(); + public ControllerLayout(Context context) { this(context, null); } - public ControllerLayout(Context context) { - this(context,null); - } + public ControllerLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public ControllerLayout(Context context, AttributeSet attrs) { - this(context, attrs,0); - } + public ControllerLayout(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } - public ControllerLayout(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr,0 ); - } + public ControllerLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } - public ControllerLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } + public void refreshChildren() { + ArrayList nodes = new ArrayList<>(); + populateNodesArray(this, nodes); - public void refreshChildren(){ - ArrayList nodes = new ArrayList<>(); - populateNodesArray(this, nodes); + // Need Reverse: First view is in back and last view is in front for respect android View hierarchy + Collections.reverse(nodes); - //Need Reverse: First view is in back and last view is in front for respect android View hierarchy - Collections.reverse(nodes); + controllerNodes.clear(); + controllerNodes.addAll(nodes); + } - controllerNodes.clear(); - controllerNodes.addAll(nodes); - } + private void populateNodesArray(ViewGroup group, ArrayList list) { + for (int i = 0; i < group.getChildCount(); i++) { + View view = group.getChildAt(i); + if (view instanceof ControllerNode) { + list.add((ControllerNode) view); + } else if (view instanceof ViewGroup) { + populateNodesArray((ViewGroup) view, list); + } + } + } - private void populateNodesArray(ViewGroup group, ArrayList list){ - for (int i = 0; i < group.getChildCount(); i++){ - View view = group.getChildAt(i); - if(view instanceof ControllerNode){ - list.add((ControllerNode) view); - } else if (view instanceof ViewGroup) { - populateNodesArray((ViewGroup) view, list); - } - } - } + @Override + public boolean onTouchEvent(MotionEvent event) { + int index = event.getActionIndex(); - @Override - public boolean onTouchEvent(MotionEvent event) { - int index = event.getActionIndex(); + switch (event.getActionMasked()) { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_POINTER_UP: { + int id = event.getPointerId(index); + processTouch(true, event.getX(index), event.getY(index), id); + } break; + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: { + int id = event.getPointerId(index); + processTouch(false, event.getX(index), event.getY(index), id); + } break; + case MotionEvent.ACTION_MOVE: + for (int id = 0; id < event.getPointerCount(); id++) { + processTouch(false, event.getX(id), event.getY(id), id); + } + break; + } + return true; + } - switch (event.getActionMasked()){ - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_POINTER_UP: { - int id = event.getPointerId(index); - processTouch(true, event.getX(index), event.getY(index), id); - }break; - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: { - int id = event.getPointerId(index); - processTouch(false, event.getX(index), event.getY(index), id); - }break; - case MotionEvent.ACTION_MOVE: - for (int id = 0; id < event.getPointerCount(); id++){ - processTouch(false, event.getX(id), event.getY(id), id); - } - break; - } - return true; - } + private void processTouch(boolean up, float x, float y, int index) { + int[] globalPosition = new int[2]; + getLocationInWindow(globalPosition); - private void processTouch(boolean up, float x, float y, int index){ - int[] globalPosition = new int[2]; - getLocationInWindow(globalPosition); + int action = TouchEvent.ACTION_MOVE; - int action = TouchEvent.ACTION_MOVE; + if ((!activeTouchEvents.containsKey(index))) { + if (up) return; + ControllerNode node = null; + for (ControllerNode item : controllerNodes) { + Vector2 pos = item.getPosition(); + Vector2 size = item.getSize(); - if ((!activeTouchEvents.containsKey(index))){ - if (up)return; - ControllerNode node = null; - for (ControllerNode item: controllerNodes){ - Vector2 pos = item.getPosition(); - Vector2 size= item.getSize(); + float cx = (pos.x - globalPosition[0]); + float cy = (pos.y - globalPosition[1]); + if (item.isVisible() && x > cx && x < cx + size.x && y > cy && y < cy + size.y) { + node = item; + break; + } + } + if (node != null) { + activeTouchEvents.put(index, node); + action = TouchEvent.ACTION_DOWN; + } else { + return; + } + } - float cx = (pos.x - globalPosition[0]); - float cy = (pos.y - globalPosition[1]); - if(item.isVisible() && x > cx && x < cx+size.x && y > cy && y < cy+size.y){ - node = item; - break; - } - } - if (node != null){ - activeTouchEvents.put(index, node); - action = TouchEvent.ACTION_DOWN; - } else { - return; - } - } + if (up) action = TouchEvent.ACTION_UP; - if (up) action = TouchEvent.ACTION_UP; + ControllerNode node = activeTouchEvents.get(index); + Vector2 pos = node.getPosition(); + pos.x -= globalPosition[0]; + pos.y -= globalPosition[1]; - ControllerNode node = activeTouchEvents.get(index); - Vector2 pos = node.getPosition(); - pos.x -= globalPosition[0]; - pos.y -= globalPosition[1]; + x -= pos.x; + y -= pos.y; - x -= pos.x; - y -= pos.y; + node.onTouch(new TouchEvent(x, y, action)); - node.onTouch(new TouchEvent(x,y,action)); + if (up) { + activeTouchEvents.remove(index); + } + } - if(up){ - activeTouchEvents.remove(index); - } - } + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + refreshChildren(); + } - @Override - public void onViewAdded(View child) { - super.onViewAdded(child); - refreshChildren(); - } + @Override + public void onViewRemoved(View child) { + super.onViewRemoved(child); + refreshChildren(); + } - @Override - public void onViewRemoved(View child) { - super.onViewRemoved(child); - refreshChildren(); - } + /*@TODO: Need replace that methods for prevent Android send events directly to children*/ - /*@TODO: Need replace that methods for prevent Android send events directly to children*/ - - @Override - public ArrayList getTouchables() { - return new ArrayList<>(); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - return true; - } + @Override + public ArrayList getTouchables() { + return new ArrayList<>(); + } + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return true; + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java index a29d08a4..e5b8795e 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java @@ -1,28 +1,22 @@ package com.panda3ds.pandroid.view.controller; - import android.view.View; - import androidx.annotation.NonNull; - import com.panda3ds.pandroid.math.Vector2; public interface ControllerNode { + @NonNull + default Vector2 getPosition() { + View me = (View) this; - @NonNull - default Vector2 getPosition(){ - View me = (View) this; + int[] position = new int[2]; + me.getLocationInWindow(position); + return new Vector2(position[0], position[1]); + } - int[] position = new int[2]; - me.getLocationInWindow(position); - return new Vector2(position[0], position[1]); - } + default boolean isVisible() { return ((View) this).isShown(); } - default boolean isVisible(){ - return ((View)this).isShown(); - } + @NonNull Vector2 getSize(); - @NonNull Vector2 getSize(); - - void onTouch(TouchEvent event); + void onTouch(TouchEvent event); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java index a804cda1..d3b40db9 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java @@ -1,28 +1,22 @@ package com.panda3ds.pandroid.view.controller; public class TouchEvent { - public static final int ACTION_DOWN = 0; - public static final int ACTION_MOVE = 1; - public static final int ACTION_UP = 2; + public static final int ACTION_DOWN = 0; + public static final int ACTION_MOVE = 1; + public static final int ACTION_UP = 2; - private final int action; - private final float x,y; + private final int action; + private final float x, y; - public float getX() { - return x; - } + public float getX() { return x; } - public float getY() { - return y; - } + public float getY() { return y; } - public int getAction() { - return action; - } + public int getAction() { return action; } - public TouchEvent(float x, float y, int action){ - this.x = x; - this.y = y; - this.action = action; - } + public TouchEvent(float x, float y, int action) { + this.x = x; + this.y = y; + this.action = action; + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/ButtonStateListener.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/ButtonStateListener.java index a658cdc0..eb5a693a 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/ButtonStateListener.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/ButtonStateListener.java @@ -3,5 +3,5 @@ package com.panda3ds.pandroid.view.controller.listeners; import com.panda3ds.pandroid.view.controller.nodes.Button; public interface ButtonStateListener { - void onButtonPressedChange(Button button, boolean pressed); + void onButtonPressedChange(Button button, boolean pressed); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/JoystickListener.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/JoystickListener.java index 538e2cd8..77225223 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/JoystickListener.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/listeners/JoystickListener.java @@ -3,5 +3,5 @@ package com.panda3ds.pandroid.view.controller.listeners; import com.panda3ds.pandroid.view.controller.nodes.Joystick; public interface JoystickListener { - void onJoystickAxisChange(Joystick joystick, float axisX, float axisY); + void onJoystickAxisChange(Joystick joystick, float axisX, float axisY); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java index 90d5f5f7..224be9a4 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java @@ -2,23 +2,15 @@ package com.panda3ds.pandroid.view.controller.nodes; import android.content.Context; import android.util.AttributeSet; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; - import com.panda3ds.pandroid.view.controller.ControllerNode; public abstract class BasicControllerNode extends AppCompatTextView implements ControllerNode { - public BasicControllerNode(@NonNull Context context) { - super(context); - } + public BasicControllerNode(@NonNull Context context) { super(context); } - public BasicControllerNode(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } + public BasicControllerNode(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } - public BasicControllerNode(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } + public BasicControllerNode(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java index 7e8d4e86..4dadc22b 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java @@ -5,69 +5,63 @@ import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.Gravity; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; - import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.view.controller.ControllerNode; import com.panda3ds.pandroid.view.controller.TouchEvent; import com.panda3ds.pandroid.view.controller.listeners.ButtonStateListener; public class Button extends BasicControllerNode { - private boolean pressed = false; - private int width,height; + private boolean pressed = false; + private int width, height; - private ButtonStateListener stateListener; + private ButtonStateListener stateListener; - public Button(@NonNull Context context) { - super(context); - init(); - } + public Button(@NonNull Context context) { + super(context); + init(); + } - public Button(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(); - } + public Button(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } - public Button(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(); - } + public Button(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - width = getWidth(); - height = getHeight(); - } + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + width = getWidth(); + height = getHeight(); + } - private void init(){ - setTextAlignment(TEXT_ALIGNMENT_CENTER); - setGravity(Gravity.CENTER); - } + private void init() { + setTextAlignment(TEXT_ALIGNMENT_CENTER); + setGravity(Gravity.CENTER); + } - public void setStateListener(ButtonStateListener stateListener) { - this.stateListener = stateListener; - } + public void setStateListener(ButtonStateListener stateListener) { this.stateListener = stateListener; } - public boolean isPressed() { - return pressed; - } + public boolean isPressed() { return pressed; } - @NonNull - @Override - public Vector2 getSize() { - return new Vector2(width,height); - } + @NonNull + @Override + public Vector2 getSize() { + return new Vector2(width, height); + } - @Override - public void onTouch(TouchEvent event) { - pressed = event.getAction() != TouchEvent.ACTION_UP; - setAlpha(pressed ? 0.2F : 1.0F); - if (stateListener != null){ - stateListener.onButtonPressedChange(this, pressed); - } - } + @Override + public void onTouch(TouchEvent event) { + pressed = event.getAction() != TouchEvent.ACTION_UP; + setAlpha(pressed ? 0.2F : 1.0F); + if (stateListener != null) { + stateListener.onButtonPressedChange(this, pressed); + } + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java index 757ec3cb..df487bd8 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java @@ -6,127 +6,110 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.AttributeSet; - import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatTextView; - import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.view.controller.ControllerNode; import com.panda3ds.pandroid.view.controller.TouchEvent; import com.panda3ds.pandroid.view.controller.listeners.JoystickListener; - public class Joystick extends BasicControllerNode implements ControllerNode { - private float stick_x = 0; - private float stick_y = 0; + private float stick_x = 0; + private float stick_y = 0; - private int size_width = 0; - private int size_height= 0; + private int size_width = 0; + private int size_height = 0; - private JoystickListener joystickListener; + private JoystickListener joystickListener; - public Joystick(Context context) { - this(context,null); - } + public Joystick(Context context) { this(context, null); } - public Joystick(Context context, AttributeSet attrs) { - this(context, attrs,0); - } + public Joystick(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public Joystick(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); + public Joystick(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); - paint.setColor(Color.RED); - invalidate(); - } + paint.setColor(Color.RED); + invalidate(); + } - private final Paint paint = new Paint(); + private final Paint paint = new Paint(); - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - } + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + } - @Override - public void onDrawForeground(Canvas canvas) { - size_width = getWidth(); - size_height = getHeight(); + @Override + public void onDrawForeground(Canvas canvas) { + size_width = getWidth(); + size_height = getHeight(); - int analogIconSize = size_width-getPaddingLeft(); + int analogIconSize = size_width - getPaddingLeft(); - float middleIconSize = analogIconSize / 2.0F; - float middle = size_width / 2.0F; + float middleIconSize = analogIconSize / 2.0F; + float middle = size_width / 2.0F; - float maxDistance = (middle - middleIconSize) * 0.9F; + float maxDistance = (middle - middleIconSize) * 0.9F; - float tx = maxDistance * stick_x; - float ty = maxDistance * stick_y; + float tx = maxDistance * stick_x; + float ty = maxDistance * stick_y; - float radius = Vector2.distance(0.0F, 0.0F, Math.abs(tx), Math.abs(ty)); - radius = Math.min(maxDistance, radius); + float radius = Vector2.distance(0.0F, 0.0F, Math.abs(tx), Math.abs(ty)); + radius = Math.min(maxDistance, radius); - double deg = Math.atan2(ty,tx) * (180.0/Math.PI); - float rx = (float) (radius*Math.cos(Math.PI * 2 * deg/360.0)); - float ry = (float) (radius*Math.sin(Math.PI * 2 * deg/360.0)); + double deg = Math.atan2(ty, tx) * (180.0 / Math.PI); + float rx = (float) (radius * Math.cos(Math.PI * 2 * deg / 360.0)); + float ry = (float) (radius * Math.sin(Math.PI * 2 * deg / 360.0)); - stick_x = Math.max(-1.0f, Math.min(1.0f, stick_x)); - stick_y = Math.max(-1.0f, Math.min(1.0f, stick_y)); + stick_x = Math.max(-1.0f, Math.min(1.0f, stick_x)); + stick_y = Math.max(-1.0f, Math.min(1.0f, stick_y)); + float x = middle - middleIconSize + rx; + float y = middle - middleIconSize + ry; - float x = middle-middleIconSize+rx; - float y = middle-middleIconSize+ry; + Drawable foreground = getForeground(); + if (foreground != null) { + foreground.setBounds((int) x, (int) y, (int) (x + analogIconSize), (int) (y + analogIconSize)); + foreground.draw(canvas); + } else { + canvas.drawOval(x, y, x + analogIconSize, y + analogIconSize, paint); + } + } + public Vector2 getAxis() { return new Vector2(Math.max(-1.0F, Math.min(1.0F, stick_x)), Math.max(-1.0F, Math.min(1.0F, stick_y))); } - Drawable foreground = getForeground(); - if (foreground != null){ - foreground.setBounds((int) x, (int) y, (int) (x+analogIconSize), (int) (y+analogIconSize)); - foreground.draw(canvas); - } else { - canvas.drawOval(x, y, x+analogIconSize,y+analogIconSize,paint); - } - } + public void setJoystickListener(JoystickListener joystickListener) { this.joystickListener = joystickListener; } - public Vector2 getAxis() { - return new Vector2( - Math.max(-1.0F, Math.min(1.0F, stick_x)), - Math.max(-1.0F, Math.min(1.0F, stick_y)) - ); - } + @NonNull + @Override + public Vector2 getSize() { + return new Vector2(size_width, size_height); + } - public void setJoystickListener(JoystickListener joystickListener) { - this.joystickListener = joystickListener; - } + @Override + public void onTouch(TouchEvent event) { + float middle = size_width / 2.0F; - @NonNull - @Override - public Vector2 getSize() { - return new Vector2(size_width,size_height); - } + float x = event.getX(); + float y = event.getY(); - @Override - public void onTouch(TouchEvent event) { + x = Math.max(0, Math.min(middle * 2, x)); + y = Math.max(0, Math.min(middle * 2, y)); - float middle = size_width/2.0F; + stick_x = ((x - middle) / middle); - float x = event.getX(); - float y = event.getY(); + stick_y = ((y - middle) / middle); - x = Math.max(0, Math.min(middle*2, x)); - y = Math.max(0, Math.min(middle*2, y)); + if (event.getAction() == TouchEvent.ACTION_UP) { + stick_x = 0; + stick_y = 0; + } - stick_x = ((x-middle)/middle); + if (joystickListener != null) { + joystickListener.onJoystickAxisChange(this, stick_x, stick_y); + } - stick_y = ((y-middle)/middle); - - if (event.getAction() == TouchEvent.ACTION_UP){ - stick_x = 0; - stick_y = 0; - } - - if (joystickListener != null){ - joystickListener.onJoystickAxisChange(this, stick_x, stick_y); - } - - invalidate(); - } + invalidate(); + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java index 85d1ddd6..1009d29c 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java @@ -3,7 +3,6 @@ package com.panda3ds.pandroid.view.controller.nodes; import android.graphics.Rect; import android.util.Log; import android.view.View; - import com.panda3ds.pandroid.AlberDriver; import com.panda3ds.pandroid.R; import com.panda3ds.pandroid.utils.Constants; @@ -12,28 +11,28 @@ import com.panda3ds.pandroid.view.controller.TouchEvent; import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; public interface TouchScreenNodeImpl extends ControllerNode { - default void onTouchScreenPress(ConsoleRenderer renderer, TouchEvent event){ + default void onTouchScreenPress(ConsoleRenderer renderer, TouchEvent event) { + View me = (View) this; + boolean hasDownEvent = me.getTag(R.id.TagEventHasDown) != null && (boolean) me.getTag(R.id.TagEventHasDown); - View me = (View) this; - boolean hasDownEvent = me.getTag(R.id.TagEventHasDown) != null && (boolean) me.getTag(R.id.TagEventHasDown); + Rect bounds = renderer.getLayout().getBottomDisplayBounds(); + ; - Rect bounds = renderer.getLayout().getBottomDisplayBounds();; + if (event.getX() >= bounds.left && event.getY() >= bounds.top && event.getX() <= bounds.right && event.getY() <= bounds.bottom) { + int x = (int) (event.getX() - bounds.left); + int y = (int) (event.getY() - bounds.top); - if (event.getX() >= bounds.left && event.getY() >= bounds.top && event.getX() <= bounds.right && event.getY() <= bounds.bottom){ - int x = (int) (event.getX() - bounds.left); - int y = (int) (event.getY() - bounds.top); + x = Math.round((x / (float) bounds.width()) * 320); + y = Math.round((y / (float) bounds.height()) * 240); - x = Math.round((x/(float)bounds.width())*320); - y = Math.round((y/(float)bounds.height())*240); + AlberDriver.TouchScreenDown(x, y); - AlberDriver.TouchScreenDown(x,y); + me.setTag(R.id.TagEventHasDown, true); + } - me.setTag(R.id.TagEventHasDown, true); - } - - if (hasDownEvent && event.getAction() == TouchEvent.ACTION_UP){ - AlberDriver.TouchScreenUp(); - me.setTag(R.id.TagEventHasDown, false); - } - } + if (hasDownEvent && event.getAction() == TouchEvent.ACTION_UP) { + AlberDriver.TouchScreenUp(); + me.setTag(R.id.TagEventHasDown, false); + } + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java index 13ad4d39..d5c99e8d 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/ConsoleRenderer.java @@ -3,7 +3,7 @@ package com.panda3ds.pandroid.view.renderer; import com.panda3ds.pandroid.view.renderer.layout.ConsoleLayout; public interface ConsoleRenderer { - void setLayout(ConsoleLayout layout); - ConsoleLayout getLayout(); - String getBackendName(); + void setLayout(ConsoleLayout layout); + ConsoleLayout getLayout(); + String getBackendName(); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java index 781f0abd..dc83c59f 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java @@ -1,15 +1,14 @@ package com.panda3ds.pandroid.view.renderer.layout; import android.graphics.Rect; - import com.panda3ds.pandroid.math.Vector2; public interface ConsoleLayout { - void update(int screenWidth, int screenHeight); + void update(int screenWidth, int screenHeight); - void setBottomDisplaySourceSize(int width, int height); - void setTopDisplaySourceSize(int width, int height); + void setBottomDisplaySourceSize(int width, int height); + void setTopDisplaySourceSize(int width, int height); - Rect getBottomDisplayBounds(); - Rect getTopDisplayBounds(); + Rect getBottomDisplayBounds(); + Rect getTopDisplayBounds(); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java index a54db8f7..d8616167 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java @@ -2,80 +2,76 @@ package com.panda3ds.pandroid.view.renderer.layout; import android.graphics.Rect; import android.util.Size; - import com.panda3ds.pandroid.math.Vector2; public class DefaultScreenLayout implements ConsoleLayout { - private final Rect topDisplay = new Rect(); - private final Rect bottomDisplay = new Rect(); + private final Rect topDisplay = new Rect(); + private final Rect bottomDisplay = new Rect(); - private final Vector2 screenSize = new Vector2(1.0F, 1.0F); - private final Vector2 topSourceSize = new Vector2(1.0F, 1.0F); - private final Vector2 bottomSourceSize = new Vector2(1.0F, 1.0F); + private final Vector2 screenSize = new Vector2(1.0F, 1.0F); + private final Vector2 topSourceSize = new Vector2(1.0F, 1.0F); + private final Vector2 bottomSourceSize = new Vector2(1.0F, 1.0F); - @Override - public void update(int screenWidth, int screenHeight) { - screenSize.set(screenWidth, screenHeight); - updateBounds(); - } + @Override + public void update(int screenWidth, int screenHeight) { + screenSize.set(screenWidth, screenHeight); + updateBounds(); + } - @Override - public void setBottomDisplaySourceSize(int width, int height) { - bottomSourceSize.set(width,height); - updateBounds(); - } - @Override - public void setTopDisplaySourceSize(int width, int height) { - topSourceSize.set(width,height); - updateBounds(); - } + @Override + public void setBottomDisplaySourceSize(int width, int height) { + bottomSourceSize.set(width, height); + updateBounds(); + } + @Override + public void setTopDisplaySourceSize(int width, int height) { + topSourceSize.set(width, height); + updateBounds(); + } - private void updateBounds(){ - int screenWidth = (int) screenSize.x; - int screenHeight = (int) screenSize.y; + private void updateBounds() { + int screenWidth = (int) screenSize.x; + int screenHeight = (int) screenSize.y; - if (screenWidth > screenHeight){ + if (screenWidth > screenHeight) { + int topDisplayWidth = (int) ((screenHeight / topSourceSize.y) * topSourceSize.x); + int topDisplayHeight = screenHeight; - int topDisplayWidth = (int) ((screenHeight / topSourceSize.y) * topSourceSize.x); - int topDisplayHeight = screenHeight; + if (topDisplayWidth > (screenWidth * 0.7)) { + topDisplayWidth = (int) (screenWidth * 0.7); + topDisplayHeight = (int) ((topDisplayWidth / topSourceSize.x) * topSourceSize.y); + } - if (topDisplayWidth > (screenWidth*0.7)){ - topDisplayWidth = (int) (screenWidth * 0.7); - topDisplayHeight = (int) ((topDisplayWidth/topSourceSize.x)* topSourceSize.y); - } + int bottomDisplayHeight = (int) (((screenWidth - topDisplayWidth) / bottomSourceSize.x) * bottomSourceSize.y); - int bottomDisplayHeight = (int) (((screenWidth-topDisplayWidth)/ bottomSourceSize.x)* bottomSourceSize.y); + topDisplay.set(0, 0, topDisplayWidth, topDisplayHeight); + bottomDisplay.set(topDisplayWidth, 0, topDisplayWidth + (screenWidth - topDisplayWidth), bottomDisplayHeight); + } else { + int topScreenHeight = (int) ((screenWidth / topSourceSize.x) * topSourceSize.y); + topDisplay.set(0, 0, screenWidth, topScreenHeight); + int bottomDisplayHeight = (int) ((screenWidth / bottomSourceSize.x) * bottomSourceSize.y); + int bottomDisplayWidth = screenWidth; + int bottomDisplayX = 0; - topDisplay.set(0, 0, topDisplayWidth, topDisplayHeight); - bottomDisplay.set(topDisplayWidth, 0, topDisplayWidth+(screenWidth-topDisplayWidth), bottomDisplayHeight); - } else { - int topScreenHeight = (int) ((screenWidth/ topSourceSize.x) * topSourceSize.y); - topDisplay.set(0,0,screenWidth,topScreenHeight); + if (topScreenHeight + bottomDisplayHeight > screenHeight) { + bottomDisplayHeight = (screenHeight - topScreenHeight); + bottomDisplayWidth = (int) ((bottomDisplayHeight / bottomSourceSize.y) * bottomSourceSize.x); + bottomDisplayX = (screenWidth - bottomDisplayX) / 2; + } - int bottomDisplayHeight = (int)((screenWidth/ bottomSourceSize.x) * bottomSourceSize.y); - int bottomDisplayWidth = screenWidth; - int bottomDisplayX = 0; + topDisplay.set(0, 0, screenWidth, topScreenHeight); + bottomDisplay.set(bottomDisplayX, topScreenHeight, bottomDisplayX + bottomDisplayWidth, topScreenHeight + bottomDisplayHeight); + } + } - if (topScreenHeight + bottomDisplayHeight > screenHeight){ - bottomDisplayHeight = (screenHeight-topScreenHeight); - bottomDisplayWidth = (int) ((bottomDisplayHeight/ bottomSourceSize.y)*bottomSourceSize.x); - bottomDisplayX = (screenWidth-bottomDisplayX)/2; - } + @Override + public Rect getBottomDisplayBounds() { + return bottomDisplay; + } - topDisplay.set(0,0, screenWidth,topScreenHeight); - bottomDisplay.set(bottomDisplayX, topScreenHeight, bottomDisplayX+bottomDisplayWidth,topScreenHeight+bottomDisplayHeight); - } - } - - - @Override - public Rect getBottomDisplayBounds() { - return bottomDisplay; - } - - @Override - public Rect getTopDisplayBounds() { - return topDisplay; - } + @Override + public Rect getTopDisplayBounds() { + return topDisplay; + } } From 609d3fc196984c7f071ca6efa9b7ea1c16906907 Mon Sep 17 00:00:00 2001 From: gabriel Date: Thu, 7 Dec 2023 17:49:22 -0400 Subject: [PATCH 11/21] Fix words --- src/pandroid/app/src/main/AndroidManifest.xml | 2 +- .../panda3ds/pandroid/app/GameActivity.java | 13 +++--- .../com/panda3ds/pandroid/math/Vector2.java | 4 -- .../panda3ds/pandroid/utils/Constants.java | 4 +- .../pandroid/view/PandaGlRenderer.java | 4 +- .../pandroid/view/PandaGlSurfaceView.java | 14 +++---- .../view/controller/ControllerNode.java | 4 +- .../view/controller/nodes/Joystick.java | 42 +++++++++---------- .../controller/nodes/TouchScreenNodeImpl.java | 12 +++--- .../view/renderer/layout/ConsoleLayout.java | 1 - .../renderer/layout/DefaultScreenLayout.java | 2 +- 11 files changed, 45 insertions(+), 57 deletions(-) diff --git a/src/pandroid/app/src/main/AndroidManifest.xml b/src/pandroid/app/src/main/AndroidManifest.xml index 978edcc5..291496f4 100644 --- a/src/pandroid/app/src/main/AndroidManifest.xml +++ b/src/pandroid/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ + android:glEsVersion="0x0030001"/> { - findViewById(R.id.overlay_controller).setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE); - }); + ((CheckBox) findViewById(R.id.hide_screen_controller)).setOnCheckedChangeListener((buttonView, isChecked) -> findViewById(R.id.overlay_controller).setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE)); } @Override diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java index 4208b610..becec9e1 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Vector2.java @@ -2,15 +2,11 @@ package com.panda3ds.pandroid.math; public class Vector2 { public float x, y; - public Vector2(Vector2 value) { this(value.x, value.y); } - public Vector2(float x, float y) { this.x = x; this.y = y; } - public float distanceTo(Vector2 vec) { return distance(x, y, vec.x, vec.y); } - public static float distance(float x, float y, float x2, float y2) { return (float) Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); } public void set(float x, float y) { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java index bc389987..3485180e 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java @@ -6,7 +6,7 @@ public class Constants { public static final int INPUT_KEY_LEFT = 1 << 5; public static final int INPUT_KEY_RIGHT = 1 << 4; - public static final int INPUT_KEY_A = 1 << 0; + public static final int INPUT_KEY_A = 1; public static final int INPUT_KEY_B = 1 << 1; public static final int INPUT_KEY_X = 1 << 10; public static final int INPUT_KEY_Y = 1 << 11; @@ -22,5 +22,5 @@ public class Constants { public static final int N3DS_FULL_HEIGHT = 480; public static final String EXTRA_PATH = "path"; - public static final String LOG_TAG = "Alber"; + public static final String LOG_TAG = "pandroid"; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java index b21e3353..0df05e9f 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java @@ -42,8 +42,8 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer } public void onSurfaceCreated(GL10 unused, EGLConfig config) { - Log.i("pandroid", glGetString(GL_EXTENSIONS)); - Log.w("pandroid", glGetString(GL_VERSION)); + Log.i(Constants.LOG_TAG, glGetString(GL_EXTENSIONS)); + Log.w(Constants.LOG_TAG, glGetString(GL_VERSION)); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java index f5a19efe..eb65762d 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java @@ -1,20 +1,18 @@ package com.panda3ds.pandroid.view; import android.content.Context; -import android.graphics.Canvas; import android.opengl.GLSurfaceView; -import android.util.Log; + import androidx.annotation.NonNull; import com.panda3ds.pandroid.math.Vector2; -import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.view.controller.TouchEvent; import com.panda3ds.pandroid.view.controller.nodes.TouchScreenNodeImpl; import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; public class PandaGlSurfaceView extends GLSurfaceView implements TouchScreenNodeImpl { final PandaGlRenderer renderer; - private int size_width; - private int size_height; + private int width; + private int height; public PandaGlSurfaceView(Context context, String romPath) { super(context); @@ -29,14 +27,14 @@ public class PandaGlSurfaceView extends GLSurfaceView implements TouchScreenNode @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - size_width = getMeasuredWidth(); - size_height = getMeasuredHeight(); + width = getMeasuredWidth(); + height = getMeasuredHeight(); } @NonNull @Override public Vector2 getSize() { - return new Vector2(size_width, size_height); + return new Vector2(width, height); } @Override diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java index e5b8795e..e6c1dc92 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java @@ -7,10 +7,10 @@ import com.panda3ds.pandroid.math.Vector2; public interface ControllerNode { @NonNull default Vector2 getPosition() { - View me = (View) this; + View view = (View) this; int[] position = new int[2]; - me.getLocationInWindow(position); + view.getLocationInWindow(position); return new Vector2(position[0], position[1]); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java index df487bd8..ad3df6b1 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java @@ -7,18 +7,18 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import androidx.annotation.NonNull; -import androidx.appcompat.widget.AppCompatTextView; + import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.view.controller.ControllerNode; import com.panda3ds.pandroid.view.controller.TouchEvent; import com.panda3ds.pandroid.view.controller.listeners.JoystickListener; public class Joystick extends BasicControllerNode implements ControllerNode { - private float stick_x = 0; - private float stick_y = 0; + private float axisX = 0; + private float axisY = 0; - private int size_width = 0; - private int size_height = 0; + private int width = 0; + private int height = 0; private JoystickListener joystickListener; @@ -42,18 +42,18 @@ public class Joystick extends BasicControllerNode implements ControllerNode { @Override public void onDrawForeground(Canvas canvas) { - size_width = getWidth(); - size_height = getHeight(); + width = getWidth(); + height = getHeight(); - int analogIconSize = size_width - getPaddingLeft(); + int analogIconSize = width - getPaddingLeft(); float middleIconSize = analogIconSize / 2.0F; - float middle = size_width / 2.0F; + float middle = width / 2.0F; float maxDistance = (middle - middleIconSize) * 0.9F; - float tx = maxDistance * stick_x; - float ty = maxDistance * stick_y; + float tx = maxDistance * axisX; + float ty = maxDistance * axisY; float radius = Vector2.distance(0.0F, 0.0F, Math.abs(tx), Math.abs(ty)); radius = Math.min(maxDistance, radius); @@ -62,8 +62,8 @@ public class Joystick extends BasicControllerNode implements ControllerNode { float rx = (float) (radius * Math.cos(Math.PI * 2 * deg / 360.0)); float ry = (float) (radius * Math.sin(Math.PI * 2 * deg / 360.0)); - stick_x = Math.max(-1.0f, Math.min(1.0f, stick_x)); - stick_y = Math.max(-1.0f, Math.min(1.0f, stick_y)); + axisX = Math.max(-1.0f, Math.min(1.0f, axisX)); + axisY = Math.max(-1.0f, Math.min(1.0f, axisY)); float x = middle - middleIconSize + rx; float y = middle - middleIconSize + ry; @@ -77,19 +77,19 @@ public class Joystick extends BasicControllerNode implements ControllerNode { } } - public Vector2 getAxis() { return new Vector2(Math.max(-1.0F, Math.min(1.0F, stick_x)), Math.max(-1.0F, Math.min(1.0F, stick_y))); } + public Vector2 getAxis() { return new Vector2(Math.max(-1.0F, Math.min(1.0F, axisX)), Math.max(-1.0F, Math.min(1.0F, axisY))); } public void setJoystickListener(JoystickListener joystickListener) { this.joystickListener = joystickListener; } @NonNull @Override public Vector2 getSize() { - return new Vector2(size_width, size_height); + return new Vector2(width, height); } @Override public void onTouch(TouchEvent event) { - float middle = size_width / 2.0F; + float middle = width / 2.0F; float x = event.getX(); float y = event.getY(); @@ -97,17 +97,17 @@ public class Joystick extends BasicControllerNode implements ControllerNode { x = Math.max(0, Math.min(middle * 2, x)); y = Math.max(0, Math.min(middle * 2, y)); - stick_x = ((x - middle) / middle); + axisX = ((x - middle) / middle); - stick_y = ((y - middle) / middle); + axisY = ((y - middle) / middle); if (event.getAction() == TouchEvent.ACTION_UP) { - stick_x = 0; - stick_y = 0; + axisX = 0; + axisY = 0; } if (joystickListener != null) { - joystickListener.onJoystickAxisChange(this, stick_x, stick_y); + joystickListener.onJoystickAxisChange(this, axisX, axisY); } invalidate(); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java index 1009d29c..39e6aae9 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java @@ -1,22 +1,20 @@ package com.panda3ds.pandroid.view.controller.nodes; import android.graphics.Rect; -import android.util.Log; import android.view.View; + import com.panda3ds.pandroid.AlberDriver; import com.panda3ds.pandroid.R; -import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.view.controller.ControllerNode; import com.panda3ds.pandroid.view.controller.TouchEvent; import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; public interface TouchScreenNodeImpl extends ControllerNode { default void onTouchScreenPress(ConsoleRenderer renderer, TouchEvent event) { - View me = (View) this; - boolean hasDownEvent = me.getTag(R.id.TagEventHasDown) != null && (boolean) me.getTag(R.id.TagEventHasDown); + View view = (View) this; + boolean hasDownEvent = view.getTag(R.id.TagEventHasDown) != null && (boolean) view.getTag(R.id.TagEventHasDown); Rect bounds = renderer.getLayout().getBottomDisplayBounds(); - ; if (event.getX() >= bounds.left && event.getY() >= bounds.top && event.getX() <= bounds.right && event.getY() <= bounds.bottom) { int x = (int) (event.getX() - bounds.left); @@ -27,12 +25,12 @@ public interface TouchScreenNodeImpl extends ControllerNode { AlberDriver.TouchScreenDown(x, y); - me.setTag(R.id.TagEventHasDown, true); + view.setTag(R.id.TagEventHasDown, true); } if (hasDownEvent && event.getAction() == TouchEvent.ACTION_UP) { AlberDriver.TouchScreenUp(); - me.setTag(R.id.TagEventHasDown, false); + view.setTag(R.id.TagEventHasDown, false); } } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java index dc83c59f..7ec00974 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/ConsoleLayout.java @@ -1,7 +1,6 @@ package com.panda3ds.pandroid.view.renderer.layout; import android.graphics.Rect; -import com.panda3ds.pandroid.math.Vector2; public interface ConsoleLayout { void update(int screenWidth, int screenHeight); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java index d8616167..adfe5443 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java @@ -1,7 +1,7 @@ package com.panda3ds.pandroid.view.renderer.layout; import android.graphics.Rect; -import android.util.Size; + import com.panda3ds.pandroid.math.Vector2; public class DefaultScreenLayout implements ConsoleLayout { From 00bf1bc6b870c46c4e8c66e47a4aebec613f3429 Mon Sep 17 00:00:00 2001 From: offtkp Date: Fri, 8 Dec 2023 02:24:02 +0200 Subject: [PATCH 12/21] Reduce jni boilerplate --- src/jni_driver.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp index 6d3bd104..82720e2a 100644 --- a/src/jni_driver.cpp +++ b/src/jni_driver.cpp @@ -13,7 +13,10 @@ HIDService* hidService = nullptr; RendererGL* renderer = nullptr; bool romLoaded = false; -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_Initialize(JNIEnv* env, jobject obj) { +#define AlberFunction(type, name) JNIEXPORT type JNICALL Java_com_panda3ds_pandroid_AlberDriver_##name + +extern "C" { +AlberFunction(void, Initialize)(JNIEnv* env, jobject obj) { emulator = std::make_unique(); if (emulator->getRendererType() != RendererType::OpenGL) { @@ -31,7 +34,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_Initial emulator->initGraphicsContext(nullptr); } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_RunFrame(JNIEnv* env, jobject obj, jint fbo) { +AlberFunction(void, RunFrame)(JNIEnv* env, jobject obj, jint fbo) { renderer->setFBO(fbo); renderer->resetStateManager(); emulator->runFrame(); @@ -39,36 +42,33 @@ extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_RunFram hidService->updateInputs(emulator->getTicks()); } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_Finalize(JNIEnv* env, jobject obj) { +AlberFunction(void, Finalize)(JNIEnv* env, jobject obj) { emulator = nullptr; hidService = nullptr; renderer = nullptr; } -extern "C" JNIEXPORT jboolean JNICALL Java_com_panda3ds_pandroid_AlberDriver_HasRomLoaded(JNIEnv* env, jobject obj) { return romLoaded; } +AlberFunction(jboolean, HasRomLoaded)(JNIEnv* env, jobject obj) { return romLoaded; } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_LoadRom(JNIEnv* env, jobject obj, jstring path) { +AlberFunction(void, LoadRom)(JNIEnv* env, jobject obj, jstring path) { const char* pathStr = env->GetStringUTFChars(path, nullptr); romLoaded = emulator->loadROM(pathStr); __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "Loading ROM %s, result: %d", pathStr, (int)romLoaded); env->ReleaseStringUTFChars(path, pathStr); } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_TouchScreenDown(JNIEnv* env, jobject obj, jint x, jint y) { - hidService->setTouchScreenPress((u16)x, (u16)y); -} +AlberFunction(void, TouchScreenDown)(JNIEnv* env, jobject obj, jint x, jint y) { hidService->setTouchScreenPress((u16)x, (u16)y); } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_TouchScreenUp(JNIEnv* env, jobject obj) { hidService->releaseTouchScreen(); } +AlberFunction(void, TouchScreenUp)(JNIEnv* env, jobject obj) { hidService->releaseTouchScreen(); } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_KeyUp(JNIEnv* env, jobject obj, jint keyCode) { - hidService->releaseKey((u32)keyCode); -} +AlberFunction(void, KeyUp)(JNIEnv* env, jobject obj, jint keyCode) { hidService->releaseKey((u32)keyCode); } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_KeyDown(JNIEnv* env, jobject obj, jint keyCode) { - hidService->pressKey((u32)keyCode); -} +AlberFunction(void, KeyDown)(JNIEnv* env, jobject obj, jint keyCode) { hidService->pressKey((u32)keyCode); } -extern "C" JNIEXPORT void JNICALL Java_com_panda3ds_pandroid_AlberDriver_SetCirclepadAxis(JNIEnv* env, jobject obj, jint x, jint y) { +AlberFunction(void, SetCirclepadAxis)(JNIEnv* env, jobject obj, jint x, jint y) { hidService->setCirclepadX((s16)x); hidService->setCirclepadY((s16)y); } +} + +#undef AlberFunction \ No newline at end of file From a78a1a099f562ad100d0d80f30c09a02ce1e49c0 Mon Sep 17 00:00:00 2001 From: offtkp Date: Fri, 8 Dec 2023 03:12:21 +0200 Subject: [PATCH 13/21] More peach fixups --- .../panda3ds/pandroid/app/GameActivity.java | 4 ++-- .../panda3ds/pandroid/app/MainActivity.java | 8 +++---- .../panda3ds/pandroid/utils/Constants.java | 23 ++++++++----------- .../panda3ds/pandroid/utils/PathUtils.java | 19 ++++----------- .../pandroid/view/PandaGlRenderer.java | 8 +++++++ .../view/controller/ControllerLayout.java | 7 +++--- .../pandroid/view/controller/TouchEvent.java | 10 +++----- .../pandroid/view/controller/TouchType.java | 7 ++++++ .../view/controller/nodes/Button.java | 5 ++-- .../view/controller/nodes/Joystick.java | 19 +++++++-------- .../controller/nodes/TouchScreenNodeImpl.java | 3 ++- .../renderer/layout/DefaultScreenLayout.java | 6 ++--- 12 files changed, 60 insertions(+), 59 deletions(-) create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchType.java diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index d086e85f..dfba96e5 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -23,14 +23,14 @@ public class GameActivity extends BaseActivity { super.onCreate(savedInstanceState); Intent intent = getIntent(); - if (!intent.hasExtra(Constants.EXTRA_PATH)) { + if (!intent.hasExtra(Constants.ACTIVITY_PARAMETER_PATH)) { setContentView(new FrameLayout(this)); Toast.makeText(this, "Invalid rom path!", Toast.LENGTH_LONG).show(); finish(); return; } - PandaGlSurfaceView pandaSurface = new PandaGlSurfaceView(this, intent.getStringExtra(Constants.EXTRA_PATH)); + PandaGlSurfaceView pandaSurface = new PandaGlSurfaceView(this, intent.getStringExtra(Constants.ACTIVITY_PARAMETER_PATH)); setContentView(R.layout.game_activity); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java index 181cfb4e..368efe0e 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java @@ -16,14 +16,14 @@ import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.utils.PathUtils; public class MainActivity extends BaseActivity { - private static final int PICK_3DS_ROM = 2; + private static final int PICK_ROM = 2; private static final int PERMISSION_REQUEST_CODE = 3; private void openFile() { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); - startActivityForResult(intent, PICK_3DS_ROM); + startActivityForResult(intent, PICK_ROM); } @Override @@ -46,11 +46,11 @@ public class MainActivity extends BaseActivity { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == PICK_3DS_ROM) { + if (requestCode == PICK_ROM) { if (resultCode == RESULT_OK) { String path = PathUtils.getPath(getApplicationContext(), data.getData()); Toast.makeText(getApplicationContext(), "pandroid opening " + path, Toast.LENGTH_LONG).show(); - startActivity(new Intent(this, GameActivity.class).putExtra(Constants.EXTRA_PATH, path)); + startActivity(new Intent(this, GameActivity.class).putExtra(Constants.ACTIVITY_PARAMETER_PATH, path)); } super.onActivityResult(requestCode, resultCode, data); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java index 3485180e..6b480c23 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java @@ -1,26 +1,23 @@ package com.panda3ds.pandroid.utils; public class Constants { + public static final int INPUT_KEY_A = 1 << 0; + public static final int INPUT_KEY_B = 1 << 1; + public static final int INPUT_KEY_SELECT = 1 << 2; + public static final int INPUT_KEY_START = 1 << 3; + public static final int INPUT_KEY_RIGHT = 1 << 4; + public static final int INPUT_KEY_LEFT = 1 << 5; public static final int INPUT_KEY_UP = 1 << 6; public static final int INPUT_KEY_DOWN = 1 << 7; - public static final int INPUT_KEY_LEFT = 1 << 5; - public static final int INPUT_KEY_RIGHT = 1 << 4; - - public static final int INPUT_KEY_A = 1; - public static final int INPUT_KEY_B = 1 << 1; + public static final int INPUT_KEY_R = 1 << 8; + public static final int INPUT_KEY_L = 1 << 9; public static final int INPUT_KEY_X = 1 << 10; public static final int INPUT_KEY_Y = 1 << 11; - public static final int INPUT_KEY_R = 1 << 8; - public static final int INPUT_KEY_L = 1 << 9; - - public static final int INPUT_KEY_START = 1 << 3; - public static final int INPUT_KEY_SELECT = 1 << 2; - public static final int N3DS_WIDTH = 400; public static final int N3DS_HALF_HEIGHT = 240; - public static final int N3DS_FULL_HEIGHT = 480; + public static final int N3DS_FULL_HEIGHT = N3DS_HALF_HEIGHT * 2; - public static final String EXTRA_PATH = "path"; + public static final String ACTIVITY_PARAMETER_PATH = "path"; public static final String LOG_TAG = "pandroid"; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java index ccf655bf..0434e53f 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java @@ -11,9 +11,8 @@ import android.provider.MediaStore; public class PathUtils { public static String getPath(final Context context, final Uri uri) { - // DocumentProvider if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) { - if (isExternalStorageDocument(uri)) { // ExternalStorageProvider + if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; @@ -33,14 +32,12 @@ public class PathUtils { return System.getenv(storageDefinition) + "/" + split[1]; } - } else if (isDownloadsDocument(uri)) { // DownloadsProvider - + } else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); - - } else if (isMediaDocument(uri)) { // MediaProvider + } else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; @@ -56,18 +53,13 @@ public class PathUtils { final String selection = "_id=?"; final String[] selectionArgs = new String[] {split[1]}; - return getDataColumn(context, contentUri, selection, selectionArgs); } - } else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general) - - // Return the remote address + } else if ("content".equalsIgnoreCase(uri.getScheme())) { if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); - return getDataColumn(context, uri, null, null); - - } else if ("file".equalsIgnoreCase(uri.getScheme())) { // File + } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } @@ -78,7 +70,6 @@ public class PathUtils { Cursor cursor = null; final String column = "_data"; final String[] projection = {column}; - try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java index 0df05e9f..128e9b4f 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java @@ -45,6 +45,14 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer Log.i(Constants.LOG_TAG, glGetString(GL_EXTENSIONS)); Log.w(Constants.LOG_TAG, glGetString(GL_VERSION)); + int[] version = new int[2]; + glGetIntegerv(GL_MAJOR_VERSION, version, 0); + glGetIntegerv(GL_MINOR_VERSION, version, 1); + + if (version[0] < 3 || (version[0] == 3 && version[1] < 1)) { + Log.e(Constants.LOG_TAG, "OpenGL 3.1 or higher is required"); + } + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java index 137bd312..4af28497 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java @@ -79,8 +79,7 @@ public class ControllerLayout extends RelativeLayout { int[] globalPosition = new int[2]; getLocationInWindow(globalPosition); - int action = TouchEvent.ACTION_MOVE; - + TouchType action = TouchType.ACTION_MOVE; if ((!activeTouchEvents.containsKey(index))) { if (up) return; ControllerNode node = null; @@ -97,13 +96,13 @@ public class ControllerLayout extends RelativeLayout { } if (node != null) { activeTouchEvents.put(index, node); - action = TouchEvent.ACTION_DOWN; + action = TouchType.ACTION_DOWN; } else { return; } } - if (up) action = TouchEvent.ACTION_UP; + if (up) action = TouchType.ACTION_UP; ControllerNode node = activeTouchEvents.get(index); Vector2 pos = node.getPosition(); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java index d3b40db9..8c940414 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java @@ -1,20 +1,16 @@ package com.panda3ds.pandroid.view.controller; public class TouchEvent { - public static final int ACTION_DOWN = 0; - public static final int ACTION_MOVE = 1; - public static final int ACTION_UP = 2; - - private final int action; + private final TouchType action; private final float x, y; public float getX() { return x; } public float getY() { return y; } - public int getAction() { return action; } + public TouchType getAction() { return action; } - public TouchEvent(float x, float y, int action) { + public TouchEvent(float x, float y, TouchType action) { this.x = x; this.y = y; this.action = action; diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchType.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchType.java new file mode 100644 index 00000000..69772915 --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchType.java @@ -0,0 +1,7 @@ +package com.panda3ds.pandroid.view.controller; + +public enum TouchType { + ACTION_DOWN, + ACTION_MOVE, + ACTION_UP +}; \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java index 4dadc22b..83c38d48 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Button.java @@ -11,6 +11,7 @@ import androidx.appcompat.widget.AppCompatTextView; import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.view.controller.ControllerNode; import com.panda3ds.pandroid.view.controller.TouchEvent; +import com.panda3ds.pandroid.view.controller.TouchType; import com.panda3ds.pandroid.view.controller.listeners.ButtonStateListener; public class Button extends BasicControllerNode { @@ -58,8 +59,8 @@ public class Button extends BasicControllerNode { @Override public void onTouch(TouchEvent event) { - pressed = event.getAction() != TouchEvent.ACTION_UP; - setAlpha(pressed ? 0.2F : 1.0F); + pressed = event.getAction() != TouchType.ACTION_UP; + setAlpha(pressed ? 0.2f : 1.0f); if (stateListener != null) { stateListener.onButtonPressedChange(this, pressed); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java index ad3df6b1..b63e9d66 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java @@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.view.controller.ControllerNode; import com.panda3ds.pandroid.view.controller.TouchEvent; +import com.panda3ds.pandroid.view.controller.TouchType; import com.panda3ds.pandroid.view.controller.listeners.JoystickListener; public class Joystick extends BasicControllerNode implements ControllerNode { @@ -47,20 +48,20 @@ public class Joystick extends BasicControllerNode implements ControllerNode { int analogIconSize = width - getPaddingLeft(); - float middleIconSize = analogIconSize / 2.0F; - float middle = width / 2.0F; + float middleIconSize = analogIconSize / 2.0f; + float middle = width / 2.0f; - float maxDistance = (middle - middleIconSize) * 0.9F; + float maxDistance = (middle - middleIconSize) * 0.9f; float tx = maxDistance * axisX; float ty = maxDistance * axisY; - float radius = Vector2.distance(0.0F, 0.0F, Math.abs(tx), Math.abs(ty)); + float radius = Vector2.distance(0.0f, 0.0f, Math.abs(tx), Math.abs(ty)); radius = Math.min(maxDistance, radius); double deg = Math.atan2(ty, tx) * (180.0 / Math.PI); - float rx = (float) (radius * Math.cos(Math.PI * 2 * deg / 360.0)); - float ry = (float) (radius * Math.sin(Math.PI * 2 * deg / 360.0)); + float rx = (float) (radius * Math.cos(2 * Math.PI * deg / 360.0)); + float ry = (float) (radius * Math.sin(2 * Math.PI * deg / 360.0)); axisX = Math.max(-1.0f, Math.min(1.0f, axisX)); axisY = Math.max(-1.0f, Math.min(1.0f, axisY)); @@ -77,7 +78,7 @@ public class Joystick extends BasicControllerNode implements ControllerNode { } } - public Vector2 getAxis() { return new Vector2(Math.max(-1.0F, Math.min(1.0F, axisX)), Math.max(-1.0F, Math.min(1.0F, axisY))); } + public Vector2 getAxis() { return new Vector2(Math.max(-1.0f, Math.min(1.0f, axisX)), Math.max(-1.0f, Math.min(1.0f, axisY))); } public void setJoystickListener(JoystickListener joystickListener) { this.joystickListener = joystickListener; } @@ -89,7 +90,7 @@ public class Joystick extends BasicControllerNode implements ControllerNode { @Override public void onTouch(TouchEvent event) { - float middle = width / 2.0F; + float middle = width / 2.0f; float x = event.getX(); float y = event.getY(); @@ -101,7 +102,7 @@ public class Joystick extends BasicControllerNode implements ControllerNode { axisY = ((y - middle) / middle); - if (event.getAction() == TouchEvent.ACTION_UP) { + if (event.getAction() == TouchType.ACTION_UP) { axisX = 0; axisY = 0; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java index 39e6aae9..bf51d4fe 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/TouchScreenNodeImpl.java @@ -7,6 +7,7 @@ import com.panda3ds.pandroid.AlberDriver; import com.panda3ds.pandroid.R; import com.panda3ds.pandroid.view.controller.ControllerNode; import com.panda3ds.pandroid.view.controller.TouchEvent; +import com.panda3ds.pandroid.view.controller.TouchType; import com.panda3ds.pandroid.view.renderer.ConsoleRenderer; public interface TouchScreenNodeImpl extends ControllerNode { @@ -28,7 +29,7 @@ public interface TouchScreenNodeImpl extends ControllerNode { view.setTag(R.id.TagEventHasDown, true); } - if (hasDownEvent && event.getAction() == TouchEvent.ACTION_UP) { + if (hasDownEvent && event.getAction() == TouchType.ACTION_UP) { AlberDriver.TouchScreenUp(); view.setTag(R.id.TagEventHasDown, false); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java index adfe5443..a726b2e6 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/renderer/layout/DefaultScreenLayout.java @@ -8,9 +8,9 @@ public class DefaultScreenLayout implements ConsoleLayout { private final Rect topDisplay = new Rect(); private final Rect bottomDisplay = new Rect(); - private final Vector2 screenSize = new Vector2(1.0F, 1.0F); - private final Vector2 topSourceSize = new Vector2(1.0F, 1.0F); - private final Vector2 bottomSourceSize = new Vector2(1.0F, 1.0F); + private final Vector2 screenSize = new Vector2(1.0f, 1.0f); + private final Vector2 topSourceSize = new Vector2(1.0f, 1.0f); + private final Vector2 bottomSourceSize = new Vector2(1.0f, 1.0f); @Override public void update(int screenWidth, int screenHeight) { From e6880b15641f4fae33880e407ac77289fb041f58 Mon Sep 17 00:00:00 2001 From: offtkp Date: Fri, 8 Dec 2023 03:28:43 +0200 Subject: [PATCH 14/21] Even more peach stuff --- src/jni_driver.cpp | 11 ++++++++--- .../java/com/panda3ds/pandroid/utils/Constants.java | 4 ++-- .../com/panda3ds/pandroid/view/PandaGlRenderer.java | 3 +++ .../panda3ds/pandroid/view/PandaGlSurfaceView.java | 5 ++++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp index 82720e2a..770e16da 100644 --- a/src/jni_driver.cpp +++ b/src/jni_driver.cpp @@ -15,19 +15,24 @@ bool romLoaded = false; #define AlberFunction(type, name) JNIEXPORT type JNICALL Java_com_panda3ds_pandroid_AlberDriver_##name +void throwException(JNIEnv* env, const char* message) { + jclass exceptionClass = env->FindClass("java/lang/RuntimeException"); + env->ThrowNew(exceptionClass, message); +} + extern "C" { AlberFunction(void, Initialize)(JNIEnv* env, jobject obj) { emulator = std::make_unique(); if (emulator->getRendererType() != RendererType::OpenGL) { - throw std::runtime_error("Renderer is not OpenGL"); + return throwException(env, "Renderer type is not OpenGL"); } renderer = static_cast(emulator->getRenderer()); hidService = &emulator->getServiceManager().getHID(); if (!gladLoadGLES2Loader(reinterpret_cast(eglGetProcAddress))) { - throw std::runtime_error("OpenGL ES init failed"); + return throwException(env, "Failed to load OpenGL ES 2.0"); } __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "OpenGL ES %d.%d", GLVersion.major, GLVersion.minor); @@ -36,6 +41,7 @@ AlberFunction(void, Initialize)(JNIEnv* env, jobject obj) { AlberFunction(void, RunFrame)(JNIEnv* env, jobject obj, jint fbo) { renderer->setFBO(fbo); + // TODO: don't reset entire state manager renderer->resetStateManager(); emulator->runFrame(); @@ -53,7 +59,6 @@ AlberFunction(jboolean, HasRomLoaded)(JNIEnv* env, jobject obj) { return romLoad AlberFunction(void, LoadRom)(JNIEnv* env, jobject obj, jstring path) { const char* pathStr = env->GetStringUTFChars(path, nullptr); romLoaded = emulator->loadROM(pathStr); - __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "Loading ROM %s, result: %d", pathStr, (int)romLoaded); env->ReleaseStringUTFChars(path, pathStr); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java index 6b480c23..d94164c7 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java @@ -15,8 +15,8 @@ public class Constants { public static final int INPUT_KEY_Y = 1 << 11; public static final int N3DS_WIDTH = 400; - public static final int N3DS_HALF_HEIGHT = 240; - public static final int N3DS_FULL_HEIGHT = N3DS_HALF_HEIGHT * 2; + public static final int N3DS_FULL_HEIGHT = 480; + public static final int N3DS_HALF_HEIGHT = N3DS_FULL_HEIGHT / 2; public static final String ACTIVITY_PARAMETER_PATH = "path"; public static final String LOG_TAG = "pandroid"; diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java index 128e9b4f..8dd350ce 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlRenderer.java @@ -69,6 +69,9 @@ public class PandaGlRenderer implements GLSurfaceView.Renderer, ConsoleRenderer screenFbo = generateBuffer[0]; glBindFramebuffer(GL_FRAMEBUFFER, screenFbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + Log.e(Constants.LOG_TAG, "Framebuffer is not complete"); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); AlberDriver.Initialize(); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java index eb65762d..c813294c 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaGlSurfaceView.java @@ -2,6 +2,7 @@ package com.panda3ds.pandroid.view; import android.content.Context; import android.opengl.GLSurfaceView; +import android.os.Debug; import androidx.annotation.NonNull; import com.panda3ds.pandroid.math.Vector2; @@ -17,7 +18,9 @@ public class PandaGlSurfaceView extends GLSurfaceView implements TouchScreenNode public PandaGlSurfaceView(Context context, String romPath) { super(context); setEGLContextClientVersion(3); - setDebugFlags(DEBUG_LOG_GL_CALLS); + if (Debug.isDebuggerConnected()) { + setDebugFlags(DEBUG_LOG_GL_CALLS); + } renderer = new PandaGlRenderer(romPath); setRenderer(renderer); } From 63a09dd51fb88013ef71612e7e01e78b415495f6 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:47:32 +0200 Subject: [PATCH 15/21] Android bonk --- src/jni_driver.cpp | 3 --- .../src/main/java/com/panda3ds/pandroid/app/GameActivity.java | 3 --- .../src/main/java/com/panda3ds/pandroid/app/MainActivity.java | 1 - .../src/main/java/com/panda3ds/pandroid/utils/PathUtils.java | 3 --- .../com/panda3ds/pandroid/view/PandaLayoutController.java | 2 -- .../panda3ds/pandroid/view/controller/ControllerLayout.java | 4 +--- .../com/panda3ds/pandroid/view/controller/ControllerNode.java | 1 - .../com/panda3ds/pandroid/view/controller/TouchEvent.java | 2 -- .../pandroid/view/controller/nodes/BasicControllerNode.java | 2 -- .../com/panda3ds/pandroid/view/controller/nodes/Joystick.java | 3 --- 10 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp index 770e16da..8f5c352e 100644 --- a/src/jni_driver.cpp +++ b/src/jni_driver.cpp @@ -63,11 +63,8 @@ AlberFunction(void, LoadRom)(JNIEnv* env, jobject obj, jstring path) { } AlberFunction(void, TouchScreenDown)(JNIEnv* env, jobject obj, jint x, jint y) { hidService->setTouchScreenPress((u16)x, (u16)y); } - AlberFunction(void, TouchScreenUp)(JNIEnv* env, jobject obj) { hidService->releaseTouchScreen(); } - AlberFunction(void, KeyUp)(JNIEnv* env, jobject obj, jint keyCode) { hidService->releaseKey((u32)keyCode); } - AlberFunction(void, KeyDown)(JNIEnv* env, jobject obj, jint keyCode) { hidService->pressKey((u32)keyCode); } AlberFunction(void, SetCirclepadAxis)(JNIEnv* env, jobject obj, jint x, jint y) { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index dfba96e5..2da73b97 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -17,7 +17,6 @@ import com.panda3ds.pandroid.view.PandaGlSurfaceView; import com.panda3ds.pandroid.view.PandaLayoutController; public class GameActivity extends BaseActivity { - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -31,14 +30,12 @@ public class GameActivity extends BaseActivity { } PandaGlSurfaceView pandaSurface = new PandaGlSurfaceView(this, intent.getStringExtra(Constants.ACTIVITY_PARAMETER_PATH)); - setContentView(R.layout.game_activity); ((FrameLayout) findViewById(R.id.panda_gl_frame)) .addView(pandaSurface, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); PandaLayoutController controllerLayout = findViewById(R.id.controller_layout); - controllerLayout.initialize(); ((CheckBox) findViewById(R.id.hide_screen_controller)).setOnCheckedChangeListener((buttonView, isChecked) -> findViewById(R.id.overlay_controller).setVisibility(isChecked ? View.VISIBLE : View.INVISIBLE)); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java index 368efe0e..f4fc27bf 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java @@ -40,7 +40,6 @@ public class MainActivity extends BaseActivity { } setContentView(R.layout.activity_main); - findViewById(R.id.load_rom).setOnClickListener(v -> { openFile(); }); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java index 0434e53f..9bfaa0e4 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/PathUtils.java @@ -83,10 +83,7 @@ public class PathUtils { } public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } - public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } - public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } - public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority()); } } \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java index 543ab840..617b407e 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/PandaLayoutController.java @@ -11,9 +11,7 @@ import com.panda3ds.pandroid.view.controller.nodes.Joystick; public class PandaLayoutController extends ControllerLayout { public PandaLayoutController(Context context) { super(context); } - public PandaLayoutController(Context context, AttributeSet attrs) { super(context, attrs); } - public PandaLayoutController(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public PandaLayoutController(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java index 4af28497..32451bc7 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerLayout.java @@ -19,9 +19,7 @@ public class ControllerLayout extends RelativeLayout { private final ArrayList controllerNodes = new ArrayList<>(); public ControllerLayout(Context context) { this(context, null); } - public ControllerLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public ControllerLayout(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public ControllerLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { @@ -131,7 +129,7 @@ public class ControllerLayout extends RelativeLayout { refreshChildren(); } - /*@TODO: Need replace that methods for prevent Android send events directly to children*/ + // TODO: Need to replace these methods to prevent Android sending events directly to children @Override public ArrayList getTouchables() { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java index e6c1dc92..7d45550a 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/ControllerNode.java @@ -17,6 +17,5 @@ public interface ControllerNode { default boolean isVisible() { return ((View) this).isShown(); } @NonNull Vector2 getSize(); - void onTouch(TouchEvent event); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java index 8c940414..6b82d201 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/TouchEvent.java @@ -5,9 +5,7 @@ public class TouchEvent { private final float x, y; public float getX() { return x; } - public float getY() { return y; } - public TouchType getAction() { return action; } public TouchEvent(float x, float y, TouchType action) { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java index 224be9a4..d196c7ec 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/BasicControllerNode.java @@ -9,8 +9,6 @@ import com.panda3ds.pandroid.view.controller.ControllerNode; public abstract class BasicControllerNode extends AppCompatTextView implements ControllerNode { public BasicControllerNode(@NonNull Context context) { super(context); } - public BasicControllerNode(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } - public BasicControllerNode(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java index b63e9d66..cf33afb6 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/controller/nodes/Joystick.java @@ -20,11 +20,9 @@ public class Joystick extends BasicControllerNode implements ControllerNode { private int width = 0; private int height = 0; - private JoystickListener joystickListener; public Joystick(Context context) { this(context, null); } - public Joystick(Context context, AttributeSet attrs) { this(context, attrs, 0); } public Joystick(Context context, AttributeSet attrs, int defStyleAttr) { @@ -99,7 +97,6 @@ public class Joystick extends BasicControllerNode implements ControllerNode { y = Math.max(0, Math.min(middle * 2, y)); axisX = ((x - middle) / middle); - axisY = ((y - middle) / middle); if (event.getAction() == TouchType.ACTION_UP) { From 79079f35e2d99986aa9585b42dc55bd72e444729 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:24:43 +0200 Subject: [PATCH 16/21] [Qt] Preparations before making the Qt builds public --- src/panda_qt/main_window.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panda_qt/main_window.cpp b/src/panda_qt/main_window.cpp index 804dc63a..2e4963d3 100644 --- a/src/panda_qt/main_window.cpp +++ b/src/panda_qt/main_window.cpp @@ -23,7 +23,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) auto aboutMenu = menuBar->addMenu(tr("About")); // Create and bind actions for them - auto pandaAction = fileMenu->addAction(tr("panda...")); + auto pandaAction = fileMenu->addAction(tr("Load game")); connect(pandaAction, &QAction::triggered, this, &MainWindow::selectROM); auto pauseAction = emulationMenu->addAction(tr("Pause")); @@ -341,4 +341,4 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event) { case Qt::Key_Return: releaseKey(HID::Keys::Start); break; case Qt::Key_Backspace: releaseKey(HID::Keys::Select); break; } -} \ No newline at end of file +} From 6527df72111234db91574ff547d1892f134791e1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:33:13 +0200 Subject: [PATCH 17/21] Add panda-qt links --- readme.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8667862d..0d9e7f7b 100644 --- a/readme.md +++ b/readme.md @@ -13,14 +13,23 @@ Join our Discord server by pressing on the banner below, or find us on other pla ![screenshot1](docs/img/KirbyRobobot.png) ![screenshot2](docs/img/OoT_Title.png) ![screenshot3](docs/img/pokegang.png) # Download -You can download stable builds from the Releases tab, or you can download the latest build from the table below +You can download stable builds from the Releases tab, or you can download the latest build from the tables below. Panda3DS comes in two flavours: A minimal SDL frontend, which does not have a GUI, and an experimental Qt frontend +SDL builds (No GUI): |Platform|Status|Download| |--------|------------|--------| |Windows build|[![Windows Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml)|[Windows Executable](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Windows_Build/master/Windows%20executable.zip)| |MacOS build|[![MacOS Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/MacOS_Build/master/MacOS%20Alber%20App%20Bundle.zip)| |Linux build|[![Linux Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml)|[Linux AppImage](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Linux_AppImage_Build/master/Linux%20executable.zip)| +Qt builds: +|Platform|Status|Download| +|--------|------------|--------| +|Windows build|[![Windows Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml)|[Windows Executable](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Windows%20executable.zip)| +|MacOS build|[![MacOS Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/MacOS%20Alber%20App%20Bundle.zip)| +|Linux build|[![Linux Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml)|[Linux AppImage](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Linux%20executable.zip)| + + # Compatibility Panda3DS is still in the early stages of development. Many games boot, many don't. Lots of games have at least some hilariously broken graphics, audio is not supported, and some QoL features (including a GUI) are missing. However, even more things are implemented, such as most of the 3DS core required to play games, and various neat features, such as Lua scripting, discord bot support, support for some system apps, cheats, controller support, WIP amiibo support and many more! The emulator is constantly evolving, so make sure to take a peek every now and then! From 09f6d46aaa186e43dfc19c1a672e0f02aaf7e8c6 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:33:43 +0200 Subject: [PATCH 18/21] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0d9e7f7b..152e3550 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ Join our Discord server by pressing on the banner below, or find us on other pla ![screenshot1](docs/img/KirbyRobobot.png) ![screenshot2](docs/img/OoT_Title.png) ![screenshot3](docs/img/pokegang.png) # Download -You can download stable builds from the Releases tab, or you can download the latest build from the tables below. Panda3DS comes in two flavours: A minimal SDL frontend, which does not have a GUI, and an experimental Qt frontend +You can download stable builds from the Releases tab, or you can download the latest build from the tables below. Panda3DS comes in two flavours: A minimal SDL frontend, which does not have a GUI, and an experimental Qt frontend. SDL builds (No GUI): |Platform|Status|Download| From 29c946af99fb0a24be0840e240ded145f26486be Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:34:20 +0200 Subject: [PATCH 19/21] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 152e3550..63be3921 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ Join our Discord server by pressing on the banner below, or find us on other pla ![screenshot1](docs/img/KirbyRobobot.png) ![screenshot2](docs/img/OoT_Title.png) ![screenshot3](docs/img/pokegang.png) # Download -You can download stable builds from the Releases tab, or you can download the latest build from the tables below. Panda3DS comes in two flavours: A minimal SDL frontend, which does not have a GUI, and an experimental Qt frontend. +You can download stable builds from the Releases tab, or you can download the latest build from the tables below. Panda3DS comes in two flavours: A minimal SDL frontend, which does not have a GUI, and an experimental Qt 6 frontend with a proper user interface. SDL builds (No GUI): |Platform|Status|Download| From 8afda8da5b056e1658bcbb7862181f6d4dd7f73c Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:37:17 +0200 Subject: [PATCH 20/21] Update readme.md --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 63be3921..6e4d5ac0 100644 --- a/readme.md +++ b/readme.md @@ -25,9 +25,9 @@ SDL builds (No GUI): Qt builds: |Platform|Status|Download| |--------|------------|--------| -|Windows build|[![Windows Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml)|[Windows Executable](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Windows%20executable.zip)| -|MacOS build|[![MacOS Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/MacOS%20Alber%20App%20Bundle.zip)| -|Linux build|[![Linux Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml)|[Linux AppImage](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Linux%20executable.zip)| +|Windows build|[![Qt Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml)|[Windows Executable](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Windows%20executable.zip)| +|MacOS build|[![Qt Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml)|[MacOS App Bundle](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/MacOS%20Alber%20App%20Bundle.zip)| +|Linux build|[![Qt Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml/badge.svg)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Qt_Build.yml)|[Linux AppImage](https://nightly.link/wheremyfoodat/Panda3DS/workflows/Qt_Build/master/Linux%20executable.zip)| # Compatibility From 0cccde79f4f5fb4eb06b5c8f315be5c998e392fa Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:45:53 +0200 Subject: [PATCH 21/21] Specify the SDL/Qt frontend split only happens on PC --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6e4d5ac0..9e27194c 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,7 @@ Join our Discord server by pressing on the banner below, or find us on other pla ![screenshot1](docs/img/KirbyRobobot.png) ![screenshot2](docs/img/OoT_Title.png) ![screenshot3](docs/img/pokegang.png) # Download -You can download stable builds from the Releases tab, or you can download the latest build from the tables below. Panda3DS comes in two flavours: A minimal SDL frontend, which does not have a GUI, and an experimental Qt 6 frontend with a proper user interface. +You can download stable builds from the Releases tab, or you can download the latest build from the tables below. Additionally, Panda3DS comes in 2 flavours on PC: A minimal SDL frontend, which does not have a GUI, and an experimental Qt 6 frontend with a proper user interface. SDL builds (No GUI): |Platform|Status|Download|