Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
wheremyfoodat committed Dec 13, 2023
2 parents 101cc4d + 0cccde7 commit a9a31c3
Show file tree
Hide file tree
Showing 77 changed files with 2,237 additions and 14 deletions.
89 changes: 89 additions & 0 deletions .github/workflows/Android_Build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Android Build

on:
push:
branches:
- master
pull_request:

env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release

jobs:
x64:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Fetch submodules
run: git submodule update --init --recursive

- name: Setup Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: latest
vulkan-use-cache: true
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang

- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'zulu' # See 'Supported distributions' for available options
java-version: '17'

- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DBUILD_HYDRA_CORE=1 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=x86_64 -DENABLE_VULKAN=0

- name: Build
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
mv ./build/libAlber.so ./src/pandroid/app/src/main/jniLibs/x86_64/
cd src/pandroid
./gradlew assembleDebug
cd ../..
- name: Upload executable
uses: actions/upload-artifact@v2
with:
name: Android APK (x86-64)
path: './src/pandroid/app/build/outputs/apk/debug/app-debug.apk'

arm64:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Fetch submodules
run: git submodule update --init --recursive

- name: Setup Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: latest
vulkan-use-cache: true
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang

- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'zulu' # See 'Supported distributions' for available options
java-version: '17'

- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DBUILD_HYDRA_CORE=1 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DENABLE_VULKAN=0 -DCMAKE_CXX_FLAGS="-march=armv8.1-a+crypto"

- name: Build
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
mv ./build/libAlber.so ./src/pandroid/app/src/main/jniLibs/arm64-v8a/
cd src/pandroid
./gradlew assembleDebug
cd ../..
- name: Upload executable
uses: actions/upload-artifact@v2
with:
name: Android APK (arm64)
path: './src/pandroid/app/build/outputs/apk/debug/app-debug.apk'

36 changes: 25 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 src/panda_qt/config_window.cpp)
set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp include/panda_qt/config_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 "")
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 src/panda_qt/config_window.cpp)
set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp include/panda_qt/config_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 "")
endif()
endif()

set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp
Expand Down Expand Up @@ -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)
Expand All @@ -386,11 +392,19 @@ else()
add_executable(Alber ${ALL_SOURCES})
endif()

if(ANDROID)
target_link_libraries(Alber PRIVATE EGL 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")
Expand Down
11 changes: 10 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. 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|
|--------|------------|--------|
|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|[![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
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!

Expand Down
2 changes: 2 additions & 0 deletions src/emulator.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "emulator.hpp"

#ifndef __ANDROID__
#include <SDL_filesystem.h>
#endif

#include <fstream>

Expand Down
76 changes: 76 additions & 0 deletions src/jni_driver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <EGL/egl.h>
#include <android/log.h>
#include <jni.h>

#include <stdexcept>

#include "emulator.hpp"
#include "renderer_gl/renderer_gl.hpp"
#include "services/hid.hpp"

std::unique_ptr<Emulator> emulator = nullptr;
HIDService* hidService = nullptr;
RendererGL* renderer = nullptr;
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<Emulator>();

if (emulator->getRendererType() != RendererType::OpenGL) {
return throwException(env, "Renderer type is not OpenGL");
}

renderer = static_cast<RendererGL*>(emulator->getRenderer());
hidService = &emulator->getServiceManager().getHID();

if (!gladLoadGLES2Loader(reinterpret_cast<GLADloadproc>(eglGetProcAddress))) {
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);
emulator->initGraphicsContext(nullptr);
}

AlberFunction(void, RunFrame)(JNIEnv* env, jobject obj, jint fbo) {
renderer->setFBO(fbo);
// TODO: don't reset entire state manager
renderer->resetStateManager();
emulator->runFrame();

hidService->updateInputs(emulator->getTicks());
}

AlberFunction(void, Finalize)(JNIEnv* env, jobject obj) {
emulator = nullptr;
hidService = nullptr;
renderer = nullptr;
}

AlberFunction(jboolean, HasRomLoaded)(JNIEnv* env, jobject obj) { return romLoaded; }

AlberFunction(void, LoadRom)(JNIEnv* env, jobject obj, jstring path) {
const char* pathStr = env->GetStringUTFChars(path, nullptr);
romLoaded = emulator->loadROM(pathStr);
env->ReleaseStringUTFChars(path, pathStr);
}

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) {
hidService->setCirclepadX((s16)x);
hidService->setCirclepadY((s16)y);
}
}

#undef AlberFunction
4 changes: 2 additions & 2 deletions src/panda_qt/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down Expand Up @@ -252,4 +252,4 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event) {
case Qt::Key_Return: releaseKey(HID::Keys::Start); break;
case Qt::Key_Backspace: releaseKey(HID::Keys::Select); break;
}
}
}
15 changes: 15 additions & 0 deletions src/pandroid/.gitignore
Original file line number Diff line number Diff line change
@@ -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
42 changes: 42 additions & 0 deletions src/pandroid/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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")
}
21 changes: 21 additions & 0 deletions src/pandroid/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
37 changes: 37 additions & 0 deletions src/pandroid/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>

<uses-feature
android:required="true"
android:glEsVersion="0x0030001"/>

<application
android:requestLegacyExternalStorage="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Pandroid"
tools:targetApi="31">
<activity
android:name=".app.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".app.GameActivity"
android:configChanges="screenSize|screenLayout|orientation|density|uiMode">
</activity>
</application>
</manifest>
Loading

0 comments on commit a9a31c3

Please sign in to comment.