diff --git a/Source/Android/Bridge/Bridge.vcxproj b/Source/Android/Bridge/Bridge.vcxproj new file mode 100644 index 000000000..f6dff789f --- /dev/null +++ b/Source/Android/Bridge/Bridge.vcxproj @@ -0,0 +1,48 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {593B00E6-1987-415D-A62C-26533FC3E95C} + Bridge + JniBridge + + + StaticLibrary + + + + + + + + + + NotUsing + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Android/Bridge/Bridge.vcxproj.filters b/Source/Android/Bridge/Bridge.vcxproj.filters new file mode 100644 index 000000000..bd0537796 --- /dev/null +++ b/Source/Android/Bridge/Bridge.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Source/Android/Bridge/JavaBridge.cpp b/Source/Android/Bridge/JavaBridge.cpp new file mode 100644 index 000000000..c2a54ac1d --- /dev/null +++ b/Source/Android/Bridge/JavaBridge.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +* * +* Project 64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include "JavaBridge.h" +#include "jniBridge.h" + +#ifdef ANDROID +JavaBridge::JavaBridge(JavaVM* vm) : + m_vm(vm) +{ + JNIEnv *env = Android_JNI_GetEnv(); + jclass GalleryActivityClass = env->FindClass("emu/project64/GalleryActivity"); + if (GalleryActivityClass != NULL) + { + m_GalleryActivityClass = (jclass)env->NewGlobalRef(GalleryActivityClass); + } + jclass NotifierClass = env->FindClass("emu/project64/util/Notifier"); + if (NotifierClass != NULL) + { + m_NotifierClass = (jclass)env->NewGlobalRef(NotifierClass); + } +} + +void JavaBridge::GfxThreadInit() +{ + JNIEnv *env = Android_JNI_GetEnv(); + if (g_GLThread != NULL && env != NULL) + { + jclass GLThreadClass = env->GetObjectClass(g_GLThread); + jmethodID midThreadStarting = env->GetMethodID(GLThreadClass, "ThreadStarting", "()V"); + env->CallVoidMethod(g_GLThread, midThreadStarting); + env->DeleteLocalRef(GLThreadClass); + } +} + +void JavaBridge::GfxThreadDone() +{ + JNIEnv *env = Android_JNI_GetEnv(); + if (g_GLThread != NULL && env != NULL) + { + jclass GLThreadClass = env->GetObjectClass(g_GLThread); + jmethodID midThreadExiting = env->GetMethodID(GLThreadClass, "ThreadExiting", "()V"); + env->CallVoidMethod(g_GLThread, midThreadExiting); + env->DeleteLocalRef(GLThreadClass); + } +} + +void JavaBridge::SwapWindow() +{ + JNIEnv *env = Android_JNI_GetEnv(); + if (g_GLThread != NULL && env != NULL) + { + jclass GLThreadClass = env->GetObjectClass(g_GLThread); + jmethodID midSwapBuffers = env->GetMethodID(GLThreadClass, "SwapBuffers", "()V"); + env->CallVoidMethod(g_GLThread, midSwapBuffers); + env->DeleteLocalRef(GLThreadClass); + } +} + +void JavaBridge::RomListReset(void) +{ + JNIEnv *env = Android_JNI_GetEnv(); + if (env) + { + jmethodID midRomListReset = env->GetStaticMethodID(m_GalleryActivityClass, "RomListReset", "()V"); + env->CallStaticVoidMethod(m_GalleryActivityClass, midRomListReset); + } +} + +void JavaBridge::RomListAddItem(const char * FullFileName, const char * FileName, const char * GoodName, uint32_t TextColor) +{ + JNIEnv *env = Android_JNI_GetEnv(); + if (env) + { + jmethodID midRomListAddItem = env->GetStaticMethodID(m_GalleryActivityClass, "RomListAddItem", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V"); + if (midRomListAddItem != NULL) + { + jstring j_FullFileName = env->NewStringUTF(FullFileName); + jstring j_FileName = env->NewStringUTF(FileName); + jstring j_GoodName = env->NewStringUTF(GoodName); + env->CallStaticVoidMethod(m_GalleryActivityClass, midRomListAddItem, j_FullFileName, j_FileName, j_GoodName, TextColor); + env->DeleteLocalRef(j_FullFileName); + env->DeleteLocalRef(j_FileName); + env->DeleteLocalRef(j_GoodName); + } + } +} + +void JavaBridge::RomListLoaded(void) +{ + JNIEnv *env = Android_JNI_GetEnv(); + if (env) + { + jmethodID midRomListLoadDone = env->GetStaticMethodID(m_GalleryActivityClass, "RomListLoadDone", "()V"); + env->CallStaticVoidMethod(m_GalleryActivityClass, midRomListLoadDone); + } +} + +void JavaBridge::DisplayMessage(const char * Message) +{ + JNIEnv *env = Android_JNI_GetEnv(); + if (env) + { + jstring j_Message = env->NewStringUTF(Message); + jmethodID midShowToast = env->GetStaticMethodID(m_NotifierClass, "showToast", "(Landroid/app/Activity;Ljava/lang/String;)V"); + env->CallStaticVoidMethod(m_NotifierClass, midShowToast,g_Activity,j_Message); + env->DeleteLocalRef(j_Message); + } +} + +#endif \ No newline at end of file diff --git a/Source/Android/Bridge/JavaBridge.h b/Source/Android/Bridge/JavaBridge.h new file mode 100644 index 000000000..7812cd482 --- /dev/null +++ b/Source/Android/Bridge/JavaBridge.h @@ -0,0 +1,37 @@ +#pragma once + +#ifdef ANDROID + +#include +#include + +class JavaBridge : + public RenderWindow +{ +public: + JavaBridge (JavaVM* vm); + + //Render window functions + void GfxThreadInit(); + void GfxThreadDone(); + void SwapWindow(); + + //Rom List + void RomListReset(void); + void RomListAddItem(const char * FullFileName, const char * FileName, const char * GoodName, uint32_t TextColor ); + void RomListLoaded(void); + + //Notification + void DisplayMessage(const char * Message); + +private: + JavaBridge(void); // Disable default constructor + JavaBridge(const JavaBridge&); // Disable copy constructor + JavaBridge& operator=(const JavaBridge&); // Disable assignment + + JavaVM* m_vm; + jclass m_GalleryActivityClass; + jclass m_NotifierClass; +}; + +#endif \ No newline at end of file diff --git a/Source/Android/Bridge/JavaRomList.cpp b/Source/Android/Bridge/JavaRomList.cpp new file mode 100644 index 000000000..4e0ad860f --- /dev/null +++ b/Source/Android/Bridge/JavaRomList.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +* * +* Project 64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include "JavaRomList.h" +#include "JavaBridge.h" + +#ifdef ANDROID +extern JavaBridge * g_JavaBridge; + +void CJavaRomList::RomListReset(void) +{ + if (g_JavaBridge) + { + g_JavaBridge->RomListReset(); + } +} + +void CJavaRomList::RomAddedToList(int32_t ListPos) +{ + if (g_JavaBridge) + { + ROM_INFO * pRomInfo = &m_RomInfo[ListPos]; + g_JavaBridge->RomListAddItem(pRomInfo->szFullFileName, pRomInfo->FileName, pRomInfo->GoodName, pRomInfo->TextColor); + } +} + +void CJavaRomList::RomListLoaded(void) +{ + if (g_JavaBridge) + { + g_JavaBridge->RomListLoaded(); + } +} + +#endif \ No newline at end of file diff --git a/Source/Android/Bridge/JavaRomList.h b/Source/Android/Bridge/JavaRomList.h new file mode 100644 index 000000000..b1fcb5950 --- /dev/null +++ b/Source/Android/Bridge/JavaRomList.h @@ -0,0 +1,11 @@ +#pragma once +#include + +class CJavaRomList : + public CRomList +{ +public: + void RomListReset(void); + void RomAddedToList(int32_t ListPos); + void RomListLoaded(void); +}; \ No newline at end of file diff --git a/Source/Android/Bridge/NotificationClass.cpp b/Source/Android/Bridge/NotificationClass.cpp new file mode 100644 index 000000000..2f344fc83 --- /dev/null +++ b/Source/Android/Bridge/NotificationClass.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include +#include +#include +#include +#include "NotificationClass.h" +#include "JavaBridge.h" +#if defined(ANDROID) +#include + +extern JavaBridge * g_JavaBridge; +#endif + +CNotificationImp & Notify(void) +{ + static CNotificationImp g_Notify; + return g_Notify; +} + +CNotificationImp::CNotificationImp() : + m_NextMsg(0) +{ +} + +CNotificationImp::~CNotificationImp() +{ +} + +void CNotificationImp::DisplayError(const char * /*Message*/) const +{ +} + +void CNotificationImp::DisplayError(LanguageStringID /*StringID*/) const +{ +} + +void CNotificationImp::FatalError(LanguageStringID /*StringID*/) const +{ +} + +void CNotificationImp::DisplayMessage(int DisplayTime, LanguageStringID StringID) const +{ + DisplayMessage(DisplayTime, g_Lang->GetString(StringID).c_str()); +} + +void CNotificationImp::FatalError(const char * Message) const +{ + DisplayMessage(0,Message); +} + +//User Feedback +void CNotificationImp::DisplayMessage(int DisplayTime, const char * Message) const +{ +#ifdef ANDROID + __android_log_print(ANDROID_LOG_VERBOSE, "PJ64-Bridge", "%s", Message); + + if (g_JavaBridge == NULL) { return; } + + /*if (m_NextMsg > 0 || DisplayTime > 0) + { + time_t Now = time(NULL); + if (DisplayTime == 0 && Now < m_NextMsg) + { + return; + } + if (DisplayTime > 0) + { + m_NextMsg = Now + DisplayTime; + } + if (m_NextMsg == 0) + { + m_NextMsg = 0; + } + }*/ + + g_JavaBridge->DisplayMessage(Message); +#endif +} + +void CNotificationImp::DisplayMessage2(const char * /*Message*/) const +{ +} + +// Ask a Yes/No Question to the user, yes = true, no = false +bool CNotificationImp::AskYesNoQuestion(const char * /*Question*/) const +{ + return false; +} + +void CNotificationImp::BreakPoint(const char * FileName, int32_t LineNumber) +{ + if (g_Settings->LoadBool(Debugger_Enabled)) + { + DisplayError(stdstr_f("Break point found at\n%s\n%d", FileName, LineNumber).c_str()); +#ifndef _WIN32 + __builtin_trap(); +#endif +#ifdef tofix + if (g_BaseSystem) + { + g_BaseSystem->CloseCpu(); + } +#endif + } + else + { + DisplayError("Fatal Error: Stopping emulation"); +#ifdef tofix + if (g_BaseSystem) + { + g_BaseSystem->CloseCpu(); + } +#endif + } +} + +void CNotificationImp::AppInitDone(void) +{ +} + +bool CNotificationImp::ProcessGuiMessages(void) const +{ + return false; +} + +void CNotificationImp::ChangeFullScreen(void) const +{ +} \ No newline at end of file diff --git a/Source/Android/Bridge/NotificationClass.h b/Source/Android/Bridge/NotificationClass.h new file mode 100644 index 000000000..f51b51584 --- /dev/null +++ b/Source/Android/Bridge/NotificationClass.h @@ -0,0 +1,50 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#pragma once + +#include + +class CNotificationImp : + public CNotification +{ +public: + CNotificationImp(void); + virtual ~CNotificationImp(); + + //Error Messages + void DisplayError(const char * Message) const; + void DisplayError(LanguageStringID StringID) const; + + void FatalError(const char * Message) const; + void FatalError(LanguageStringID StringID) const; + + //User Feedback + void DisplayMessage(int DisplayTime, const char * Message) const; + void DisplayMessage(int DisplayTime, LanguageStringID StringID) const; + + void DisplayMessage2(const char * Message) const; + + // Ask a Yes/No Question to the user, yes = true, no = false + bool AskYesNoQuestion(const char * Question) const; + void BreakPoint(const char * FileName, int32_t LineNumber); + + void AppInitDone(void); + bool ProcessGuiMessages(void) const; + void ChangeFullScreen(void) const; + +private: + CNotificationImp(const CNotificationImp&); // Disable copy constructor + CNotificationImp& operator=(const CNotificationImp&); // Disable assignment + + mutable time_t m_NextMsg; +}; + +CNotificationImp & Notify(void); \ No newline at end of file diff --git a/Source/Android/Bridge/UISettings.cpp b/Source/Android/Bridge/UISettings.cpp new file mode 100644 index 000000000..eccdbbbff --- /dev/null +++ b/Source/Android/Bridge/UISettings.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include +#include +#include "UISettings.h" + +void RegisterUISettings(void) +{ + g_Settings->AddHandler((SettingID)(FirstUISettings + Asserts_Version), new CSettingTypeApplication("", "Asserts Version", (uint32_t)0)); + g_Settings->AddHandler((SettingID)(FirstUISettings + Screen_Orientation), new CSettingTypeApplication("", "Screen Orientation", (uint32_t)0)); +} + +void UISettingsSaveBool(UISettingID Type, bool Value) +{ + g_Settings->SaveBool((SettingID)(FirstUISettings + Type), Value); + CSettings::FlushSettings(g_Settings); +} + +void UISettingsSaveDword(UISettingID Type, uint32_t Value) +{ + g_Settings->SaveDword((SettingID)(FirstUISettings + Type), Value); + CSettings::FlushSettings(g_Settings); +} + +bool UISettingsLoadBool(UISettingID Type) +{ + return g_Settings->LoadBool((SettingID)(FirstUISettings + Type)); +} + +uint32_t UISettingsLoadDword(UISettingID Type) +{ + return g_Settings->LoadDword((SettingID)(FirstUISettings + Type)); +} + diff --git a/Source/Android/Bridge/UISettings.h b/Source/Android/Bridge/UISettings.h new file mode 100644 index 000000000..e5bb4d61a --- /dev/null +++ b/Source/Android/Bridge/UISettings.h @@ -0,0 +1,44 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#pragma once +#include +#include + +enum UISettingID +{ + Asserts_Version, + Screen_Orientation, +}; + +void RegisterUISettings(void); + +void UISettingsSaveBool(UISettingID Type, bool Value); +void UISettingsSaveDword(UISettingID Type, uint32_t Value); + +bool UISettingsLoadBool(UISettingID Type); +uint32_t UISettingsLoadDword(UISettingID Type); + +/* +void UISettingsSaveBoolIndex(UISettingID Type, int32_t index, bool Value); +void UISettingsSaveDwordIndex(UISettingID Type, int32_t index, uint32_t Value); +void UISettingsSaveString(UISettingID Type, const std::string & Value); +void UISettingsSaveStringIndex(UISettingID Type, int32_t index, const std::string & Value); + +void UISettingsDeleteSettingIndex(UISettingID Type, int32_t index); + +bool UISettingsLoadBoolIndex(UISettingID Type, int32_t index); +bool UISettingsLoadDword(UISettingID Type, uint32_t & Value); +bool UISettingsLoadDwordIndex(UISettingID Type, int index, uint32_t & Value); +bool UISettingsLoadStringIndex(UISettingID Type, int32_t index, std::string & Value); +std::string UISettingsLoadStringIndex(UISettingID Type, int32_t index); +std::string UISettingsLoadStringVal(UISettingID Type); +bool UISettingsLoadStringVal(UISettingID Type, char * Buffer, int32_t BufferSize); +*/ \ No newline at end of file diff --git a/Source/Android/Bridge/jniBridge.cpp b/Source/Android/Bridge/jniBridge.cpp new file mode 100644 index 000000000..b23d1723b --- /dev/null +++ b/Source/Android/Bridge/jniBridge.cpp @@ -0,0 +1,358 @@ +/**************************************************************************** +* * +* Project 64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include +#include "NotificationClass.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "jniBridge.h" +#include "jniBridgeSettings.h" +#include "JavaBridge.h" +#include "UISettings.h" +#include "JavaRomList.h" + +#ifdef _WIN32 +#define EXPORT extern "C" __declspec(dllexport) +#define CALL __cdecl +#else +#define EXPORT extern "C" __attribute__((visibility("default"))) +#define CALL +#endif + +CJniBridegSettings * JniBridegSettings = NULL; +CJavaRomList * g_JavaRomList = NULL; + +#ifdef ANDROID +#include + +class AndroidLogger : public CTraceModule +{ + void Write(uint32_t module, uint8_t severity, const char * file, int line, const char * function, const char * Message) + { + switch (severity) + { + case TraceError: __android_log_print(ANDROID_LOG_ERROR, TraceModule(module), "%05d: %s: %s",CThread::GetCurrentThreadId(),function,Message); break; + case TraceWarning: __android_log_print(ANDROID_LOG_WARN, TraceModule(module), "%05d: %s: %s",CThread::GetCurrentThreadId(),function,Message); break; + case TraceNotice: __android_log_print(ANDROID_LOG_INFO, TraceModule(module), "%05d: %s: %s",CThread::GetCurrentThreadId(),function,Message); break; + case TraceInfo: __android_log_print(ANDROID_LOG_INFO, TraceModule(module), "%05d: %s: %s",CThread::GetCurrentThreadId(),function,Message); break; + case TraceDebug: __android_log_print(ANDROID_LOG_DEBUG, TraceModule(module), "%05d: %s: %s",CThread::GetCurrentThreadId(),function,Message); break; + case TraceVerbose: __android_log_print(ANDROID_LOG_VERBOSE, TraceModule(module), "%05d: %s: %s",CThread::GetCurrentThreadId(),function,Message); break; + default: __android_log_print(ANDROID_LOG_UNKNOWN, TraceModule(module), "%05d: %s: %s",CThread::GetCurrentThreadId(),function,Message); break; + } + } +}; +AndroidLogger * g_Logger = NULL; +static pthread_key_t g_ThreadKey; +static JavaVM* g_JavaVM = NULL; +JavaBridge * g_JavaBridge = NULL; +jobject g_Activity = NULL; +jobject g_GLThread = NULL; + +static void Android_JNI_ThreadDestroyed(void*); +static void Android_JNI_SetupThread(void); + +EXPORT jint CALL JNI_OnLoad(JavaVM* vm, void* reserved) +{ + __android_log_print(ANDROID_LOG_INFO, "jniBridge", "JNI_OnLoad called"); + g_JavaVM = vm; + + JNIEnv *env; + if (g_JavaVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) + { + __android_log_print(ANDROID_LOG_ERROR, "jniBridge", "Failed to get the environment using GetEnv()"); + return -1; + } + /* + * Create mThreadKey so we can keep track of the JNIEnv assigned to each thread + * Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this + */ + if (pthread_key_create(&g_ThreadKey, Android_JNI_ThreadDestroyed) != 0) + { + __android_log_print(ANDROID_LOG_ERROR, "jniBridge", "Error initializing pthread key"); + } + Android_JNI_SetupThread(); + return JNI_VERSION_1_4; +} + +EXPORT jboolean CALL Java_emu_project64_jni_NativeExports_appInit(JNIEnv* env, jclass cls, jstring BaseDir) +{ + if (g_Logger == NULL) + { + g_Logger = new AndroidLogger(); + } + TraceAddModule(g_Logger); + + Notify().DisplayMessage(10, " ____ _ __ _____ __ __"); + Notify().DisplayMessage(10, " / __ \\_________ (_)__ _____/ /_/ ___// // /"); + Notify().DisplayMessage(10, " / /_/ / ___/ __ \\ / / _ \\/ ___/ __/ __ \\/ // /_"); + Notify().DisplayMessage(10, " / ____/ / / /_/ / / / __/ /__/ /_/ /_/ /__ __/"); + Notify().DisplayMessage(10, "/_/ /_/ \\____/_/ /\\___/\\___/\\__/\\____/ /_/"); + Notify().DisplayMessage(10, " /___/"); + Notify().DisplayMessage(10, "http://www.pj64-emu.com/"); + Notify().DisplayMessage(10, stdstr_f("%s Version %s", VER_FILE_DESCRIPTION_STR, VER_FILE_VERSION_STR).c_str()); + Notify().DisplayMessage(10, ""); + + if (g_JavaVM == NULL) + { + Notify().DisplayError("No java VM"); + return false; + } + + const char *baseDir = env->GetStringUTFChars(BaseDir, 0); + bool res = AppInit(&Notify(), baseDir, 0, NULL); + + env->ReleaseStringUTFChars(BaseDir, baseDir); + if (res) + { + g_JavaBridge = new JavaBridge(g_JavaVM); + g_Plugins->SetRenderWindows(g_JavaBridge, NULL); + + JniBridegSettings = new CJniBridegSettings(); + + RegisterUISettings(); + } + else + { + AppCleanup(); + } + return res; +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_SettingsSaveBool(JNIEnv* env, jclass cls, int Type, jboolean Value) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Saving %d value: %s",Type,Value ? "true" : "false"); + g_Settings->SaveBool((SettingID)Type, Value); + WriteTrace(TraceUserInterface, TraceDebug, "Saved"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_SettingsSaveDword(JNIEnv* env, jclass cls, int Type, int Value) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Saving %d value: 0x%X",Type,Value); + g_Settings->SaveDword((SettingID)Type, Value); + WriteTrace(TraceUserInterface, TraceDebug, "Saved"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_SettingsSaveString(JNIEnv* env, jclass cls, int Type, jstring Buffer) +{ + const char *value = env->GetStringUTFChars(Buffer, 0); + WriteTrace(TraceUserInterface, TraceDebug, "Saving %d value: %s",Type,value); + g_Settings->SaveString((SettingID)Type, value); + WriteTrace(TraceUserInterface, TraceDebug, "Saved"); + env->ReleaseStringUTFChars(Buffer, value); +} + +EXPORT jboolean CALL Java_emu_project64_jni_NativeExports_SettingsLoadBool(JNIEnv* env, jclass cls, int Type) +{ + return g_Settings->LoadBool((SettingID)Type); +} + +EXPORT jint CALL Java_emu_project64_jni_NativeExports_SettingsLoadDword(JNIEnv* env, jclass cls, int Type) +{ + return g_Settings->LoadDword((SettingID)Type); +} + +EXPORT jstring CALL Java_emu_project64_jni_NativeExports_SettingsLoadString(JNIEnv* env, jclass cls, int Type) +{ + return env->NewStringUTF(g_Settings->LoadStringVal((SettingID)Type).c_str()); +} + +EXPORT jboolean CALL Java_emu_project64_jni_NativeExports_IsSettingSet(JNIEnv* env, jclass cls, int Type) +{ + return g_Settings->IsSettingSet((SettingID)Type); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_LoadRomList(JNIEnv* env, jclass cls) +{ + WriteTrace(TraceUserInterface, TraceDebug, "start"); + if (g_JavaRomList == NULL) + { + g_JavaRomList = new CJavaRomList; + } + g_JavaRomList->LoadRomList(); + + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_LoadGame(JNIEnv* env, jclass cls, jstring FileLoc, jobject activity, jobject GLThread) +{ + g_Activity = env->NewGlobalRef(activity); + g_GLThread = env->NewGlobalRef(GLThread); + const char *fileLoc = env->GetStringUTFChars(FileLoc, 0); + WriteTrace(TraceUserInterface, TraceDebug, "FileLoc: %s",fileLoc); + g_Settings->SaveBool(Setting_AutoStart,false); + CN64System::RunFileImage(fileLoc); + env->ReleaseStringUTFChars(FileLoc, fileLoc); + WriteTrace(TraceUserInterface, TraceDebug, "Image loaded"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_StartGame(JNIEnv* env, jclass cls) +{ + g_BaseSystem->StartEmulation(true); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_RefreshRomDir(JNIEnv* env, jclass cls, jstring RomDir, jboolean Recursive) +{ + const char *romDir = env->GetStringUTFChars(RomDir, 0); + WriteTrace(TraceUserInterface, TraceDebug, "romDir = %s Recursive = %s", romDir, Recursive ? "true" : "false"); + g_Settings->SaveString(RomList_GameDir,romDir); + g_Settings->SaveBool(RomList_GameDirRecursive,Recursive); + env->ReleaseStringUTFChars(RomDir, romDir); + + if (g_JavaRomList == NULL) + { + g_JavaRomList = new CJavaRomList; + } + g_JavaRomList->RefreshRomList(); + + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_ExternalEvent(JNIEnv* env, jclass cls, int Type) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Start (Type: %d)",Type); + if (g_BaseSystem) + { + g_BaseSystem->ExternalEvent((SystemEvent)Type); + } + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_onSurfaceCreated(JNIEnv * env, jclass cls) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Start"); + if (g_Plugins != NULL && g_Plugins->Gfx() != NULL && g_Plugins->Gfx()->SurfaceCreated) + { + g_Plugins->Gfx()->SurfaceCreated(); + } + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_onSurfaceChanged(JNIEnv * env, jclass cls, jint width, jint height) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Start"); + if (g_Plugins != NULL && g_Plugins->Gfx() != NULL && g_Plugins->Gfx()->SurfaceChanged) + { + g_Plugins->Gfx()->SurfaceChanged(width,height); + } + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_UISettingsSaveBool(JNIEnv* env, jclass cls, jint Type, jboolean Value) +{ + UISettingsSaveBool((UISettingID)Type, Value); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_UISettingsSaveDword(JNIEnv* env, jclass cls, jint Type, jint Value) +{ + UISettingsSaveDword((UISettingID)Type, Value); +} + +EXPORT jboolean CALL Java_emu_project64_jni_NativeExports_UISettingsLoadBool(JNIEnv* env, jclass cls, jint Type) +{ + return UISettingsLoadBool((UISettingID)Type); +} + +EXPORT int CALL Java_emu_project64_jni_NativeExports_UISettingsLoadDword(JNIEnv* env, jclass cls, jint Type) +{ + return UISettingsLoadDword((UISettingID)Type); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_StopEmulation(JNIEnv* env, jclass cls) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Start"); + if (g_BaseSystem) + { + g_BaseSystem->CloseCpu(); + } + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_StartEmulation(JNIEnv* env, jclass cls) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Start"); + if (g_BaseSystem) + { + g_BaseSystem->StartEmulation(true); + } + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +EXPORT void CALL Java_emu_project64_jni_NativeExports_CloseSystem(JNIEnv* env, jclass cls) +{ + WriteTrace(TraceUserInterface, TraceDebug, "Start"); + CN64System::CloseSystem(); + env->DeleteGlobalRef(g_Activity); + g_Activity = NULL; + env->DeleteGlobalRef(g_GLThread); + g_GLThread = NULL; + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +static void Android_JNI_ThreadDestroyed(void* value) +{ + __android_log_print(ANDROID_LOG_ERROR, "Android_JNI_ThreadDestroyed", "start"); + + /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */ + JNIEnv *env = (JNIEnv*)value; + if (env != NULL) + { + g_JavaVM->DetachCurrentThread(); + pthread_setspecific(g_ThreadKey, NULL); + } + __android_log_print(ANDROID_LOG_ERROR, "Android_JNI_ThreadDestroyed", "Done"); +} + +JNIEnv* Android_JNI_GetEnv(void) +{ + /* From http://developer.android.com/guide/practices/jni.html + * All threads are Linux threads, scheduled by the kernel. + * They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then + * attached to the JavaVM. For example, a thread started with pthread_create can be attached with the + * JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv, + * and cannot make JNI calls. + * Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main" + * ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread + * is a no-op. + * Note: You can call this function any number of times for the same thread, there's no harm in it + */ + + JNIEnv *env; + int status = g_JavaVM->AttachCurrentThread(&env, NULL); + if (status < 0) + { + __android_log_print(ANDROID_LOG_ERROR, "jniBridge", "failed to attach current thread"); + return 0; + } + + /* From http://developer.android.com/guide/practices/jni.html + * Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward, + * in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be + * called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific + * to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.) + * Note: The destructor is not called unless the stored value is != NULL + * Note: You can call this function any number of times for the same thread, there's no harm in it + * (except for some lost CPU cycles) + */ + pthread_setspecific(g_ThreadKey, (void*)env); + return env; +} + +void Android_JNI_SetupThread(void) +{ + Android_JNI_GetEnv(); +} + +#endif \ No newline at end of file diff --git a/Source/Android/Bridge/jniBridge.h b/Source/Android/Bridge/jniBridge.h new file mode 100644 index 000000000..9376ebbc1 --- /dev/null +++ b/Source/Android/Bridge/jniBridge.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef ANDROID +#include + +JNIEnv* Android_JNI_GetEnv(void); + +extern jobject g_Activity; +extern jobject g_GLThread; + +#endif \ No newline at end of file diff --git a/Source/Android/Bridge/jniBridgeSettings.cpp b/Source/Android/Bridge/jniBridgeSettings.cpp new file mode 100644 index 000000000..268e251c7 --- /dev/null +++ b/Source/Android/Bridge/jniBridgeSettings.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#include "jniBridgeSettings.h" +#include + +int CJniBridegSettings::m_RefCount = 0; +bool CJniBridegSettings::m_bCPURunning; + +CJniBridegSettings::CJniBridegSettings() +{ + m_RefCount += 1; + if (m_RefCount == 1) + { + g_Settings->RegisterChangeCB(GameRunning_CPU_Running,NULL,RefreshSettings); + RefreshSettings(NULL); + } +} + +CJniBridegSettings::~CJniBridegSettings() +{ + m_RefCount -= 1; + if (m_RefCount == 0) + { + g_Settings->UnregisterChangeCB(GameRunning_CPU_Running,NULL,RefreshSettings); + } +} + +void CJniBridegSettings::RefreshSettings(void *) +{ + m_bCPURunning = g_Settings->LoadBool(GameRunning_CPU_Running); +} + diff --git a/Source/Android/Bridge/jniBridgeSettings.h b/Source/Android/Bridge/jniBridgeSettings.h new file mode 100644 index 000000000..971789445 --- /dev/null +++ b/Source/Android/Bridge/jniBridgeSettings.h @@ -0,0 +1,27 @@ +/**************************************************************************** +* * +* Project64 - A Nintendo 64 emulator. * +* http://www.pj64-emu.com/ * +* Copyright (C) 2012 Project64. All rights reserved. * +* * +* License: * +* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * +* * +****************************************************************************/ +#pragma once + +class CJniBridegSettings +{ +public: + CJniBridegSettings(); + ~CJniBridegSettings(); + + static inline bool bCPURunning ( void) { return m_bCPURunning; } + +private: + static void RefreshSettings (void *); + + static bool m_bCPURunning; + + static int m_RefCount; +};