(Android andretro) get rid of andretro
@ -1,31 +0,0 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.andretro"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="9"
|
||||
android:targetSdkVersion="16" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name" >
|
||||
<activity android:name=".browser.ModuleActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
|
||||
<activity android:name=".browser.DirectoryActivity"></activity>
|
||||
<activity android:name=".RetroDisplay"></activity>
|
||||
<activity android:name=".settings.SettingActivity"></activity>
|
||||
<activity android:name=".browser.StateList"></activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -1,6 +0,0 @@
|
||||
Building:
|
||||
|
||||
* Put any compiled module libraries in Andretro/jni/modules, the file must be named like libretro_{MODNAME}.so.
|
||||
* Ensure a matching libretro_{MODNAME}.so.xml exists in the Andretro/assets directory. The xml file contains basic information used by the file browser before the .so itself is loaded.
|
||||
* In the Andretro directory, run the ndk-build script supplied with the Android NDK.
|
||||
* In the Andretro directory, run 'ant debug install' to install to the device. The java code can alternatively be built with the included eclipse project.
|
@ -1,17 +0,0 @@
|
||||
# This file is used to override default values used by the Ant build system.
|
||||
#
|
||||
# This file must be checked into Version Control Systems, as it is
|
||||
# integral to the build system of your project.
|
||||
|
||||
# This file is only used by the Ant script.
|
||||
|
||||
# You can use this to override default values such as
|
||||
# 'source.dir' for the location of your java source folder and
|
||||
# 'out.dir' for the location of your output folder.
|
||||
|
||||
# You can also use it define how the release builds are signed by declaring
|
||||
# the following properties:
|
||||
# 'key.store' for the location of your keystore and
|
||||
# 'key.alias' for the name of the key to use.
|
||||
# The password will be asked during the build when you use the 'release' target.
|
||||
|
@ -1,19 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="Nintendo Entertainment System" shortname="NES"/>
|
||||
<module libraryname="FCEUmm" extensions="fds|nes|unif"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="select" fullname="Select" mappedkey="SELECT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="a" fullname="A" mappedkey="A"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
</retro>
|
@ -1,28 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="Final Burn Alpha" shortname="fba"/>
|
||||
<module libraryname="FB Alpha" extensions="zip"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="select" fullname="Select" mappedkey="SELECT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="a" fullname="A" mappedkey="A"/>
|
||||
<button shortname="x" fullname="X" mappedkey="X"/>
|
||||
<button shortname="y" fullname="Y" mappedkey="Y"/>
|
||||
<button shortname="l1" fullname="L1" mappedkey="L1"/>
|
||||
<button shortname="r1" fullname="R1" mappedkey="R1"/>
|
||||
<button shortname="l2" fullname="L2" mappedkey="L2"/>
|
||||
<button shortname="r2" fullname="R2" mappedkey="R2"/>
|
||||
<button shortname="l3" fullname="L3" mappedkey="L3"/>
|
||||
<button shortname="r3" fullname="R3" mappedkey="R3"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
|
||||
</retro>
|
@ -1,20 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="Nintendo Gameboy" shortname="GB"/>
|
||||
<module libraryname="gambatte" extensions="gb|gbc|dmg"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="select" fullname="Select" mappedkey="SELECT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="a" fullname="A" mappedkey="A"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
|
||||
</retro>
|
@ -1,23 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="Sega Genesis/Megadrive" shortname="MD"/>
|
||||
<module libraryname="Genesis Plus GX" extensions="md|smd|bin|cue|gen|bin|sms|gg|sg"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="a" fullname="A" mappedkey="Y"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="c" fullname="C" mappedkey="A"/>
|
||||
<button shortname="x" fullname="X" mappedkey="L1"/>
|
||||
<button shortname="y" fullname="Y" mappedkey="X"/>
|
||||
<button shortname="z" fullname="Z" mappedkey="R1"/>
|
||||
<button shortname="mode" fullname="Mode" mappedkey="SELECT"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
</retro>
|
@ -1,24 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="PlayStation1 (PCSX ReARMed)" shortname="PS1"/>
|
||||
<module libraryname="PCSX ReARMed" extensions="bin|cue|img|mdf|pbp|cbn|toc"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="select" fullname="Select" mappedkey="SELECT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="a" fullname="A" mappedkey="A"/>
|
||||
<button shortname="x" fullname="X" mappedkey="X"/>
|
||||
<button shortname="y" fullname="Y" mappedkey="Y"/>
|
||||
<button shortname="l" fullname="L" mappedkey="L1"/>
|
||||
<button shortname="r" fullname="R" mappedkey="R1"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
|
||||
</retro>
|
@ -1,29 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="DOOM" shortname="doom"/>
|
||||
<module libraryname="prboom" extensions="wad|iwad"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="strafeleft" fullname="Strafe Left" mappedkey="L1"/>
|
||||
<button shortname="straferight" fullname="Strafe Right" mappedkey="R1"/>
|
||||
|
||||
<button shortname="fire" fullname="Fire" mappedkey="X"/>
|
||||
<button shortname="use" fullname="Use" mappedkey="A"/>
|
||||
<button shortname="run" fullname="Run" mappedkey="Y"/>
|
||||
<button shortname="strafe" fullname="Strafe" mappedkey="B"/>
|
||||
|
||||
<button shortname="menu" fullname="Menu" mappedkey="START"/>
|
||||
<button shortname="map" fullname="Map" mappedkey="SELECT"/>
|
||||
|
||||
<button shortname="prevweapon" fullname="Previous Weapon" mappedkey="L2"/>
|
||||
<button shortname="nextweapon" fullname="Next Weapon" mappedkey="R2"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
|
||||
</retro>
|
@ -1,24 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="Super Nintendo Entertainment System" shortname="SNES"/>
|
||||
<module libraryname="SNES9x Next" extensions="smc|fig|sfc|gd3|gd7|dx2|bsx|swc"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="select" fullname="Select" mappedkey="SELECT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="a" fullname="A" mappedkey="A"/>
|
||||
<button shortname="x" fullname="X" mappedkey="X"/>
|
||||
<button shortname="y" fullname="Y" mappedkey="Y"/>
|
||||
<button shortname="l" fullname="L" mappedkey="L1"/>
|
||||
<button shortname="r" fullname="R" mappedkey="R1"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
|
||||
</retro>
|
@ -1,28 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="Atari 2600" shortname="a2600"/>
|
||||
<module libraryname="Stella" extensions="a26|bin"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="select" fullname="Select" mappedkey="SELECT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="a" fullname="A" mappedkey="A"/>
|
||||
<button shortname="x" fullname="X" mappedkey="X"/>
|
||||
<button shortname="y" fullname="Y" mappedkey="Y"/>
|
||||
<button shortname="l1" fullname="L1" mappedkey="L1"/>
|
||||
<button shortname="r1" fullname="R1" mappedkey="R1"/>
|
||||
<button shortname="l2" fullname="L2" mappedkey="L2"/>
|
||||
<button shortname="r2" fullname="R2" mappedkey="R2"/>
|
||||
<button shortname="l3" fullname="L3" mappedkey="L3"/>
|
||||
<button shortname="r3" fullname="R3" mappedkey="R3"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
|
||||
</retro>
|
@ -1,22 +0,0 @@
|
||||
<retro>
|
||||
<system fullname="Nintendo Gameboy Advance" shortname="GBA"/>
|
||||
<module libraryname="VBA Next" extensions="gba"/>
|
||||
|
||||
<input>
|
||||
<port shortname="p1" fullname="Player 1" defaultdevice="pad">
|
||||
<device shortname="pad" fullname="Gamepad">
|
||||
<button shortname="up" fullname="Up" mappedkey="UP"/>
|
||||
<button shortname="down" fullname="Down" mappedkey="DOWN"/>
|
||||
<button shortname="left" fullname="Left" mappedkey="LEFT"/>
|
||||
<button shortname="right" fullname="Right" mappedkey="RIGHT"/>
|
||||
<button shortname="select" fullname="Select" mappedkey="SELECT"/>
|
||||
<button shortname="start" fullname="Start" mappedkey="START"/>
|
||||
<button shortname="b" fullname="B" mappedkey="B"/>
|
||||
<button shortname="a" fullname="A" mappedkey="A"/>
|
||||
<button shortname="l" fullname="L" mappedkey="L1"/>
|
||||
<button shortname="r" fullname="R" mappedkey="R1"/>
|
||||
</device>
|
||||
</port>
|
||||
</input>
|
||||
|
||||
</retro>
|
@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="andretro" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
Before Width: | Height: | Size: 36 KiB |
@ -1,23 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_CPP_FEATURES := exceptions rtti
|
||||
|
||||
LOCAL_SRC_FILES = Driver.cpp
|
||||
|
||||
LOCAL_MODULE := retroiface
|
||||
LOCAL_LDLIBS := -llog -lz -lGLESv2
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# Include all present sub-modules
|
||||
FOCAL_PATH := $(LOCAL_PATH)
|
||||
|
||||
define function
|
||||
$(eval RETRO_MODULE_OBJECT := $(1))
|
||||
$(eval include $(FOCAL_PATH)/modules/Android.mk)
|
||||
endef
|
||||
|
||||
$(foreach m,$(wildcard $(FOCAL_PATH)/modules/*.so),$(eval $(call function,$(m))))
|
@ -1 +0,0 @@
|
||||
APP_STL := gnustl_static
|
@ -1,177 +0,0 @@
|
||||
#ifndef MJNI_COMMON_H
|
||||
#define MJNI_COMMON_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <fstream>
|
||||
#include <exception>
|
||||
|
||||
#define Log(...) __android_log_print(ANDROID_LOG_INFO, "andretro", __VA_ARGS__);
|
||||
|
||||
class FileReader
|
||||
{
|
||||
private:
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
public:
|
||||
FileReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FileReader(const char* aPath)
|
||||
{
|
||||
load(aPath);
|
||||
}
|
||||
|
||||
bool load(const char* aPath)
|
||||
{
|
||||
close();
|
||||
|
||||
// Open new file
|
||||
if(aPath)
|
||||
{
|
||||
FILE* file = fopen(aPath, "rb");
|
||||
|
||||
if(file)
|
||||
{
|
||||
fseek(file, 0, SEEK_END);
|
||||
data.resize(ftell(file));
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
fread(&data[0], data.size(), 1, file);
|
||||
|
||||
fclose(file);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
|
||||
bool isOpen() const
|
||||
{
|
||||
return 0 < data.size();
|
||||
}
|
||||
|
||||
const uint8_t* base() const
|
||||
{
|
||||
return &data[0];
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
};
|
||||
|
||||
// Makes no guarantees about aData if read fails!
|
||||
bool ReadFile(const char* aPath, void* aData, size_t aLength)
|
||||
{
|
||||
FILE* file = fopen(aPath, "rb");
|
||||
|
||||
if(file)
|
||||
{
|
||||
bool result = 1 == fread(aData, aLength, 1, file);
|
||||
fclose(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DumpFile(const char* aPath, const void* aData, size_t aLength)
|
||||
{
|
||||
FILE* file = fopen(aPath, "wb");
|
||||
|
||||
if(file)
|
||||
{
|
||||
bool result = 1 == fwrite(aData, aLength, 1, file);
|
||||
fclose(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct JavaClass
|
||||
{
|
||||
std::map<std::string, jfieldID> fields;
|
||||
|
||||
JavaClass(JNIEnv* aEnv, jclass aClass, int aFieldCount, const char* const* aNames, const char* const* aSigs)
|
||||
{
|
||||
if(!aEnv || !aClass || !aNames || !aSigs || !aFieldCount)
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
for(int i = 0; i != aFieldCount; i ++)
|
||||
{
|
||||
fields[aNames[i]] = aEnv->GetFieldID(aClass, aNames[i], aSigs[i]);
|
||||
|
||||
if(fields[aNames[i]] == 0)
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jfieldID operator[](const char* aName)
|
||||
{
|
||||
return fields[aName];
|
||||
}
|
||||
};
|
||||
|
||||
// jstring wrapper
|
||||
struct JavaChars
|
||||
{
|
||||
JNIEnv* env;
|
||||
jstring string;
|
||||
const char* chars;
|
||||
|
||||
JavaChars(JNIEnv* aEnv, jstring aString)
|
||||
{
|
||||
env = aEnv;
|
||||
string = aString;
|
||||
chars = env->GetStringUTFChars(string, 0);
|
||||
}
|
||||
|
||||
~JavaChars()
|
||||
{
|
||||
env->ReleaseStringUTFChars(string, chars);
|
||||
}
|
||||
|
||||
operator const char*() const
|
||||
{
|
||||
return chars;
|
||||
}
|
||||
|
||||
// No copy
|
||||
private:
|
||||
JavaChars(const JavaChars&);
|
||||
JavaChars& operator= (const JavaChars&);
|
||||
|
||||
};
|
||||
|
||||
// Build a string with checking (later anyway)
|
||||
inline jstring JavaString(JNIEnv* aEnv, const char* aString)
|
||||
{
|
||||
jstring string = aEnv->NewStringUTF(aString ? aString : "(NULL)");
|
||||
|
||||
if(string)
|
||||
{
|
||||
return string;
|
||||
}
|
||||
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
#endif
|
@ -1,558 +0,0 @@
|
||||
#include <jni.h>
|
||||
#include <dlfcn.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <memory>
|
||||
|
||||
#include "Common.h"
|
||||
#include "../../../libretro.h"
|
||||
#include "Library.h"
|
||||
|
||||
#include "Rewinder.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
Library* module;
|
||||
|
||||
FileReader ROM;
|
||||
Rewinder rewinder;
|
||||
|
||||
bool dontProcess;
|
||||
|
||||
char* systemDirectory;
|
||||
|
||||
JNIEnv* env;
|
||||
|
||||
jobject videoFrame;
|
||||
jint rotation;
|
||||
|
||||
retro_system_info systemInfo;
|
||||
retro_system_av_info avInfo;
|
||||
|
||||
std::auto_ptr<JavaClass> avInfo_class;
|
||||
std::auto_ptr<JavaClass> systemInfo_class;
|
||||
std::auto_ptr<JavaClass> frame_class;
|
||||
}
|
||||
|
||||
namespace VIDEO
|
||||
{
|
||||
typedef void (*andretro_video_refresh)(const void* data, unsigned width, unsigned height, size_t pitch);
|
||||
unsigned pixelFormat;
|
||||
|
||||
template<typename T, int FORMAT, int TYPE>
|
||||
static void refresh_noconv(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
const unsigned pixelPitch = pitch / sizeof(T);
|
||||
|
||||
if(pixelPitch == width)
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, FORMAT, TYPE, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
T outPixels[width * height];
|
||||
T* outPixels_t = outPixels;
|
||||
const T* inPixels = (const T*)data;
|
||||
|
||||
for(int i = 0; i != height; i ++, inPixels += pixelPitch, outPixels_t += width)
|
||||
{
|
||||
memcpy(outPixels_t, inPixels, width * sizeof(T));
|
||||
}
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, FORMAT, TYPE, outPixels);
|
||||
}
|
||||
}
|
||||
|
||||
// retro_video_refresh for 0RGB1555: deprecated
|
||||
static void refresh_15(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
uint16_t outPixels[width * height];
|
||||
uint16_t* outPixels_t = outPixels;
|
||||
const uint16_t* inPixels = (const uint16_t*)data;
|
||||
const unsigned pixelPitch = pitch / 2;
|
||||
|
||||
for(int i = 0; i != height; i ++, inPixels += pixelPitch - width)
|
||||
{
|
||||
for(int j = 0; j != width; j ++)
|
||||
{
|
||||
(*outPixels_t++) = (*inPixels++) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, outPixels);
|
||||
}
|
||||
|
||||
static void retro_video_refresh_imp(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
if(!dontProcess)
|
||||
{
|
||||
static const andretro_video_refresh refreshByMode[3] = {&refresh_15, &refresh_noconv<uint32_t, GL_RGBA, GL_UNSIGNED_BYTE>, &refresh_noconv<uint16_t, GL_RGB, GL_UNSIGNED_SHORT_5_6_5>};
|
||||
|
||||
if(data)
|
||||
{
|
||||
refreshByMode[pixelFormat](data, width, height, pitch);
|
||||
}
|
||||
|
||||
env->SetIntField(videoFrame, (*frame_class)["width"], width);
|
||||
env->SetIntField(videoFrame, (*frame_class)["height"], height);
|
||||
env->SetIntField(videoFrame, (*frame_class)["pixelFormat"], VIDEO::pixelFormat);
|
||||
env->SetIntField(videoFrame, (*frame_class)["rotation"], rotation);
|
||||
env->SetFloatField(videoFrame, (*frame_class)["aspect"], avInfo.geometry.aspect_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
static void createTexture()
|
||||
{
|
||||
const GLenum formats[3] = {GL_RGBA, GL_RGBA, GL_RGB};
|
||||
const GLenum types[3] = {GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5};
|
||||
|
||||
if(pixelFormat < 3)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, formats[pixelFormat], 1024, 1024, 0, formats[pixelFormat], types[pixelFormat], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace INPUT
|
||||
{
|
||||
jint keyboard[RETROK_LAST];
|
||||
jint joypads[8];
|
||||
|
||||
int16_t touchData[3];
|
||||
|
||||
static void retro_input_poll_imp(void)
|
||||
{
|
||||
// Joystick
|
||||
jintArray js = (jintArray)env->GetObjectField(videoFrame, (*frame_class)["buttons"]);
|
||||
env->GetIntArrayRegion(js, 0, 8, joypads);
|
||||
|
||||
// Keyboard
|
||||
jintArray kbd = (jintArray)env->GetObjectField(videoFrame, (*frame_class)["keyboard"]);
|
||||
env->GetIntArrayRegion(kbd, 0, RETROK_LAST, keyboard);
|
||||
|
||||
// Pointer
|
||||
touchData[0] = env->GetShortField(videoFrame, (*frame_class)["touchX"]);
|
||||
touchData[1] = env->GetShortField(videoFrame, (*frame_class)["touchY"]);
|
||||
touchData[2] = env->GetShortField(videoFrame, (*frame_class)["touched"]) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int16_t retro_input_state_imp(unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
switch(device)
|
||||
{
|
||||
case RETRO_DEVICE_JOYPAD: return (joypads[port] >> id) & 1;
|
||||
case RETRO_DEVICE_KEYBOARD: return (id < RETROK_LAST) ? keyboard[id] : 0;
|
||||
case RETRO_DEVICE_POINTER: return (id < 3) ? touchData[id] : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AUDIO
|
||||
{
|
||||
static uint32_t audioLength;
|
||||
static int16_t buffer[48000];
|
||||
|
||||
static inline void prepareFrame()
|
||||
{
|
||||
audioLength = 0;
|
||||
}
|
||||
|
||||
static inline void endFrame()
|
||||
{
|
||||
if(!dontProcess)
|
||||
{
|
||||
jshortArray audioData = (jshortArray)env->GetObjectField(videoFrame, (*frame_class)["audio"]);
|
||||
env->SetShortArrayRegion(audioData, 0, audioLength, buffer);
|
||||
|
||||
env->SetIntField(videoFrame, (*frame_class)["audioSamples"], audioLength);
|
||||
}
|
||||
}
|
||||
|
||||
static void retro_audio_sample_imp(int16_t left, int16_t right)
|
||||
{
|
||||
if(!dontProcess)
|
||||
{
|
||||
buffer[audioLength++] = left;
|
||||
buffer[audioLength++] = right;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t retro_audio_sample_batch_imp(const int16_t *data, size_t frames)
|
||||
{
|
||||
if(!dontProcess)
|
||||
{
|
||||
memcpy(&buffer[audioLength], data, frames * 4);
|
||||
audioLength += frames * 2;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
//
|
||||
// Environment callback. Gives implementations a way of performing uncommon tasks. Extensible.
|
||||
static bool retro_environment_imp(unsigned cmd, void *data)
|
||||
{
|
||||
if(RETRO_ENVIRONMENT_SET_ROTATION == cmd)
|
||||
{
|
||||
rotation = (*(unsigned*)data) & 3;
|
||||
return true;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_GET_OVERSCAN == cmd)
|
||||
{
|
||||
// TODO: true causes snes9x-next to shit a brick
|
||||
*(uint8_t*)data = false;
|
||||
return true;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_GET_CAN_DUPE == cmd)
|
||||
{
|
||||
*(uint8_t*)data = true;
|
||||
return true;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_GET_VARIABLE == cmd)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_SET_VARIABLES == cmd)
|
||||
{
|
||||
// HACK
|
||||
return false;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_SET_MESSAGE == cmd)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_SHUTDOWN == cmd)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL == cmd)
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY == cmd)
|
||||
{
|
||||
*(const char**)data = systemDirectory;
|
||||
return true;
|
||||
}
|
||||
else if(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT == cmd)
|
||||
{
|
||||
unsigned newFormat = *(unsigned*)data;
|
||||
|
||||
if(newFormat < 3 && newFormat != 1)
|
||||
{
|
||||
VIDEO::pixelFormat = newFormat;
|
||||
VIDEO::createTexture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
#define JNIFUNC(RET, FUNCTION) extern "C" RET Java_org_libretro_LibRetro_ ## FUNCTION
|
||||
#define JNIARGS JNIEnv* aEnv, jclass aClass
|
||||
|
||||
JNIFUNC(jboolean, loadLibrary)(JNIARGS, jstring path, jstring systemDir)
|
||||
{
|
||||
JavaChars libname(aEnv, path);
|
||||
|
||||
delete module;
|
||||
module = 0;
|
||||
|
||||
try
|
||||
{
|
||||
module = new Library(libname);
|
||||
systemDirectory = strdup(JavaChars(aEnv, systemDir));
|
||||
chdir(systemDirectory);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JNIFUNC(void, unloadLibrary)(JNIARGS)
|
||||
{
|
||||
delete module;
|
||||
module = 0;
|
||||
|
||||
free(systemDirectory);
|
||||
systemDirectory = 0;
|
||||
|
||||
memset(&systemInfo, 0, sizeof(systemInfo));
|
||||
|
||||
rotation = 0;
|
||||
}
|
||||
|
||||
JNIFUNC(void, init)(JNIARGS)
|
||||
{
|
||||
module->set_environment(retro_environment_imp);
|
||||
|
||||
VIDEO::pixelFormat = 0;
|
||||
VIDEO::createTexture();
|
||||
|
||||
module->init();
|
||||
|
||||
module->get_system_info(&systemInfo);
|
||||
}
|
||||
|
||||
JNIFUNC(void, deinit)(JNIARGS)
|
||||
{
|
||||
module->deinit();
|
||||
}
|
||||
|
||||
JNIFUNC(jint, apiVersion)(JNIARGS)
|
||||
{
|
||||
return module->api_version();
|
||||
}
|
||||
|
||||
JNIFUNC(void, getSystemInfo)(JNIARGS, jobject aSystemInfo)
|
||||
{
|
||||
aEnv->SetObjectField(aSystemInfo, (*systemInfo_class)["libraryName"], JavaString(aEnv, systemInfo.library_name));
|
||||
aEnv->SetObjectField(aSystemInfo, (*systemInfo_class)["libraryVersion"], JavaString(aEnv, systemInfo.library_version));
|
||||
aEnv->SetObjectField(aSystemInfo, (*systemInfo_class)["validExtensions"], JavaString(aEnv, systemInfo.valid_extensions));
|
||||
aEnv->SetBooleanField(aSystemInfo, (*systemInfo_class)["needFullPath"], systemInfo.need_fullpath);
|
||||
aEnv->SetBooleanField(aSystemInfo, (*systemInfo_class)["blockExtract"], systemInfo.block_extract);
|
||||
}
|
||||
|
||||
JNIFUNC(void, getSystemAVInfo)(JNIARGS, jobject aAVInfo)
|
||||
{
|
||||
aEnv->SetIntField(aAVInfo, (*avInfo_class)["baseWidth"], avInfo.geometry.base_width);
|
||||
aEnv->SetIntField(aAVInfo, (*avInfo_class)["baseHeight"], avInfo.geometry.base_height);
|
||||
aEnv->SetIntField(aAVInfo, (*avInfo_class)["maxWidth"], avInfo.geometry.max_width);
|
||||
aEnv->SetIntField(aAVInfo, (*avInfo_class)["maxHeight"], avInfo.geometry.max_height);
|
||||
aEnv->SetFloatField(aAVInfo, (*avInfo_class)["aspectRatio"], avInfo.geometry.aspect_ratio);
|
||||
aEnv->SetDoubleField(aAVInfo, (*avInfo_class)["fps"], avInfo.timing.fps);
|
||||
aEnv->SetDoubleField(aAVInfo, (*avInfo_class)["sampleRate"], avInfo.timing.sample_rate);
|
||||
}
|
||||
|
||||
JNIFUNC(void, setControllerPortDevice)(JNIARGS, jint port, jint device)
|
||||
{
|
||||
module->set_controller_port_device(port, device);
|
||||
}
|
||||
|
||||
JNIFUNC(void, reset)(JNIARGS)
|
||||
{
|
||||
module->reset();
|
||||
}
|
||||
|
||||
JNIFUNC(void, run)(JNIARGS, jobject aVideo)
|
||||
{
|
||||
// TODO
|
||||
env = aEnv;
|
||||
videoFrame = aVideo;
|
||||
|
||||
if(env->GetBooleanField(videoFrame, (*frame_class)["restarted"]))
|
||||
{
|
||||
VIDEO::createTexture();
|
||||
env->SetBooleanField(videoFrame, (*frame_class)["restarted"], false);
|
||||
}
|
||||
|
||||
const int count = env->GetIntField(videoFrame, (*frame_class)["framesToRun"]);
|
||||
const bool rewind = env->GetBooleanField(videoFrame, (*frame_class)["rewind"]);
|
||||
|
||||
for(int i = 0; i < count; i ++)
|
||||
{
|
||||
dontProcess = !(i == (count - 1));
|
||||
|
||||
const bool rewound = rewind && rewinder.eatFrame(module);
|
||||
|
||||
if(!rewind || rewound)
|
||||
{
|
||||
AUDIO::prepareFrame();
|
||||
module->run();
|
||||
AUDIO::endFrame();
|
||||
|
||||
if(!rewind)
|
||||
{
|
||||
rewinder.stashFrame(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JNIFUNC(jint, serializeSize)(JNIARGS)
|
||||
{
|
||||
return module->serialize_size();
|
||||
}
|
||||
|
||||
JNIFUNC(void, cheatReset)(JNIARGS)
|
||||
{
|
||||
module->cheat_reset();
|
||||
}
|
||||
|
||||
JNIFUNC(void, cheatSet)(JNIARGS, jint index, jboolean enabled, jstring code)
|
||||
{
|
||||
JavaChars codeN(aEnv, code);
|
||||
module->cheat_set(index, enabled, codeN);
|
||||
}
|
||||
|
||||
JNIFUNC(bool, loadGame)(JNIARGS, jstring path)
|
||||
{
|
||||
JavaChars fileName(aEnv, path);
|
||||
|
||||
retro_game_info info = {fileName, 0, 0, 0};
|
||||
|
||||
if(!systemInfo.need_fullpath)
|
||||
{
|
||||
if(ROM.load(fileName))
|
||||
{
|
||||
info.data = ROM.base();
|
||||
info.size = ROM.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(module->load_game(&info))
|
||||
{
|
||||
module->get_system_av_info(&avInfo);
|
||||
|
||||
module->set_video_refresh(VIDEO::retro_video_refresh_imp);
|
||||
module->set_audio_sample(AUDIO::retro_audio_sample_imp);
|
||||
module->set_audio_sample_batch(AUDIO::retro_audio_sample_batch_imp);
|
||||
module->set_input_poll(INPUT::retro_input_poll_imp);
|
||||
module->set_input_state(INPUT::retro_input_state_imp);
|
||||
|
||||
rewinder.gameLoaded(module);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
JNIFUNC(void, unloadGame)(JNIARGS)
|
||||
{
|
||||
module->unload_game();
|
||||
memset(&avInfo, 0, sizeof(avInfo));
|
||||
|
||||
ROM.close();
|
||||
}
|
||||
|
||||
JNIFUNC(jint, getRegion)(JNIARGS)
|
||||
{
|
||||
return module->get_region();
|
||||
}
|
||||
|
||||
JNIFUNC(jobject, getMemoryData)(JNIARGS, int aID)
|
||||
{
|
||||
void* const memoryData = module->get_memory_data(aID);
|
||||
const size_t memorySize = module->get_memory_size(aID);
|
||||
|
||||
return (memoryData && memorySize) ? aEnv->NewDirectByteBuffer(memoryData, memorySize) : 0;
|
||||
}
|
||||
|
||||
JNIFUNC(int, getMemorySize)(JNIARGS, int aID)
|
||||
{
|
||||
return module->get_memory_size(aID);
|
||||
}
|
||||
|
||||
// Extensions: Rewinder
|
||||
JNIFUNC(void, setupRewinder)(JNIARGS, int aSize)
|
||||
{
|
||||
rewinder.setSize(aSize);
|
||||
}
|
||||
|
||||
// Extensions: Read or write a memory region into a specified file.
|
||||
JNIFUNC(jboolean, writeMemoryRegion)(JNIARGS, int aID, jstring aFileName)
|
||||
{
|
||||
const size_t size = module->get_memory_size(aID);
|
||||
void* const data = module->get_memory_data(aID);
|
||||
|
||||
if(size && data)
|
||||
{
|
||||
DumpFile(JavaChars(aEnv, aFileName), data, size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JNIFUNC(jboolean, readMemoryRegion)(JNIARGS, int aID, jstring aFileName)
|
||||
{
|
||||
const size_t size = module->get_memory_size(aID);
|
||||
void* const data = module->get_memory_data(aID);
|
||||
|
||||
if(size && data)
|
||||
{
|
||||
ReadFile(JavaChars(aEnv, aFileName), data, size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Extensions: Serialize/Unserialize using a file
|
||||
JNIFUNC(jboolean, serializeToFile)(JNIARGS, jstring aPath)
|
||||
{
|
||||
const size_t size = module->serialize_size();
|
||||
|
||||
if(size > 0)
|
||||
{
|
||||
uint8_t buffer[size];
|
||||
if(module->serialize(buffer, size))
|
||||
{
|
||||
return DumpFile(JavaChars(aEnv, aPath), buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
JNIFUNC(jboolean, unserializeFromFile)(JNIARGS, jstring aPath)
|
||||
{
|
||||
const size_t size = module->serialize_size();
|
||||
|
||||
if(size > 0)
|
||||
{
|
||||
uint8_t buffer[size];
|
||||
|
||||
if(ReadFile(JavaChars(aEnv, aPath), buffer, size))
|
||||
{
|
||||
return module->unserialize(buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preload native class data
|
||||
JNIFUNC(jboolean, nativeInit)(JNIARGS)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
static const char* const n[] = {"libraryName", "libraryVersion", "validExtensions", "needFullPath", "blockExtract"};
|
||||
static const char* const s[] = {"Ljava/lang/String;", "Ljava/lang/String;", "Ljava/lang/String;", "Z", "Z"};
|
||||
systemInfo_class.reset(new JavaClass(aEnv, aEnv->FindClass("org/libretro/LibRetro$SystemInfo"), sizeof(n) / sizeof(n[0]), n, s));
|
||||
}
|
||||
|
||||
{
|
||||
static const char* const n[] = {"baseWidth", "baseHeight", "maxWidth", "maxHeight", "aspectRatio", "fps", "sampleRate"};
|
||||
static const char* const s[] = {"I", "I", "I", "I", "F", "D", "D"};
|
||||
avInfo_class.reset(new JavaClass(aEnv, aEnv->FindClass("org/libretro/LibRetro$AVInfo"), sizeof(n) / sizeof(n[0]), n, s));
|
||||
}
|
||||
|
||||
{
|
||||
static const char* const n[] = {"restarted", "framesToRun", "rewind", "width", "height", "pixelFormat", "rotation", "aspect", "keyboard", "buttons", "touchX", "touchY", "touched", "audio", "audioSamples"};
|
||||
static const char* const s[] = {"Z", "I", "Z", "I", "I", "I", "I", "F", "[I", "[I", "S", "S", "Z", "[S", "I"};
|
||||
frame_class.reset(new JavaClass(aEnv, aEnv->FindClass("org/libretro/LibRetro$VideoFrame"), sizeof(n) / sizeof(n[0]), n, s));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
#ifndef RETRO_LIB_HHH
|
||||
#define RETRO_LIB_HHH
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <exception>
|
||||
#include <android/log.h>
|
||||
#include "../../../libretro.h"
|
||||
|
||||
#define LOG(...) __android_log_print(ANDROID_LOG_ERROR, "Andretro", __VA_ARGS__)
|
||||
|
||||
class Library
|
||||
{
|
||||
public:
|
||||
Library(const char* aPath) :
|
||||
handle(openLib(aPath)),
|
||||
set_environment((void (*)(retro_environment_t))getFn("retro_set_environment")),
|
||||
set_video_refresh((void (*)(retro_video_refresh_t))getFn("retro_set_video_refresh")),
|
||||
set_audio_sample((void (*)(retro_audio_sample_t))getFn("retro_set_audio_sample")),
|
||||
set_audio_sample_batch((void (*)(retro_audio_sample_batch_t))getFn("retro_set_audio_sample_batch")),
|
||||
set_input_poll((void (*)(retro_input_poll_t))getFn("retro_set_input_poll")),
|
||||
set_input_state((void (*)(retro_input_state_t))getFn("retro_set_input_state")),
|
||||
init((void (*)(void))getFn("retro_init")),
|
||||
deinit((void (*)(void))getFn("retro_deinit")),
|
||||
api_version((unsigned (*)(void))getFn("retro_api_version")),
|
||||
get_system_info((void (*)(struct retro_system_info *info))getFn("retro_get_system_info")),
|
||||
get_system_av_info((void (*)(struct retro_system_av_info *info))getFn("retro_get_system_av_info")),
|
||||
set_controller_port_device((void (*)(unsigned port, unsigned device))getFn("retro_set_controller_port_device")),
|
||||
reset((void (*)(void))getFn("retro_reset")),
|
||||
run((void (*)(void))getFn("retro_run")),
|
||||
serialize_size((size_t (*)(void))getFn("retro_serialize_size")),
|
||||
serialize((bool (*)(void *data, size_t size))getFn("retro_serialize")),
|
||||
unserialize((bool (*)(const void *data, size_t size))getFn("retro_unserialize")),
|
||||
cheat_reset((void (*)(void))getFn("retro_cheat_reset")),
|
||||
cheat_set((void (*)(unsigned index, bool enabled, const char *code))getFn("retro_cheat_set")),
|
||||
load_game((bool (*)(const struct retro_game_info *game))getFn("retro_load_game")),
|
||||
load_game_special((bool (*)(unsigned game_type,const struct retro_game_info *info, size_t num_info))getFn("retro_load_game_special")),
|
||||
unload_game((void (*)(void))getFn("retro_unload_game")),
|
||||
get_region((unsigned (*)(void))getFn("retro_get_region")),
|
||||
get_memory_data((void *(*)(unsigned id))getFn("retro_get_memory_data")),
|
||||
get_memory_size((size_t (*)(unsigned id))getFn("retro_get_memory_size"))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~Library()
|
||||
{
|
||||
if(handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void* const handle;
|
||||
|
||||
void (* const set_environment)(retro_environment_t);
|
||||
void (* const set_video_refresh)(retro_video_refresh_t);
|
||||
void (* const set_audio_sample)(retro_audio_sample_t);
|
||||
void (* const set_audio_sample_batch)(retro_audio_sample_batch_t);
|
||||
void (* const set_input_poll)(retro_input_poll_t);
|
||||
void (* const set_input_state)(retro_input_state_t);
|
||||
void (* const init)(void);
|
||||
void (* const deinit)(void);
|
||||
unsigned (* const api_version)(void);
|
||||
void (* const get_system_info)(struct retro_system_info *info);
|
||||
void (* const get_system_av_info)(struct retro_system_av_info *info);
|
||||
void (* const set_controller_port_device)(unsigned port, unsigned device);
|
||||
void (* const reset)(void);
|
||||
void (* const run)(void);
|
||||
size_t (* const serialize_size)(void);
|
||||
bool (* const serialize)(void *data, size_t size);
|
||||
bool (* const unserialize)(const void *data, size_t size);
|
||||
void (* const cheat_reset)(void);
|
||||
void (* const cheat_set)(unsigned index, bool enabled, const char *code);
|
||||
bool (* const load_game)(const struct retro_game_info *game);
|
||||
bool (* const load_game_special)(unsigned game_type,const struct retro_game_info *info, size_t num_info);
|
||||
void (* const unload_game)(void);
|
||||
unsigned (* const get_region)(void);
|
||||
void *(* const get_memory_data)(unsigned id);
|
||||
size_t (* const get_memory_size)(unsigned id);
|
||||
|
||||
private:
|
||||
void* openLib(const char* aPath)
|
||||
{
|
||||
void* result = dlopen(aPath, RTLD_NOW | RTLD_LOCAL);
|
||||
|
||||
if(!result)
|
||||
{
|
||||
LOG("openLib failed: %s\n", dlerror());
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* getFn(const char* aName)
|
||||
{
|
||||
void* result = dlsym(handle, aName);
|
||||
|
||||
if(!result)
|
||||
{
|
||||
LOG("getFn failed: %s\n", dlerror());
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -1,118 +0,0 @@
|
||||
#ifndef ANDRETRO_REWINDER_H
|
||||
#define ANDRETRO_REWINDER_H
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <stdint.h>
|
||||
#include <zlib.h>
|
||||
#include "Library.h"
|
||||
#include "Common.h"
|
||||
|
||||
class Rewinder
|
||||
{
|
||||
struct Frame
|
||||
{
|
||||
Frame(uint32_t aLocation, uint32_t aSize) :
|
||||
location(aLocation), size(aSize)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool overlaps(const Frame& aOther) const
|
||||
{
|
||||
const uint32_t myLow = location;
|
||||
const uint32_t myHigh = location + size;
|
||||
|
||||
const uint32_t yourLow = aOther.location;
|
||||
const uint32_t yourHigh = aOther.location + aOther.size;
|
||||
|
||||
return (myLow < yourHigh && yourLow < myHigh);
|
||||
}
|
||||
|
||||
uint32_t location;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<uint8_t> buffer;
|
||||
std::vector<uint8_t> compressBuffer;
|
||||
|
||||
uint32_t nextFrame;
|
||||
|
||||
std::deque<Frame> frames;
|
||||
|
||||
public:
|
||||
Rewinder() :
|
||||
data(0), buffer(0), nextFrame(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void gameLoaded(const Library* aModule)
|
||||
{
|
||||
buffer.resize(aModule->serialize_size());
|
||||
compressBuffer.resize(compressBound(aModule->serialize_size()));
|
||||
nextFrame = 0;
|
||||
frames.clear();
|
||||
}
|
||||
|
||||
void setSize(int aSize)
|
||||
{
|
||||
data.resize((aSize >= 0) ? aSize : 0);
|
||||
nextFrame = 0;
|
||||
frames.clear();
|
||||
}
|
||||
|
||||
void stashFrame(const Library* aModule)
|
||||
{
|
||||
if(buffer.size() && data.size())
|
||||
{
|
||||
if(aModule->serialize(&buffer[0], buffer.size()))
|
||||
{
|
||||
uLongf len = compressBuffer.size();
|
||||
if(Z_OK == compress(&compressBuffer[0], &len, &buffer[0], buffer.size()))
|
||||
{
|
||||
nextFrame = ((data.size() - nextFrame) < len) ? 0 : nextFrame;
|
||||
memcpy(&data[nextFrame], &compressBuffer[0], len);
|
||||
|
||||
// Add to list
|
||||
frames.push_back(Frame(nextFrame, len));
|
||||
nextFrame += len;
|
||||
|
||||
// Remove any dead entries from the list
|
||||
while((frames.size() > 1) && frames.front().overlaps(frames.back()))
|
||||
{
|
||||
frames.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool eatFrame(const Library* aModule)
|
||||
{
|
||||
if(buffer.size() && data.size())
|
||||
{
|
||||
if(!frames.empty())
|
||||
{
|
||||
const Frame loadFrame = frames.back();
|
||||
frames.pop_back();
|
||||
nextFrame = loadFrame.location;
|
||||
|
||||
uLongf len = buffer.size();
|
||||
if(Z_OK == uncompress(&buffer[0], &len, &data[loadFrame.location], loadFrame.size))
|
||||
{
|
||||
return aModule->unserialize(&buffer[0], buffer.size());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -1,6 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := $(notdir $(RETRO_MODULE_OBJECT))
|
||||
LOCAL_SRC_FILES := $(notdir $(RETRO_MODULE_OBJECT))
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<issue id="UseCompoundDrawables">
|
||||
<ignore path="res/layout/directory_list_item.xml" />
|
||||
</issue>
|
||||
</lint>
|
@ -1,20 +0,0 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# 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 *;
|
||||
#}
|
@ -1,14 +0,0 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-16
|
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 423 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.9 KiB |
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/hack_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:inputType="text" >
|
||||
|
||||
</EditText>
|
@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="192dp"
|
||||
android:layout_height="192dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/file_type_icon"
|
||||
android:padding="8dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="0.5"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</LinearLayout>
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:numColumns="2" >
|
||||
|
||||
</GridView>
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
</ListView>
|
||||
|
@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="48dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:contentDescription="@string/file_type_icon"
|
||||
android:padding="8dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="0.5"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</LinearLayout>
|
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.andretro.input.view.InputGroup xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/base"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" >
|
||||
|
||||
<android.opengl.GLSurfaceView
|
||||
android:id="@+id/renderer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
</android.opengl.GLSurfaceView>
|
||||
|
||||
</org.andretro.input.view.InputGroup>
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@+id/goto_root" android:title="@string/root_directory" android:showAsAction="always"></item>
|
||||
<item android:id="@+id/input_method_select" android:title="@string/input_method" android:showAsAction="ifRoom"></item>
|
||||
<item android:id="@+id/system_settings" android:title="@string/system_settings"></item>
|
||||
|
||||
|
||||
</menu>
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@+id/save_state" android:title="@string/save_state"></item>
|
||||
<item android:id="@+id/load_state" android:title="@string/load_state"></item>
|
||||
<item android:id="@+id/reset" android:title="@string/reset"></item>
|
||||
<item android:id="@+id/input_method_select" android:title="@string/input_method" android:showAsAction="always"></item>
|
||||
<item android:id="@+id/system_settings" android:title="@string/system_settings"></item>
|
||||
<item android:id="@+id/show_on_screen_input" android:checkable="true" android:title="@string/show_on_screen_input" android:checked="true"></item>
|
||||
<item android:id="@+id/screenshot" android:title="@string/screenshot"></item>
|
||||
<item android:id="@+id/pause" android:title="@string/pause" android:checkable="true" android:checked="false"></item>
|
||||
|
||||
|
||||
|
||||
</menu>
|
@ -1,7 +0,0 @@
|
||||
<group>
|
||||
<ButtonDiamond horzanchor="left" vertanchor="bottom" horzmargin="20" vertmargin="20" width="200" height="200" upbits="16" downbits="32" leftbits="64" rightbits="128"/>
|
||||
<ButtonDiamond horzanchor="right" vertanchor="bottom" horzmargin="20" vertmargin="20" width="200" height="200" upbits="512" downbits="1" leftbits="2" rightbits="256" />
|
||||
<ButtonDuo horzanchor="center" vertanchor="bottom" horzmargin="20" vertmargin="20" width="200" height="50" leftbits="4" rightbits="8"/>
|
||||
<Button horzanchor="right" vertanchor="top" horzmargin="20" vertmargin="20" width="50" height="50" bits="2048" />
|
||||
<Button horzanchor="left" vertanchor="top" horzmargin="20" vertmargin="20" width="50" height="50" bits="1024" />
|
||||
</group>
|
@ -1,9 +0,0 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 texCoord;
|
||||
uniform sampler2D texUnit;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(texUnit, texCoord);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
attribute vec2 pos;
|
||||
attribute vec2 tex;
|
||||
|
||||
varying vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position.x = pos.x;
|
||||
gl_Position.y = pos.y;
|
||||
gl_Position.z = 0.0;
|
||||
gl_Position.w = 1.0;
|
||||
|
||||
texCoord = tex;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Andretro</string>
|
||||
<string name="load_state">Load State</string>
|
||||
<string name="save_state">Save State</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="root_directory">SD Card Root</string>
|
||||
<string name="input_settings">Input Settings</string>
|
||||
<string name="input_method">Input Method</string>
|
||||
<string name="show_on_screen_input">On Screen Input</string>
|
||||
<string name="system_settings">System Settings</string>
|
||||
<string-array name="aspect_mode_values">
|
||||
<item >Default</item>
|
||||
<item >4:3</item>
|
||||
<item >Pixel Aspect</item>
|
||||
</string-array>
|
||||
<string-array name="orientation_modes">
|
||||
<item >Sensor</item>
|
||||
<item >Landscape</item>
|
||||
<item >Portrait</item>
|
||||
</string-array>
|
||||
<string name="file_type_icon">File type icon</string>
|
||||
<string name="screenshot">Take Screenshot</string>
|
||||
<string name="pause">Pause</string>
|
||||
|
||||
</resources>
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<PreferenceCategory android:title="Fast Forward">
|
||||
<org.andretro.settings.ButtonSetting android:title="Fast Forward Key" android:key="fast_forward_key" android:persistent="true" android:defaultValue="69"/>
|
||||
<EditTextPreference android:title="Fast Forward Speed" android:key="fast_forward_speed" android:summary="Multiplier for fast forward mode." android:defaultValue="4" android:persistent="true"/>
|
||||
<CheckBoxPreference android:title="Use Fast Forward Mode By Default" android:key="fast_forward_default" android:summary="The toggle button will run the game at normal speed." android:persistent="true" android:defaultValue="false"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Rewind">
|
||||
<org.andretro.settings.ButtonSetting android:title="Rewind Key" android:key="rewind_key" android:persistent="true" android:defaultValue="68"/>
|
||||
<CheckBoxPreference android:title="Enable Population of the Rewind Buffer" android:key="rewind_enabled" android:summary="Will use memory and processor resources." android:persistent="true" android:defaultValue="false"/>
|
||||
<EditTextPreference android:title="Size of the Rewind Buffer" android:key="rewind_buffer_size" android:summary="Size is in megabytes." android:defaultValue="16" android:persistent="true"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Scaling">
|
||||
<CheckBoxPreference android:title="Linear Filtering" android:persistent="true" android:key="scaling_smooth" android:summary="Use a smoothing effect when scaling the image." android:defaultValue="true"/>
|
||||
<ListPreference android:defaultValue="Default" android:entryValues="@array/aspect_mode_values" android:summary="Force an aspect ratio on the game's image." android:persistent="true" android:title="Aspect Ratio" android:key="scaling_aspect_mode" android:entries="@array/aspect_mode_values"/>
|
||||
<ListPreference android:key="scaling_orientation" android:title="Orientation" android:summary="Force a screen orientation" android:persistent="true" android:defaultValue="Sensor" android:entryValues="@array/orientation_modes" android:entries="@array/orientation_modes"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
</PreferenceScreen>
|
@ -1,81 +0,0 @@
|
||||
package org.andretro;
|
||||
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
|
||||
public class QuestionDialog extends android.support.v4.app.DialogFragment
|
||||
{
|
||||
public interface QuestionHandler
|
||||
{
|
||||
void onAnswer(int aID, QuestionDialog aDialog, boolean aPositive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a question dialog with the specified strings.
|
||||
*
|
||||
* @param aID The ID to pass to callback.
|
||||
* @param aTitle The title of the dialog.
|
||||
* @param aMessage The message to display in the dialog.
|
||||
* @param aPositive The text on the positive button of the dialog.
|
||||
* @param aNegative The text on the negative button of the dialog.
|
||||
* @return The dialog.
|
||||
*/
|
||||
public static QuestionDialog newInstance(int aID, String aTitle, String aMessage, String aPositive, String aNegative, Bundle aUserData)
|
||||
{
|
||||
// Create the output
|
||||
QuestionDialog result = new QuestionDialog();
|
||||
|
||||
// Fill the details
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("id", aID);
|
||||
args.putString("title", aTitle);
|
||||
args.putString("message", aMessage);
|
||||
args.putString("positive", aPositive);
|
||||
args.putString("negative", aNegative);
|
||||
args.putBundle("userdata", aUserData);
|
||||
result.setArguments(args);
|
||||
|
||||
// Done
|
||||
return result;
|
||||
}
|
||||
|
||||
Bundle getUserData()
|
||||
{
|
||||
return getArguments().getBundle("userdata");
|
||||
}
|
||||
|
||||
@Override public Dialog onCreateDialog(Bundle aState)
|
||||
{
|
||||
final Bundle args = getArguments();
|
||||
final int id = args.getInt("id");
|
||||
|
||||
// TODO: Use string resources
|
||||
AlertDialog result = new AlertDialog.Builder(getActivity())
|
||||
.setTitle(args.getString("title"))
|
||||
.setMessage(args.getString("message"))
|
||||
.setPositiveButton(args.getString("positive"), new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override public void onClick(DialogInterface UNUSED, int aWhich)
|
||||
{
|
||||
((QuestionHandler)getActivity()).onAnswer(id, QuestionDialog.this, true);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(args.getString("negative"), new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override public void onClick(DialogInterface UNUSED, int aWhich)
|
||||
{
|
||||
((QuestionHandler)getActivity()).onAnswer(id, QuestionDialog.this, false);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public void onCancel(DialogInterface aDialog)
|
||||
{
|
||||
((QuestionHandler)getActivity()).onAnswer(getArguments().getInt("id"), QuestionDialog.this, false);
|
||||
super.onCancel(aDialog);
|
||||
}
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
package org.andretro;
|
||||
import org.andretro.browser.*;
|
||||
import org.andretro.emulator.*;
|
||||
import org.andretro.settings.*;
|
||||
import org.andretro.system.*;
|
||||
import org.andretro.system.video.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.opengl.*;
|
||||
import android.os.*;
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
import android.graphics.*;
|
||||
|
||||
public class RetroDisplay extends android.support.v4.app.FragmentActivity implements QuestionDialog.QuestionHandler
|
||||
{
|
||||
private static final int CLOSE_GAME_QUESTION = 1;
|
||||
|
||||
private WindowManager windowManager;
|
||||
GLSurfaceView view;
|
||||
private boolean questionOpen;
|
||||
private boolean isPaused;
|
||||
private boolean showActionBar;
|
||||
private String moduleName;
|
||||
ModuleInfo moduleInfo;
|
||||
|
||||
@Override public void onCreate(Bundle aState)
|
||||
{
|
||||
super.onCreate(aState);
|
||||
|
||||
// Setup window
|
||||
windowManager = WindowManager.createBest();
|
||||
windowManager.setActivity(this);
|
||||
windowManager.windowCreating();
|
||||
|
||||
// Read state
|
||||
questionOpen = (null == aState) ? false : aState.getBoolean("questionOpen", false);
|
||||
windowManager.setOnScreenInput((null == aState) ? true : aState.getBoolean("onScreenInput", true));
|
||||
isPaused = (null == aState) ? false : aState.getBoolean("isPaused", false);
|
||||
showActionBar = (null == aState) ? true : aState.getBoolean("showActionBar", true);
|
||||
moduleName = getIntent().getStringExtra("moduleName");
|
||||
moduleInfo = ModuleInfo.getInfoAbout(this, new File(moduleName));
|
||||
|
||||
// Setup the view
|
||||
setContentView(R.layout.retro_display);
|
||||
|
||||
view = (GLSurfaceView)findViewById(R.id.renderer);
|
||||
view.setEGLContextClientVersion(2);
|
||||
view.setRenderer(Present.createRenderer(this));
|
||||
view.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
|
||||
view.setKeepScreenOn(true);
|
||||
|
||||
if(!Game.hasGame())
|
||||
{
|
||||
Game.queueCommand(new Commands.LoadGame(this, moduleName, new File(getIntent().getStringExtra("path"))));
|
||||
}
|
||||
|
||||
windowManager.windowCreated();
|
||||
}
|
||||
|
||||
@Override public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
windowManager.setupDisplay();
|
||||
view.onResume();
|
||||
}
|
||||
|
||||
@Override public void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
view.onPause();
|
||||
}
|
||||
|
||||
// QuestionDialog.QuestionHandler
|
||||
@Override public void onAnswer(int aID, QuestionDialog aDialog, boolean aPositive)
|
||||
{
|
||||
if(CLOSE_GAME_QUESTION == aID && questionOpen)
|
||||
{
|
||||
Game.queueCommand(new Commands.Pause(false));
|
||||
if(aPositive)
|
||||
{
|
||||
Game.queueCommand(new Commands.CloseGame().setCallback(new CommandQueue.Callback(this, new Runnable()
|
||||
{
|
||||
@Override public void run()
|
||||
{
|
||||
System.exit(0);
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
||||
questionOpen = false;
|
||||
windowManager.setupDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean dispatchTouchEvent(MotionEvent aEvent)
|
||||
{
|
||||
if(aEvent.getActionMasked() == MotionEvent.ACTION_DOWN)
|
||||
{
|
||||
windowManager.screenTouched(aEvent);
|
||||
}
|
||||
|
||||
// if(aEvent.getActionMasked() == MotionEvent.ACTION_DOWN || aEvent.getActionMasked() == MotionEvent.ACTION_MOVE)
|
||||
// {
|
||||
// final Rect imageArea = VertexData.getImageArea();
|
||||
//
|
||||
// final float xBase = (float)(aEvent.getX() - imageArea.left) / (float)imageArea.width();
|
||||
// final float yBase = (float)(aEvent.getY() - imageArea.top) / (float)imageArea.height();
|
||||
//
|
||||
// Input.setTouchData((short)(((xBase - .5f) * 2.0f) * 32767.0f), (short)(((yBase - .5f) * 2.0f) * 32767.0f), true);
|
||||
// }
|
||||
// else if(aEvent.getActionMasked() == MotionEvent.ACTION_UP)
|
||||
// {
|
||||
// Input.setTouchData((short)0, (short)0, false);
|
||||
// }
|
||||
|
||||
return super.dispatchTouchEvent(aEvent);
|
||||
}
|
||||
|
||||
@Override public boolean dispatchKeyEvent(KeyEvent aEvent)
|
||||
{
|
||||
int keyCode = aEvent.getKeyCode();
|
||||
|
||||
// Keys to never handle as game input
|
||||
if(keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_MENU)
|
||||
{
|
||||
return super.dispatchKeyEvent(aEvent);
|
||||
}
|
||||
|
||||
// Update game input structure
|
||||
Input.processEvent(aEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public void onBackPressed()
|
||||
{
|
||||
if(Game.hasGame())
|
||||
{
|
||||
if(!questionOpen)
|
||||
{
|
||||
Game.queueCommand(new Commands.Pause(true));
|
||||
QuestionDialog.newInstance(CLOSE_GAME_QUESTION, "Really Close Game?", "All unsaved data will be lost.", "Yes", "No", null).show(getSupportFragmentManager(), "mainfragment");
|
||||
|
||||
questionOpen = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onSaveInstanceState(Bundle aState)
|
||||
{
|
||||
super.onSaveInstanceState(aState);
|
||||
aState.putBoolean("questionOpen", questionOpen);
|
||||
aState.putBoolean("onScreenInput", windowManager.getOnScreenInput());
|
||||
aState.putBoolean("onPause", isPaused);
|
||||
aState.putBoolean("showActionBar", showActionBar);
|
||||
}
|
||||
|
||||
// Menu
|
||||
@Override public boolean onCreateOptionsMenu(Menu aMenu)
|
||||
{
|
||||
super.onCreateOptionsMenu(aMenu);
|
||||
getMenuInflater().inflate(R.menu.retro_display, aMenu);
|
||||
|
||||
aMenu.findItem(R.id.show_on_screen_input).setChecked(windowManager.getOnScreenInput());
|
||||
aMenu.findItem(R.id.pause).setChecked(isPaused);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void runCommandWithText(CommandQueue.BaseCommand aCommand, final String aText)
|
||||
{
|
||||
Game.queueCommand(aCommand.setCallback(new CommandQueue.Callback(this, new Runnable()
|
||||
{
|
||||
@Override public void run()
|
||||
{
|
||||
Toast.makeText(getApplicationContext(), aText, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
)));
|
||||
}
|
||||
|
||||
@Override public boolean onOptionsItemSelected(MenuItem aItem)
|
||||
{
|
||||
int itemID = aItem.getItemId();
|
||||
|
||||
switch(itemID)
|
||||
{
|
||||
case R.id.show_on_screen_input:
|
||||
{
|
||||
windowManager.setOnScreenInput(!aItem.isChecked());
|
||||
aItem.setChecked(windowManager.getOnScreenInput());
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.pause:
|
||||
{
|
||||
isPaused = !isPaused;
|
||||
aItem.setChecked(isPaused);
|
||||
|
||||
runCommandWithText(new Commands.Pause(isPaused), "Game " + (isPaused ? "Paused" : "Unpaused"));
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.input_method_select: ((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE)).showInputMethodPicker(); return true;
|
||||
|
||||
case R.id.screenshot: runCommandWithText(new Commands.TakeScreenShot(), "Screenshot Saved"); return true;
|
||||
case R.id.reset: runCommandWithText(new Commands.Reset(), "Game Reset"); return true;
|
||||
|
||||
case R.id.save_state: startActivity(new Intent(this, StateList.class).putExtra("moduleName", moduleName).putExtra("loading", false)); return true;
|
||||
case R.id.load_state: startActivity(new Intent(this, StateList.class).putExtra("moduleName", moduleName).putExtra("loading", true)); return true;
|
||||
case R.id.system_settings: startActivity(new Intent(this, SettingActivity.class).putExtra("moduleName", moduleName)); return true;
|
||||
|
||||
default: return super.onOptionsItemSelected(aItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,224 +0,0 @@
|
||||
package org.andretro;
|
||||
|
||||
import org.andretro.input.view.*;
|
||||
import org.andretro.system.*;
|
||||
|
||||
import android.annotation.*;
|
||||
import android.app.*;
|
||||
import android.view.*;
|
||||
|
||||
abstract class WindowManager
|
||||
{
|
||||
protected RetroDisplay activity;
|
||||
protected boolean onScreenInput = true;
|
||||
private boolean windowCreated;
|
||||
|
||||
public void setOnScreenInput(boolean aState)
|
||||
{
|
||||
if(onScreenInput != aState)
|
||||
{
|
||||
onScreenInput = aState;
|
||||
|
||||
if(windowCreated)
|
||||
{
|
||||
setupDisplay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getOnScreenInput()
|
||||
{
|
||||
return onScreenInput;
|
||||
}
|
||||
|
||||
public void setActivity(RetroDisplay aActivity)
|
||||
{
|
||||
activity = aActivity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called to set any paramters that need to be set before the window is created.
|
||||
*/
|
||||
public void windowCreating() { }
|
||||
public void windowCreated()
|
||||
{
|
||||
windowCreated = true;
|
||||
}
|
||||
|
||||
public void screenTouched(MotionEvent aEvent) { }
|
||||
|
||||
public void setupDisplay()
|
||||
{
|
||||
InputGroup inputBase = (InputGroup)activity.findViewById(R.id.base);
|
||||
inputBase.removeChildren();
|
||||
|
||||
if(onScreenInput)
|
||||
{
|
||||
inputBase.loadInputLayout(activity, activity.moduleInfo, activity.getResources().openRawResource(R.raw.default_retro_pad));
|
||||
}
|
||||
|
||||
Input.setOnScreenInput(onScreenInput ? inputBase : null);
|
||||
}
|
||||
|
||||
static public WindowManager createBest()
|
||||
{
|
||||
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
|
||||
{
|
||||
return new WindowManager_JellyBean();
|
||||
}
|
||||
else if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
{
|
||||
return new WindowManager_IceCreamSandwich();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new WindowManager_GingerBread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WindowManager_GingerBread extends WindowManager
|
||||
{
|
||||
@Override public void windowCreating()
|
||||
{
|
||||
super.windowCreating();
|
||||
activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(11) class WindowManager_ICSBase extends WindowManager
|
||||
{
|
||||
protected boolean uiFullscreen = false;
|
||||
protected int uiFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE;
|
||||
|
||||
@Override public void windowCreating()
|
||||
{
|
||||
super.windowCreating();
|
||||
|
||||
activity.requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
|
||||
}
|
||||
|
||||
@Override public void setupDisplay()
|
||||
{
|
||||
super.setupDisplay();
|
||||
|
||||
activity.view.setSystemUiVisibility(uiFlags);
|
||||
}
|
||||
|
||||
protected void setActionBarState()
|
||||
{
|
||||
final ActionBar bar = activity.getActionBar();
|
||||
|
||||
if(null != bar && !uiFullscreen)
|
||||
{
|
||||
bar.show();
|
||||
}
|
||||
else if(null != bar && uiFullscreen)
|
||||
{
|
||||
bar.hide();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean touchedOverActionBar(float aY)
|
||||
{
|
||||
final float barSize = 82.0f;
|
||||
return aY <= barSize;
|
||||
}
|
||||
|
||||
protected boolean toggleFullscreenOverActionBar(float aY)
|
||||
{
|
||||
final ActionBar bar = activity.getActionBar();
|
||||
|
||||
if(bar != null)
|
||||
{
|
||||
final boolean top = touchedOverActionBar(aY);
|
||||
|
||||
if(top == uiFullscreen)
|
||||
{
|
||||
uiFullscreen = !uiFullscreen;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(11) class WindowManager_IceCreamSandwich extends WindowManager_ICSBase
|
||||
{
|
||||
@Override public void setupDisplay()
|
||||
{
|
||||
super.setupDisplay();
|
||||
|
||||
super.setActionBarState();
|
||||
}
|
||||
|
||||
@Override public void screenTouched(MotionEvent aEvent)
|
||||
{
|
||||
super.screenTouched(aEvent);
|
||||
|
||||
if(toggleFullscreenOverActionBar(aEvent.getY()))
|
||||
{
|
||||
setupDisplay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(11) class WindowManager_JellyBean extends WindowManager_ICSBase
|
||||
{
|
||||
@Override public void windowCreated()
|
||||
{
|
||||
super.windowCreated();
|
||||
|
||||
activity.view.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener()
|
||||
{
|
||||
@Override public void onSystemUiVisibilityChange(int aVisibility)
|
||||
{
|
||||
if(!onScreenInput)
|
||||
{
|
||||
uiFullscreen = (aVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override public void setupDisplay()
|
||||
{
|
||||
uiFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE;
|
||||
|
||||
if(!onScreenInput)
|
||||
{
|
||||
uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
|
||||
|
||||
if(uiFullscreen)
|
||||
{
|
||||
uiFlags |= View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
super.setActionBarState();
|
||||
}
|
||||
|
||||
super.setupDisplay();
|
||||
}
|
||||
|
||||
@Override public void screenTouched(MotionEvent aEvent)
|
||||
{
|
||||
super.screenTouched(aEvent);
|
||||
|
||||
if(!onScreenInput)
|
||||
{
|
||||
if(!touchedOverActionBar(aEvent.getY()))
|
||||
{
|
||||
uiFullscreen = true;
|
||||
setupDisplay();
|
||||
}
|
||||
}
|
||||
else if(toggleFullscreenOverActionBar(aEvent.getY()))
|
||||
{
|
||||
setupDisplay();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
package org.andretro.browser;
|
||||
|
||||
import org.andretro.*;
|
||||
import org.andretro.settings.*;
|
||||
import org.andretro.emulator.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
import android.content.*;
|
||||
import android.app.*;
|
||||
import android.os.*;
|
||||
import android.widget.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.graphics.drawable.*;
|
||||
|
||||
class FileWrapper implements IconAdapterItem
|
||||
{
|
||||
public final File file;
|
||||
protected final int typeIndex;
|
||||
protected final boolean enabled;
|
||||
|
||||
public FileWrapper(File aFile, boolean aIsEnabled)
|
||||
{
|
||||
file = aFile;
|
||||
typeIndex = (file.isDirectory() ? 1 : 0) + (file.isFile() ? 2 : 0);
|
||||
enabled = aIsEnabled;
|
||||
}
|
||||
|
||||
@Override public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override public String getText()
|
||||
{
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
@Override public int getIconResourceId()
|
||||
{
|
||||
return file.isFile() ? R.drawable.file : R.drawable.folder;
|
||||
}
|
||||
|
||||
@Override public Drawable getIconDrawable()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public int compareTo(FileWrapper aOther)
|
||||
{
|
||||
if(null != aOther)
|
||||
{
|
||||
// Who says ternary is hard to follow
|
||||
if(isEnabled() == aOther.isEnabled())
|
||||
{
|
||||
return (typeIndex == aOther.typeIndex) ? file.compareTo(aOther.file) : ((typeIndex < aOther.typeIndex) ? -1 : 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return isEnabled() ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public class DirectoryActivity extends Activity implements AdapterView.OnItemClickListener
|
||||
{
|
||||
private IconAdapter<FileWrapper> adapter;
|
||||
private boolean inRoot;
|
||||
private String moduleName;
|
||||
private ModuleInfo moduleInfo;
|
||||
|
||||
@Override public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.line_list);
|
||||
|
||||
inRoot = getIntent().getBooleanExtra("inRoot", false);
|
||||
moduleName = getIntent().getStringExtra("moduleName");
|
||||
moduleInfo = ModuleInfo.getInfoAbout(this, new File(moduleName));
|
||||
|
||||
// Setup the list
|
||||
adapter = new IconAdapter<FileWrapper>(this, R.layout.line_list_item);
|
||||
ListView list = (ListView)findViewById(R.id.list);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
|
||||
// Load Directory
|
||||
final String path = getIntent().getStringExtra("path");;
|
||||
wrapFiles(new File(path));
|
||||
setTitle(path);
|
||||
}
|
||||
|
||||
@Override public void onItemClick(AdapterView<?> aListView, View aView, int aPosition, long aID)
|
||||
{
|
||||
final File selected = adapter.getItem(aPosition).file;
|
||||
|
||||
final Intent intent = new Intent(this, selected.isFile() ? RetroDisplay.class : DirectoryActivity.class)
|
||||
.putExtra("path", selected.getAbsolutePath())
|
||||
.putExtra("moduleName", moduleName)
|
||||
.putExtra("inRoot", inRoot);
|
||||
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override public boolean onCreateOptionsMenu(Menu aMenu)
|
||||
{
|
||||
super.onCreateOptionsMenu(aMenu);
|
||||
getMenuInflater().inflate(R.menu.directory_list, aMenu);
|
||||
|
||||
if(inRoot)
|
||||
{
|
||||
aMenu.removeItem(R.id.goto_root);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean onOptionsItemSelected(MenuItem aItem)
|
||||
{
|
||||
if(R.id.goto_root == aItem.getItemId())
|
||||
{
|
||||
startActivity(new Intent(this, DirectoryActivity.class)
|
||||
.putExtra("inRoot", true)
|
||||
.putExtra("path", "/mnt/")
|
||||
.putExtra("moduleName", moduleName));
|
||||
return true;
|
||||
}
|
||||
|
||||
if(R.id.input_method_select == aItem.getItemId())
|
||||
{
|
||||
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showInputMethodPicker();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(aItem.getItemId() == R.id.system_settings)
|
||||
{
|
||||
startActivity(new Intent(this, SettingActivity.class)
|
||||
.putExtra("moduleName", moduleName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(aItem);
|
||||
}
|
||||
|
||||
private void wrapFiles(File aDirectory)
|
||||
{
|
||||
if(null == aDirectory || !aDirectory.isDirectory())
|
||||
{
|
||||
throw new IllegalArgumentException("Directory is not valid.");
|
||||
}
|
||||
|
||||
// Copy new items
|
||||
for(File file: aDirectory.listFiles())
|
||||
{
|
||||
adapter.add(new FileWrapper(file, file.isDirectory() || moduleInfo.isFileValid(file)));
|
||||
}
|
||||
|
||||
// Sort items
|
||||
adapter.sort(new Comparator<FileWrapper>()
|
||||
{
|
||||
@Override public int compare(FileWrapper aLeft, FileWrapper aRight)
|
||||
{
|
||||
return aLeft.compareTo(aRight);
|
||||
};
|
||||
});
|
||||
|
||||
// Update
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package org.andretro.browser;
|
||||
|
||||
import org.andretro.*;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.graphics.drawable.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
interface IconAdapterItem
|
||||
{
|
||||
public abstract boolean isEnabled();
|
||||
public abstract String getText();
|
||||
public abstract int getIconResourceId();
|
||||
public abstract Drawable getIconDrawable();
|
||||
}
|
||||
|
||||
class IconAdapter<T extends IconAdapterItem> extends ArrayAdapter<T>
|
||||
{
|
||||
private final int layout;
|
||||
|
||||
public IconAdapter(Activity aContext, int aLayout)
|
||||
{
|
||||
super(aContext, aLayout);
|
||||
|
||||
layout = aLayout;
|
||||
}
|
||||
|
||||
@Override public View getView(int aPosition, View aConvertView, ViewGroup aParent)
|
||||
{
|
||||
// Build the view
|
||||
if(aConvertView == null)
|
||||
{
|
||||
LayoutInflater inflater = (LayoutInflater)aParent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
aConvertView = inflater.inflate(layout, aParent, false);
|
||||
}
|
||||
|
||||
// Fill the view
|
||||
IconAdapterItem item = getItem(aPosition);
|
||||
final boolean enabled = item.isEnabled();
|
||||
|
||||
TextView textView = (TextView)aConvertView.findViewById(R.id.name);
|
||||
if(null != textView)
|
||||
{
|
||||
textView.setText(item.getText());
|
||||
textView.setEnabled(enabled);
|
||||
}
|
||||
|
||||
ImageView imageView = (ImageView)aConvertView.findViewById(R.id.icon);
|
||||
if(null != imageView)
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
final int id = item.getIconResourceId();
|
||||
if(0 != id)
|
||||
{
|
||||
imageView.setImageResource(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
imageView.setImageDrawable(item.getIconDrawable());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
imageView.setImageDrawable(null);
|
||||
}
|
||||
}
|
||||
|
||||
return aConvertView;
|
||||
}
|
||||
|
||||
@Override public boolean isEnabled(int aPosition)
|
||||
{
|
||||
return getItem(aPosition).isEnabled();
|
||||
}
|
||||
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
package org.andretro.browser;
|
||||
|
||||
import org.andretro.*;
|
||||
import org.andretro.emulator.*;
|
||||
import org.andretro.system.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import android.content.*;
|
||||
import android.app.*;
|
||||
import android.os.*;
|
||||
import android.widget.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.graphics.drawable.*;
|
||||
|
||||
class ModuleWrapper implements IconAdapterItem
|
||||
{
|
||||
public final File file;
|
||||
public final ModuleInfo info;
|
||||
|
||||
public ModuleWrapper(Context aContext, File aFile) throws IOException
|
||||
{
|
||||
file = aFile;
|
||||
info = ModuleInfo.getInfoAbout(aContext, aFile);
|
||||
}
|
||||
|
||||
@Override public boolean isEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public String getText()
|
||||
{
|
||||
return info.name;
|
||||
}
|
||||
|
||||
@Override public int getIconResourceId()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public Drawable getIconDrawable()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ModuleActivity extends Activity implements AdapterView.OnItemClickListener
|
||||
{
|
||||
// HACK: Hard path
|
||||
private static final String modulePath = "/data/data/org.andretro/lib/";
|
||||
private IconAdapter<ModuleWrapper> adapter;
|
||||
|
||||
@Override public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.line_list);
|
||||
|
||||
// Setup the list
|
||||
adapter = new IconAdapter<ModuleWrapper>(this, R.layout.line_list_item);
|
||||
ListView list = (ListView)findViewById(R.id.list);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
|
||||
setTitle("Select Emulator");
|
||||
|
||||
for(final File lib: new File(modulePath).listFiles())
|
||||
{
|
||||
if(lib.getName().startsWith("libretro_"))
|
||||
{
|
||||
try
|
||||
{
|
||||
adapter.add(new ModuleWrapper(this, lib));;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Logger.d("Couldn't add module: " + lib.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onItemClick(AdapterView<?> aListView, View aView, int aPosition, long aID)
|
||||
{
|
||||
final ModuleWrapper item = adapter.getItem(aPosition);
|
||||
|
||||
startActivity(new Intent(ModuleActivity.this, DirectoryActivity.class)
|
||||
.putExtra("path", item.info.getDataPath() + "/Games")
|
||||
.putExtra("moduleName", item.file.getAbsolutePath()));
|
||||
}
|
||||
|
||||
@Override public boolean onCreateOptionsMenu(Menu aMenu)
|
||||
{
|
||||
super.onCreateOptionsMenu(aMenu);
|
||||
getMenuInflater().inflate(R.menu.directory_list, aMenu);
|
||||
|
||||
aMenu.removeItem(R.id.goto_root);
|
||||
aMenu.removeItem(R.id.system_settings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean onOptionsItemSelected(MenuItem aItem)
|
||||
{
|
||||
if(R.id.input_method_select == aItem.getItemId())
|
||||
{
|
||||
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showInputMethodPicker();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(aItem);
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
package org.andretro.browser;
|
||||
|
||||
import org.andretro.*;
|
||||
import org.andretro.emulator.*;
|
||||
|
||||
import android.app.*;
|
||||
import android.graphics.drawable.*;
|
||||
import android.os.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
class SlotWrapper implements IconAdapterItem
|
||||
{
|
||||
public final int slot;
|
||||
public final boolean enabled;
|
||||
public final String text;
|
||||
public final Drawable thumbNail;
|
||||
|
||||
public SlotWrapper(int aSlot, boolean aLoading)
|
||||
{
|
||||
slot = aSlot;
|
||||
|
||||
final File slotFile = new File(Game.getGameDataName("SaveStates", "st" + aSlot));
|
||||
final boolean hasSlotFile = slotFile.isFile() && slotFile.exists();
|
||||
final String slotFileDate = hasSlotFile ? DateFormat.getDateTimeInstance().format(new Date(slotFile.lastModified())) : "EMPTY";
|
||||
|
||||
enabled = !aLoading || hasSlotFile;
|
||||
text = "Slot " + aSlot + " (" + slotFileDate + ")";
|
||||
|
||||
// Get thumb
|
||||
final File thumbFile = new File(Game.getGameDataName("SaveStates", "tb" + aSlot));
|
||||
thumbNail = thumbFile.isFile() ? Drawable.createFromPath(thumbFile.getAbsolutePath()) : null;
|
||||
}
|
||||
|
||||
@Override public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override public String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override public int getIconResourceId()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public Drawable getIconDrawable()
|
||||
{
|
||||
return thumbNail;
|
||||
}
|
||||
}
|
||||
|
||||
public class StateList extends Activity implements AdapterView.OnItemClickListener
|
||||
{
|
||||
private IconAdapter<SlotWrapper> adapter;
|
||||
private boolean loading;
|
||||
|
||||
@Override public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.icon_grid_list);
|
||||
|
||||
loading = getIntent().getBooleanExtra("loading", false);
|
||||
|
||||
|
||||
// Setup the list
|
||||
adapter = new IconAdapter<SlotWrapper>(this, R.layout.icon_grid_item);
|
||||
GridView list = (GridView)findViewById(R.id.list);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
|
||||
setTitle(loading ? "Load State" : "Save State");
|
||||
|
||||
// Add data
|
||||
for(int i = 0; i != 10; i ++)
|
||||
{
|
||||
adapter.add(new SlotWrapper(i, loading));
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onItemClick(AdapterView<?> aListView, View aView, int aPosition, long aID)
|
||||
{
|
||||
Game.queueCommand(new Commands.StateAction(loading, aPosition));
|
||||
finish();
|
||||
}
|
||||
}
|
@ -1,188 +0,0 @@
|
||||
package org.andretro.emulator;
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
import android.content.*;
|
||||
import android.content.pm.*;
|
||||
import android.view.*;
|
||||
import android.app.*;
|
||||
|
||||
import org.andretro.system.*;
|
||||
import org.andretro.system.video.*;
|
||||
import org.libretro.LibRetro;
|
||||
|
||||
public final class Commands
|
||||
{
|
||||
public static final class LoadGame extends CommandQueue.BaseCommand
|
||||
{
|
||||
private final Activity activity;
|
||||
private final String library;
|
||||
private final File file;
|
||||
|
||||
public LoadGame(Activity aActivity, String aLibrary, File aFile)
|
||||
{
|
||||
activity = aActivity;
|
||||
library = aLibrary;
|
||||
file = aFile;
|
||||
|
||||
if(null == activity || null == library || null == aFile)
|
||||
{
|
||||
throw new NullPointerException("Neither aActivity, aLibrary nor aFile may be null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void perform()
|
||||
{
|
||||
Game.loadGame(activity, library, file);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CloseGame extends CommandQueue.BaseCommand
|
||||
{
|
||||
@Override protected void perform()
|
||||
{
|
||||
Game.closeGame();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Reset extends CommandQueue.BaseCommand
|
||||
{
|
||||
@Override protected void perform()
|
||||
{
|
||||
LibRetro.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TakeScreenShot extends CommandQueue.BaseCommand
|
||||
{
|
||||
@Override protected void perform()
|
||||
{
|
||||
Game.screenShotName = Game.getGameDataName("ScreenShots", DateFormat.getDateTimeInstance().format(new Date()) + ".png");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class StateAction extends CommandQueue.BaseCommand
|
||||
{
|
||||
private final boolean load;
|
||||
private final int slot;
|
||||
|
||||
public StateAction(boolean aLoad, int aSlot)
|
||||
{
|
||||
load = aLoad;
|
||||
|
||||
slot = aSlot;
|
||||
if(slot < 0 || slot > 9)
|
||||
{
|
||||
throw new RuntimeException("Slot must be in the range of 0-9");
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void perform()
|
||||
{
|
||||
if(load)
|
||||
{
|
||||
LibRetro.unserializeFromFile(Game.getGameDataName("SaveStates", "st" + slot));
|
||||
}
|
||||
else
|
||||
{
|
||||
LibRetro.serializeToFile(Game.getGameDataName("SaveStates", "st" + slot));
|
||||
Game.screenShotName = Game.getGameDataName("SaveStates", "tb" + slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Pause extends CommandQueue.BaseCommand
|
||||
{
|
||||
private final boolean pause;
|
||||
|
||||
public Pause(boolean aPause)
|
||||
{
|
||||
pause = aPause;
|
||||
}
|
||||
|
||||
@Override protected void perform()
|
||||
{
|
||||
if(0 == Game.pauseDepth && !pause)
|
||||
{
|
||||
throw new RuntimeException("Internal Error: Emulator was unpaused too many times (Please Report).");
|
||||
}
|
||||
|
||||
Game.pauseDepth += pause ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class RefreshInput extends CommandQueue.BaseCommand
|
||||
{
|
||||
@Override protected void perform()
|
||||
{
|
||||
// TODO
|
||||
LibRetro.setControllerPortDevice(0, LibRetro.RETRO_DEVICE_JOYPAD);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class RefreshSettings extends CommandQueue.BaseCommand
|
||||
{
|
||||
private final SharedPreferences settings;
|
||||
|
||||
public RefreshSettings(SharedPreferences aSettings)
|
||||
{
|
||||
settings = aSettings;
|
||||
|
||||
if(null == aSettings)
|
||||
{
|
||||
throw new RuntimeException("aSettings may not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void perform()
|
||||
{
|
||||
// Scaling
|
||||
Present.Texture.setSmoothMode(settings.getBoolean("scaling_smooth", true));
|
||||
|
||||
final String aspectMode = settings.getString("scaling_aspect_mode", "Default");
|
||||
if("Default".equals(aspectMode))
|
||||
{
|
||||
VertexData.setForcedAspect(false, 0.0f);
|
||||
}
|
||||
else if("4:3".equals(aspectMode))
|
||||
{
|
||||
VertexData.setForcedAspect(true, 1.3333333f);
|
||||
}
|
||||
else if("Pixel".equals(aspectMode))
|
||||
{
|
||||
VertexData.setForcedAspect(true, -1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
VertexData.setForcedAspect(false, 0.0f);
|
||||
}
|
||||
|
||||
// Orientation
|
||||
final String orientMode = settings.getString("scaling_orientation", "Sensor");
|
||||
if("Portrait".equals(orientMode))
|
||||
{
|
||||
Game.loadingActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
else if("Landscape".equals(orientMode))
|
||||
{
|
||||
Game.loadingActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.loadingActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
|
||||
}
|
||||
|
||||
// Fast forward
|
||||
Game.fastForwardDefault = settings.getBoolean("fast_forward_default", false);
|
||||
Game.fastForwardSpeed = Integer.parseInt(settings.getString("fast_forward_speed", "4"));
|
||||
Game.fastForwardKey = settings.getInt("fast_forward_key", KeyEvent.KEYCODE_BUTTON_R2);
|
||||
|
||||
// Rewind
|
||||
final boolean rewindEnabled = settings.getBoolean("rewind_enabled", false);
|
||||
final int rewindDataSize = Integer.parseInt(settings.getString("rewind_buffer_size", "16")) * 1024 * 1024;
|
||||
LibRetro.setupRewinder(rewindEnabled ? rewindDataSize : 0);
|
||||
Game.rewindKey = settings.getInt("rewind_key", KeyEvent.KEYCODE_BUTTON_L2);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
package org.andretro.emulator;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import android.content.*;
|
||||
import org.w3c.dom.*;
|
||||
|
||||
public final class Doodads
|
||||
{
|
||||
private static abstract class NamedInput
|
||||
{
|
||||
/**
|
||||
* The short name of the input. Best used for setting keys.
|
||||
*/
|
||||
public final String name;
|
||||
|
||||
/**
|
||||
* The friendly name of the input. Best used for display.
|
||||
*/
|
||||
public final String fullName;
|
||||
|
||||
/**
|
||||
* Construct a new NamedInput.
|
||||
* @param aShort The setting name of the input. May not be null.
|
||||
* @param aFull The display name of the input. May not be null.
|
||||
*/
|
||||
NamedInput(String aShort, String aFull)
|
||||
{
|
||||
if(null == aShort || null == aFull)
|
||||
{
|
||||
throw new IllegalArgumentException("Neither name of a NamedInput may be null.");
|
||||
}
|
||||
|
||||
name = aShort;
|
||||
fullName = aFull;
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class GroupedInput <E extends NamedInput> extends NamedInput
|
||||
{
|
||||
/**
|
||||
* List of input objects.
|
||||
*/
|
||||
protected final ArrayList<E> inputs;
|
||||
|
||||
/**
|
||||
* Create a new GroupedInput.
|
||||
* @param aShort Setting name for the input. May not be null.
|
||||
* @param aFull Display name for the input. May not be null.
|
||||
* @param aCount Number of devices in this set.
|
||||
*/
|
||||
GroupedInput(String aShort, String aFull)
|
||||
{
|
||||
super(aShort, aFull);
|
||||
|
||||
inputs = new ArrayList<E>();
|
||||
}
|
||||
|
||||
public int getCount()
|
||||
{
|
||||
return inputs.size();
|
||||
}
|
||||
|
||||
public ArrayList<E> getAll()
|
||||
{
|
||||
return inputs;
|
||||
}
|
||||
|
||||
public E getItem(int aIndex)
|
||||
{
|
||||
return inputs.get(aIndex);
|
||||
}
|
||||
|
||||
public E getItem(String aName)
|
||||
{
|
||||
for(E i: inputs)
|
||||
{
|
||||
if(aName.equals(i.name))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public final static class Button extends NamedInput
|
||||
{
|
||||
public final String configKey;
|
||||
public final int bitOffset;
|
||||
private int keyCode;
|
||||
|
||||
public static final String[] names = {"UP", "DOWN", "LEFT", "RIGHT", "A", "B", "X", "Y", "SELECT", "START", "L1", "R1", "L2", "R2", "L3", "R3"};
|
||||
public static final int[] offsets = {4, 5, 6, 7, 8, 0, 9, 1, 2, 3, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
Button(SharedPreferences aPreferences, String aKeyBase, Element aData)
|
||||
{
|
||||
super(aData.getAttribute("shortname"), aData.getAttribute("fullname"));
|
||||
|
||||
// Get configKey
|
||||
configKey = aKeyBase + "_" + name;
|
||||
|
||||
// Get value
|
||||
keyCode = aPreferences.getInt(configKey, 0);
|
||||
|
||||
// Grab native data
|
||||
final String keyName = aData.getAttribute("mappedkey");
|
||||
for(int i = 0; i != 16; i ++)
|
||||
{
|
||||
if(names[i].equals(keyName))
|
||||
{
|
||||
bitOffset = offsets[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Mapped key " + keyName + " not found");
|
||||
}
|
||||
|
||||
public int getKeyCode()
|
||||
{
|
||||
return keyCode;
|
||||
}
|
||||
|
||||
public void setKeyCode(int aKeyCode)
|
||||
{
|
||||
keyCode = aKeyCode;
|
||||
}
|
||||
}
|
||||
|
||||
public final static class Device extends GroupedInput<Button>
|
||||
{
|
||||
Device(SharedPreferences aPreferences, String aKeyBase, Element aData)
|
||||
{
|
||||
super(aData.getAttribute("shortname"), aData.getAttribute("fullname"));
|
||||
|
||||
final NodeList buttons = aData.getElementsByTagName("button");
|
||||
for(int i = 0; i != buttons.getLength(); i ++)
|
||||
{
|
||||
inputs.add(i, new Button(aPreferences, aKeyBase + "_" + name, (Element)buttons.item(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final static class Port extends GroupedInput<Device>
|
||||
{
|
||||
public final String defaultDevice;
|
||||
private final String currentDevice;
|
||||
|
||||
Port(SharedPreferences aPreferences, String aKeyBase, Element aData)
|
||||
{
|
||||
super(aData.getAttribute("shortname"), aData.getAttribute("fullname"));
|
||||
defaultDevice = aData.getAttribute("defaultdevice");
|
||||
currentDevice = aPreferences.getString(aKeyBase + "_" + name, defaultDevice);
|
||||
|
||||
final NodeList devices = aData.getElementsByTagName("device");
|
||||
for(int i = 0; i != devices.getLength(); i ++)
|
||||
{
|
||||
inputs.add(i, new Device(aPreferences, aKeyBase + "_" + name, (Element)devices.item(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public String getCurrentDevice()
|
||||
{
|
||||
return currentDevice;
|
||||
}
|
||||
}
|
||||
|
||||
public final static class Set extends GroupedInput<Port>
|
||||
{
|
||||
Set(SharedPreferences aPreferences, String aKeyBase, Element aData)
|
||||
{
|
||||
super("root", "root");
|
||||
|
||||
final NodeList ports = aData.getElementsByTagName("port");
|
||||
for(int i = 0; i != ports.getLength(); i ++)
|
||||
{
|
||||
inputs.add(new Port(aPreferences, aKeyBase, (Element)ports.item(i)));
|
||||
}
|
||||
}
|
||||
|
||||
// Implement
|
||||
public Doodads.Port getPort(int aPort)
|
||||
{
|
||||
return getItem(aPort);
|
||||
}
|
||||
|
||||
public Doodads.Device getDevice(int aPort, int aDevice)
|
||||
{
|
||||
return getItem(aPort).getItem(aDevice);
|
||||
}
|
||||
|
||||
public Doodads.Button getButton(int aPort, int aDevice, int aIndex)
|
||||
{
|
||||
return getItem(aPort).getItem(aDevice).getItem(aIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
package org.andretro.emulator;
|
||||
|
||||
import org.andretro.system.*;
|
||||
import org.libretro.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import android.app.*;
|
||||
|
||||
public final class Game
|
||||
{
|
||||
// Singleton
|
||||
static
|
||||
{
|
||||
System.loadLibrary("retroiface");
|
||||
|
||||
if(!LibRetro.nativeInit())
|
||||
{
|
||||
throw new RuntimeException("Failed to initialize JNI classes.");
|
||||
}
|
||||
}
|
||||
|
||||
// Thread
|
||||
private static final CommandQueue eventQueue = new CommandQueue();
|
||||
|
||||
public static void queueCommand(final CommandQueue.BaseCommand aCommand)
|
||||
{
|
||||
eventQueue.queueCommand(aCommand);
|
||||
}
|
||||
|
||||
// Game Info
|
||||
static int pauseDepth;
|
||||
|
||||
// Fast forward
|
||||
static int fastForwardKey;
|
||||
static int fastForwardSpeed = 1;
|
||||
static boolean fastForwardDefault;
|
||||
static int rewindKey;
|
||||
static String screenShotName;
|
||||
|
||||
// Functions to retrieve game data, careful as the data may be null, or outdated!
|
||||
public static String getGameDataName(String aSubDirectory, String aExtension)
|
||||
{
|
||||
final File dir = new File(moduleInfo.getDataPath() + "/" + aSubDirectory);
|
||||
if(!dir.exists() && !dir.mkdirs())
|
||||
{
|
||||
throw new RuntimeException("Failed to make data directory");
|
||||
}
|
||||
|
||||
return moduleInfo.getDataPath() + "/" + aSubDirectory + "/" + dataName + "." + aExtension;
|
||||
}
|
||||
|
||||
// LIBRARY
|
||||
static Activity loadingActivity;
|
||||
private static ModuleInfo moduleInfo;
|
||||
private static boolean gameLoaded;
|
||||
private static boolean gameClosed;
|
||||
private static LibRetro.SystemInfo systemInfo = new LibRetro.SystemInfo();
|
||||
private static LibRetro.AVInfo avInfo = new LibRetro.AVInfo();
|
||||
private static String dataName;
|
||||
|
||||
static void loadGame(Activity aActivity, String aLibrary, File aFile)
|
||||
{
|
||||
if(!gameLoaded && !gameClosed && null != aFile && aFile.isFile())
|
||||
{
|
||||
moduleInfo = ModuleInfo.getInfoAbout(aActivity, new File(aLibrary));
|
||||
|
||||
if(LibRetro.loadLibrary(aLibrary, moduleInfo.getDataPath()))
|
||||
{
|
||||
LibRetro.init();
|
||||
|
||||
if(LibRetro.loadGame(aFile.getAbsolutePath()))
|
||||
{
|
||||
// System info
|
||||
LibRetro.getSystemInfo(systemInfo);
|
||||
LibRetro.getSystemAVInfo(avInfo);
|
||||
|
||||
// Filesystem stuff
|
||||
dataName = aFile.getName().split("\\.(?=[^\\.]+$)")[0];
|
||||
LibRetro.readMemoryRegion(LibRetro.RETRO_MEMORY_SAVE_RAM, getGameDataName("SaveRAM", "srm"));
|
||||
LibRetro.readMemoryRegion(LibRetro.RETRO_MEMORY_RTC, getGameDataName("SaveRAM", "rtc"));
|
||||
|
||||
// Load settings
|
||||
loadingActivity = aActivity;
|
||||
new Commands.RefreshSettings(aActivity.getSharedPreferences(moduleInfo.getDataName(), 0)).run();
|
||||
new Commands.RefreshInput().run();
|
||||
|
||||
gameLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gameLoaded = true;
|
||||
gameClosed = true;
|
||||
throw new RuntimeException("Failed to load game");
|
||||
}
|
||||
}
|
||||
|
||||
static void closeGame()
|
||||
{
|
||||
if(gameLoaded && !gameClosed)
|
||||
{
|
||||
LibRetro.writeMemoryRegion(LibRetro.RETRO_MEMORY_SAVE_RAM, getGameDataName("SaveRAM", "srm"));
|
||||
LibRetro.writeMemoryRegion(LibRetro.RETRO_MEMORY_RTC, getGameDataName("SaveRAM", "rtc"));
|
||||
|
||||
LibRetro.unloadGame();
|
||||
LibRetro.deinit();
|
||||
LibRetro.unloadLibrary();
|
||||
|
||||
// Shutdown any audio device
|
||||
Audio.close();
|
||||
|
||||
gameClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasGame()
|
||||
{
|
||||
return gameLoaded && !gameClosed;
|
||||
}
|
||||
|
||||
// LOOP
|
||||
public static boolean doFrame(LibRetro.VideoFrame aFrame)
|
||||
{
|
||||
eventQueue.pump();
|
||||
|
||||
if(gameLoaded && !gameClosed && 0 == pauseDepth)
|
||||
{
|
||||
// Fast forward
|
||||
aFrame.rewind = Input.isPressed(rewindKey);
|
||||
|
||||
final boolean fastKeyPressed = Input.isPressed(fastForwardKey);
|
||||
final int frameToggle = fastForwardDefault ? 1 : fastForwardSpeed;
|
||||
final int frameTarget = fastForwardDefault ? fastForwardSpeed : 1;
|
||||
aFrame.framesToRun = (fastKeyPressed) ? frameToggle : frameTarget;
|
||||
|
||||
// Write any pending screen shots
|
||||
if(null != screenShotName && !aFrame.restarted)
|
||||
{
|
||||
PngWriter.write(screenShotName);
|
||||
screenShotName = null;
|
||||
}
|
||||
|
||||
// Get input data
|
||||
Input.poolKeyboard(aFrame.keyboard);
|
||||
aFrame.buttons[0] = Input.getBits(moduleInfo.inputData.getDevice(0, 0));
|
||||
aFrame.touchX = Input.getTouchX();
|
||||
aFrame.touchY = Input.getTouchY();
|
||||
aFrame.touched = Input.getTouched();
|
||||
|
||||
//Emulate
|
||||
LibRetro.run(aFrame);
|
||||
|
||||
// Present
|
||||
if(0 != aFrame.audioSamples)
|
||||
{
|
||||
Audio.write((int)avInfo.sampleRate, aFrame.audio, aFrame.audioSamples);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,107 +0,0 @@
|
||||
package org.andretro.emulator;
|
||||
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.xml.parsers.*;
|
||||
import javax.xml.xpath.*;
|
||||
import org.w3c.dom.*;
|
||||
|
||||
public class ModuleInfo
|
||||
{
|
||||
// TODO: Make them not public!
|
||||
public String name;
|
||||
public String shortName;
|
||||
public String libraryName;
|
||||
public String[] extensions;
|
||||
|
||||
public String dataPath;
|
||||
|
||||
private Document document;
|
||||
private Element onScreenInputData;
|
||||
public final Doodads.Set inputData;
|
||||
|
||||
private static final Map<String, ModuleInfo> cache = new HashMap<String, ModuleInfo>();
|
||||
|
||||
public static ModuleInfo getInfoAbout(final Context aContext, final File aFile)
|
||||
{
|
||||
final String key = aFile.getName() + ".xml";
|
||||
|
||||
if(cache.containsKey(key))
|
||||
{
|
||||
return cache.get(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModuleInfo newInfo = new ModuleInfo(aContext, aFile);
|
||||
cache.put(key, newInfo);
|
||||
return newInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private ModuleInfo(final Context aContext, final File aFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Why does xml have to be so god damned difficult?
|
||||
document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(aContext.getAssets().open(aFile.getName() + ".xml"));
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
|
||||
// Read system info
|
||||
Element system = (Element)xpath.evaluate("/retro/system", document, XPathConstants.NODE);
|
||||
name = system.getAttribute("fullname");
|
||||
shortName = system.getAttribute("shortname");
|
||||
|
||||
// Read module info
|
||||
Element module = (Element)xpath.evaluate("/retro/module", document, XPathConstants.NODE);
|
||||
libraryName = module.getAttribute("libraryname");
|
||||
extensions = module.getAttribute("extensions").split("\\|");
|
||||
Arrays.sort(extensions);
|
||||
|
||||
// Read input element
|
||||
onScreenInputData = (Element)xpath.evaluate("/retro/onscreeninput", document, XPathConstants.NODE);
|
||||
inputData = new Doodads.Set(aContext.getSharedPreferences(libraryName, 0), "input", (Element)xpath.evaluate("/retro/input", document, XPathConstants.NODE));
|
||||
|
||||
// Quick check hack
|
||||
if(null == name || null == shortName || null == libraryName || null == extensions)
|
||||
{
|
||||
throw new Exception("Not all elements present in xml");
|
||||
}
|
||||
|
||||
// Build Directories
|
||||
dataPath = Environment.getExternalStorageDirectory().getPath() + "/andretro/" + libraryName;
|
||||
new File(dataPath + "/Games").mkdirs();
|
||||
}
|
||||
catch(final Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getDataName()
|
||||
{
|
||||
return libraryName;
|
||||
}
|
||||
|
||||
public String getDataPath()
|
||||
{
|
||||
return dataPath;
|
||||
}
|
||||
|
||||
public boolean isFileValid(File aFile)
|
||||
{
|
||||
final String path = aFile.getAbsolutePath();
|
||||
final int dot = path.lastIndexOf(".");
|
||||
final String extension = (dot < 0) ? null : path.substring(dot + 1).toLowerCase();
|
||||
|
||||
return (null == extension) ? false : (0 <= Arrays.binarySearch(extensions, extension));
|
||||
}
|
||||
|
||||
public Element getOnScreenInputDefinition()
|
||||
{
|
||||
return onScreenInputData;
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package org.andretro.input.view;
|
||||
|
||||
import org.andretro.*;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.w3c.dom.*;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class Button extends ImageView implements InputGroup.InputHandler
|
||||
{
|
||||
int touchCount = 0;
|
||||
int bits;
|
||||
|
||||
public Button(Context aContext, Element aElement)
|
||||
{
|
||||
super(aContext);
|
||||
setImageResource(R.drawable.button);
|
||||
|
||||
bits = InputGroup.getInt(aElement, "bits");
|
||||
}
|
||||
|
||||
@Override public int getBits(int aX, int aY)
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package org.andretro.input.view;
|
||||
import org.andretro.*;
|
||||
import org.w3c.dom.*;
|
||||
|
||||
import android.annotation.*;
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ButtonDiamond extends ImageView implements InputGroup.InputHandler
|
||||
{
|
||||
private final int bits[] = new int[4];
|
||||
|
||||
public ButtonDiamond(Context aContext, Element aElement)
|
||||
{
|
||||
super(aContext);
|
||||
setImageResource(R.drawable.dpad);
|
||||
|
||||
bits[0] = InputGroup.getInt(aElement, "upbits");
|
||||
bits[1] = InputGroup.getInt(aElement, "downbits");
|
||||
bits[2] = InputGroup.getInt(aElement, "leftbits");
|
||||
bits[3] = InputGroup.getInt(aElement, "rightbits");
|
||||
}
|
||||
|
||||
@Override public int getBits(int aX, int aY)
|
||||
{
|
||||
final int w = getWidth() / 3;
|
||||
final int h = getHeight() / 3;
|
||||
|
||||
final int x = aX - getLeft();
|
||||
final int y = aY - getTop();
|
||||
|
||||
int result = 0;
|
||||
result |= (x < w) ? bits[2] : 0;
|
||||
result |= (x > w * 2) ? bits[3] : 0;
|
||||
result |= (y < h) ? bits[0] : 0;
|
||||
result |= (y > h * 2) ? bits[1] : 0;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package org.andretro.input.view;
|
||||
import org.andretro.*;
|
||||
import org.w3c.dom.*;
|
||||
|
||||
import android.annotation.*;
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ButtonDuo extends ImageView implements InputGroup.InputHandler
|
||||
{
|
||||
int currentBits = 0;
|
||||
int bits[] = new int[2];
|
||||
|
||||
public ButtonDuo(Context aContext, Element aElement)
|
||||
{
|
||||
super(aContext);
|
||||
|
||||
setImageResource(R.drawable.buttonduo);
|
||||
|
||||
bits[0] = InputGroup.getInt(aElement, "leftbits");
|
||||
bits[1] = InputGroup.getInt(aElement, "rightbits");
|
||||
}
|
||||
|
||||
@Override public int getBits(int aX, int aY)
|
||||
{
|
||||
final int x = aX - getLeft();
|
||||
final int width = getWidth() / 3;
|
||||
|
||||
int result = (x < width * 2) ? bits[0] : 0;
|
||||
result |= (x > width) ? bits[1] : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
package org.andretro.input.view;
|
||||
import org.andretro.emulator.*;
|
||||
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import android.content.*;
|
||||
import android.widget.*;
|
||||
import android.app.*;
|
||||
import android.graphics.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.xml.parsers.*;
|
||||
import org.w3c.dom.*;
|
||||
|
||||
public class InputGroup extends RelativeLayout
|
||||
{
|
||||
public static interface InputHandler
|
||||
{
|
||||
int getBits(int aX, int aY);
|
||||
}
|
||||
|
||||
private static class Handler
|
||||
{
|
||||
final Rect area = new Rect();
|
||||
final View view;
|
||||
|
||||
public Handler(View aHandler)
|
||||
{
|
||||
if(!(aHandler instanceof InputHandler))
|
||||
{
|
||||
throw new RuntimeException("aHandler must be an object that implements the InputHandler interface.");
|
||||
}
|
||||
|
||||
view = aHandler;
|
||||
}
|
||||
|
||||
public int getBits(int aX, int aY)
|
||||
{
|
||||
final InputHandler handler = (InputHandler)view;
|
||||
|
||||
area.left = view.getLeft();
|
||||
area.right = view.getRight();
|
||||
area.top = view.getTop();
|
||||
area.bottom = view.getBottom();
|
||||
return area.contains(aX, aY) ? handler.getBits(aX, aY) : 0;
|
||||
}
|
||||
}
|
||||
private ArrayList<Handler> handlers = new ArrayList<Handler>();
|
||||
|
||||
private int currentBits;
|
||||
|
||||
public InputGroup(Context aContext, AttributeSet aAttributes)
|
||||
{
|
||||
super(aContext, aAttributes);
|
||||
setFocusableInTouchMode(true);
|
||||
}
|
||||
|
||||
@Override public boolean onTouchEvent(MotionEvent aEvent)
|
||||
{
|
||||
currentBits = 0;
|
||||
|
||||
final int count = aEvent.getPointerCount();
|
||||
for(int i = 0; i != count; i ++)
|
||||
{
|
||||
if(aEvent.getActionMasked() != MotionEvent.ACTION_UP || i != aEvent.getActionIndex())
|
||||
{
|
||||
for(Handler j: handlers)
|
||||
{
|
||||
currentBits |= j.getBits((int)aEvent.getX(i), (int)aEvent.getY(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getBits()
|
||||
{
|
||||
return currentBits;
|
||||
}
|
||||
|
||||
public void removeChildren()
|
||||
{
|
||||
final List<View> toRemove = new ArrayList<View>();
|
||||
|
||||
for(int i = 0; i != getChildCount(); i ++)
|
||||
{
|
||||
final View thisOne = getChildAt(i);
|
||||
if(thisOne instanceof InputHandler)
|
||||
{
|
||||
toRemove.add(thisOne);
|
||||
}
|
||||
}
|
||||
|
||||
for(final View view: toRemove)
|
||||
{
|
||||
removeView(view);
|
||||
}
|
||||
|
||||
handlers.clear();
|
||||
}
|
||||
|
||||
public void loadInputLayout(final Activity aContext, final ModuleInfo aModule, final InputStream aFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
removeChildren();
|
||||
|
||||
// Get the default from the module, if it's null read the default from aFile
|
||||
Element inputElement = aModule.getOnScreenInputDefinition();
|
||||
if(null == inputElement)
|
||||
{
|
||||
inputElement = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(aFile).getDocumentElement();
|
||||
}
|
||||
|
||||
// Build the views
|
||||
NodeList inputs = inputElement.getChildNodes();
|
||||
for(int i = 0; i != inputs.getLength(); i ++)
|
||||
{
|
||||
if(Node.ELEMENT_NODE == inputs.item(i).getNodeType())
|
||||
{
|
||||
Element input = (Element)inputs.item(i);
|
||||
|
||||
final Class<? extends View> clazz = Class.forName("org.andretro.input.view." + input.getNodeName()).asSubclass(View.class);
|
||||
View inputView = clazz.getConstructor(Context.class, Element.class).newInstance(aContext, input);
|
||||
addView(inputView, extractAnchorData(input));
|
||||
|
||||
handlers.add(new Handler(inputView));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(final Exception e)
|
||||
{
|
||||
aContext.runOnUiThread(new Runnable()
|
||||
{
|
||||
@Override public void run()
|
||||
{
|
||||
String message = e.getMessage();
|
||||
message = (message == null) ? "No Message" : message;
|
||||
Toast.makeText(aContext, "Failed to load controls from " + aFile + "\n" + e.getClass().toString() + "\n" + message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Anchor mapping
|
||||
private RelativeLayout.LayoutParams extractAnchorData(Element aElement)
|
||||
{
|
||||
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getInt(aElement, "width"), getInt(aElement, "height"));
|
||||
|
||||
final int horizontalAnchorMode = horizontalAnchor.get(aElement.getAttribute("horzanchor"));
|
||||
final int horizontalMargin = getInt(aElement, "horzmargin");
|
||||
params.leftMargin = (horizontalAnchorMode == RelativeLayout.ALIGN_PARENT_LEFT) ? horizontalMargin : 0;;
|
||||
params.rightMargin = (horizontalAnchorMode == RelativeLayout.ALIGN_PARENT_RIGHT) ? horizontalMargin : 0;;
|
||||
params.addRule(horizontalAnchorMode);
|
||||
|
||||
final int verticalAnchorMode = verticalAnchor.get(aElement.getAttribute("vertanchor"));
|
||||
final int verticalMargin = getInt(aElement, "vertmargin");
|
||||
params.topMargin = (verticalAnchorMode == RelativeLayout.ALIGN_PARENT_TOP) ? verticalMargin : 0;
|
||||
params.bottomMargin = (verticalAnchorMode == RelativeLayout.ALIGN_PARENT_BOTTOM) ? verticalMargin : 0;
|
||||
params.addRule(verticalAnchorMode);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private static final Map<String, Integer> horizontalAnchor = new HashMap<String, Integer>();
|
||||
private static final Map<String, Integer> verticalAnchor = new HashMap<String, Integer>();
|
||||
|
||||
static
|
||||
{
|
||||
horizontalAnchor.put("left", RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
horizontalAnchor.put("center", RelativeLayout.CENTER_HORIZONTAL);
|
||||
horizontalAnchor.put("right", RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
verticalAnchor.put("top", RelativeLayout.ALIGN_PARENT_TOP);
|
||||
verticalAnchor.put("center", RelativeLayout.CENTER_VERTICAL);
|
||||
verticalAnchor.put("bottom", RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
}
|
||||
|
||||
public static int getInt(Element aElement, String aAttribute)
|
||||
{
|
||||
final String value = aElement.getAttribute(aAttribute);
|
||||
return ("".equals(value)) ? 0 : Integer.parseInt(value);
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
package org.andretro.settings;
|
||||
|
||||
import org.andretro.*;
|
||||
|
||||
import android.annotation.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.preference.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import android.util.*;
|
||||
|
||||
public class ButtonSetting extends DialogPreference
|
||||
{
|
||||
@TargetApi(12) public ButtonSetting(Context aContext, AttributeSet aAttributes)
|
||||
{
|
||||
super(aContext, aAttributes);
|
||||
|
||||
// HACK: Set a layout that forces the dialog to get key focus
|
||||
// TODO: Make the layout better looking!
|
||||
setDialogLayoutResource(R.layout.dialog_focus_hack);
|
||||
|
||||
setDialogTitle("Waiting for input");
|
||||
setDialogMessage(getTitle());
|
||||
}
|
||||
|
||||
@TargetApi(12) public ButtonSetting(Context aContext, String aKey, String aName, int aDefault)
|
||||
{
|
||||
super(aContext, null);
|
||||
|
||||
setKey(aKey);
|
||||
setTitle(aName);
|
||||
setPersistent(true);
|
||||
setDefaultValue(aDefault);
|
||||
|
||||
// HACK: Set a layout that forces the dialog to get key focus
|
||||
// TODO: Make the layout better looking!
|
||||
setDialogLayoutResource(R.layout.dialog_focus_hack);
|
||||
|
||||
setDialogTitle("Waiting for input");
|
||||
setDialogMessage(aName);
|
||||
}
|
||||
|
||||
@Override protected void onAttachedToActivity()
|
||||
{
|
||||
super.onAttachedToActivity();
|
||||
refreshSummary();
|
||||
}
|
||||
|
||||
@Override protected void showDialog(Bundle aState)
|
||||
{
|
||||
super.showDialog(aState);
|
||||
|
||||
// HACK: Set the message in the hacked layout
|
||||
((EditText)getDialog().findViewById(R.id.hack_message)).setText(getDialogMessage());
|
||||
|
||||
getDialog().setOnKeyListener(new DialogInterface.OnKeyListener()
|
||||
{
|
||||
@Override public boolean onKey(DialogInterface aDialog, int aKeyCode, KeyEvent aEvent)
|
||||
{
|
||||
persistInt(aKeyCode);
|
||||
valueChanged(aKeyCode);
|
||||
refreshSummary();
|
||||
getDialog().dismiss();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@TargetApi(12) private void refreshSummary()
|
||||
{
|
||||
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR1)
|
||||
{
|
||||
setSummary(KeyEvent.keyCodeToString(getPersistedInt(0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
setSummary(Integer.toString(getPersistedInt(0)));
|
||||
}
|
||||
}
|
||||
|
||||
protected void valueChanged(int aKeyCode)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
package org.andretro.settings;
|
||||
|
||||
import org.andretro.*;
|
||||
import org.andretro.emulator.*;
|
||||
|
||||
import android.preference.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SettingActivity extends PreferenceActivity
|
||||
{
|
||||
private String moduleName;
|
||||
private ModuleInfo moduleInfo;
|
||||
|
||||
@Override public void onCreate(Bundle aState)
|
||||
{
|
||||
super.onCreate(aState);
|
||||
|
||||
moduleName = getIntent().getStringExtra("moduleName");
|
||||
moduleInfo = ModuleInfo.getInfoAbout(this, new File(moduleName));
|
||||
|
||||
getPreferenceManager().setSharedPreferencesName(moduleInfo.getDataName());
|
||||
|
||||
// Add the input subsection
|
||||
PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(this);
|
||||
PreferenceCategory inputCategory = new PreferenceCategory(this);
|
||||
inputCategory.setTitle("Input");
|
||||
screen.addPreference(inputCategory);
|
||||
|
||||
// Add all pads (TODO: Just port 1 for now)
|
||||
PreferenceScreen inputScreen = getPreferenceManager().createPreferenceScreen(this);
|
||||
inputScreen.setTitle("Port 1");
|
||||
|
||||
Doodads.Device device = moduleInfo.inputData.getDevice(0, 0);
|
||||
for(Doodads.Button i: device.getAll())
|
||||
{
|
||||
inputScreen.addPreference(new Button(this, i));
|
||||
}
|
||||
|
||||
inputCategory.addPreference(inputScreen);
|
||||
|
||||
// Add the rest of the system settings
|
||||
setPreferenceScreen(screen);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
}
|
||||
|
||||
@Override public void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
|
||||
if(Game.hasGame())
|
||||
{
|
||||
Game.queueCommand(new Commands.RefreshSettings(getPreferenceManager().getSharedPreferences()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class Button extends ButtonSetting
|
||||
{
|
||||
final Doodads.Button button;
|
||||
|
||||
public Button(Context aContext, final Doodads.Button aButton)
|
||||
{
|
||||
super(aContext, aButton.configKey, aButton.fullName, 0);
|
||||
|
||||
button = aButton;
|
||||
}
|
||||
|
||||
@Override protected void valueChanged(int aKeyCode)
|
||||
{
|
||||
button.setKeyCode(aKeyCode);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
package org.andretro.system;
|
||||
import android.media.*;
|
||||
|
||||
/**
|
||||
* A stateless audio stream.
|
||||
*
|
||||
* Underlying audio object is created and managed transparently. User only needs to call write().
|
||||
* @author jason
|
||||
*
|
||||
*/
|
||||
public final class Audio
|
||||
{
|
||||
private static AudioTrack audio;
|
||||
private static int rate;
|
||||
private static boolean failed;
|
||||
|
||||
public synchronized static void open(int aRate)
|
||||
{
|
||||
close();
|
||||
|
||||
rate = aRate;
|
||||
|
||||
try
|
||||
{
|
||||
final int bufferSize = AudioTrack.getMinBufferSize(aRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
|
||||
audio = new AudioTrack(AudioManager.STREAM_MUSIC, aRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
|
||||
audio.setStereoVolume(1, 1);
|
||||
audio.play();
|
||||
|
||||
failed = false;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
audio = null;
|
||||
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void close()
|
||||
{
|
||||
if(null != audio)
|
||||
{
|
||||
audio.stop();
|
||||
audio.release();
|
||||
}
|
||||
|
||||
audio = null;
|
||||
}
|
||||
|
||||
public synchronized static void write(int aRate, short aSamples[], int aCount)
|
||||
{
|
||||
// Check args
|
||||
if(null == aSamples || aCount < 0 || aCount >= aSamples.length)
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid audio stream chunk.");
|
||||
}
|
||||
|
||||
// Create audio if needed
|
||||
if((null == audio && !failed) || aRate != rate)
|
||||
{
|
||||
open(aRate);
|
||||
}
|
||||
|
||||
// Write samples
|
||||
if(null != audio)
|
||||
{
|
||||
audio.write(aSamples, 0, aCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,74 +0,0 @@
|
||||
package org.andretro.system;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import android.app.*;
|
||||
|
||||
public class CommandQueue
|
||||
{
|
||||
private final BlockingQueue<BaseCommand> eventQueue = new ArrayBlockingQueue<BaseCommand>(8);
|
||||
|
||||
/**
|
||||
* Must be called before any other function
|
||||
* @param aThread
|
||||
*/
|
||||
|
||||
public void queueCommand(final BaseCommand aCommand)
|
||||
{
|
||||
// Put the event in the queue and notify any waiting clients that it's present. (This will wake the waiting emulator if needed.)
|
||||
eventQueue.add(aCommand);
|
||||
}
|
||||
|
||||
public void pump()
|
||||
{
|
||||
// Run all events
|
||||
for(BaseCommand i = eventQueue.poll(); null != i; i = eventQueue.poll())
|
||||
{
|
||||
i.run();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Callback
|
||||
{
|
||||
private final Runnable callback;
|
||||
private final Activity activity;
|
||||
|
||||
public Callback(Activity aActivity, Runnable aCallback)
|
||||
{
|
||||
callback = aCallback;
|
||||
activity = aActivity;
|
||||
|
||||
if(null == callback || null == activity)
|
||||
{
|
||||
throw new RuntimeException("Neither aCallback nor aActivity may be null.");
|
||||
}
|
||||
}
|
||||
|
||||
public void perform()
|
||||
{
|
||||
activity.runOnUiThread(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class BaseCommand implements Runnable
|
||||
{
|
||||
private Callback finishedCallback;
|
||||
|
||||
public BaseCommand setCallback(Callback aFinished)
|
||||
{
|
||||
finishedCallback = aFinished;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public final void run()
|
||||
{
|
||||
perform();
|
||||
|
||||
if(null != finishedCallback)
|
||||
{
|
||||
finishedCallback.perform();
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected void perform();
|
||||
}
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
package org.andretro.system;
|
||||
|
||||
import static android.view.KeyEvent.*;
|
||||
import static org.libretro.LibRetro.*;
|
||||
|
||||
import org.andretro.input.view.*;
|
||||
import android.view.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.andretro.emulator.Doodads;
|
||||
|
||||
/**
|
||||
* Static class to manage input state for the emulator view.
|
||||
* @author jason
|
||||
*
|
||||
*/
|
||||
public final class Input
|
||||
{
|
||||
private static Set<Integer> keys = new TreeSet<Integer>();
|
||||
private static InputGroup onscreenInput;
|
||||
|
||||
private static short touchX;
|
||||
private static short touchY;
|
||||
private static boolean touched;
|
||||
|
||||
// Called by UI
|
||||
public synchronized static void processEvent(KeyEvent aEvent)
|
||||
{
|
||||
if(aEvent.getAction() == KeyEvent.ACTION_DOWN)
|
||||
{
|
||||
keys.add(aEvent.getKeyCode());
|
||||
}
|
||||
else if(aEvent.getAction() == KeyEvent.ACTION_UP)
|
||||
{
|
||||
keys.remove(aEvent.getKeyCode());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void clear()
|
||||
{
|
||||
keys.clear();
|
||||
}
|
||||
|
||||
public synchronized static void setOnScreenInput(InputGroup aInput)
|
||||
{
|
||||
onscreenInput = aInput;
|
||||
}
|
||||
|
||||
public synchronized static void setTouchData(short aX, short aY, boolean aTouched)
|
||||
{
|
||||
touchX = aX;
|
||||
touchY = aY;
|
||||
touched = aTouched;
|
||||
}
|
||||
|
||||
// Called by emulator
|
||||
public static synchronized int getBits(Doodads.Device aDevice)
|
||||
{
|
||||
int result = (null != onscreenInput) ? onscreenInput.getBits() : 0;
|
||||
|
||||
for(Doodads.Button i: aDevice.getAll())
|
||||
{
|
||||
if(keys.contains(i.getKeyCode()))
|
||||
{
|
||||
result |= (1 << i.bitOffset);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static synchronized boolean isPressed(int aKeyCode)
|
||||
{
|
||||
return keys.contains(aKeyCode);
|
||||
}
|
||||
|
||||
public static synchronized void poolKeyboard(int[] aKeyState)
|
||||
{
|
||||
for(int i = 0; i != mappingTable.length / 2; i ++)
|
||||
{
|
||||
final int retroID = mappingTable[i * 2 + 0];
|
||||
final int androidID = mappingTable[i * 2 + 1];
|
||||
aKeyState[retroID] = keys.contains(androidID) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized short getTouchX()
|
||||
{
|
||||
return touchX;
|
||||
}
|
||||
|
||||
public static synchronized short getTouchY()
|
||||
{
|
||||
return touchY;
|
||||
}
|
||||
|
||||
public static synchronized boolean getTouched()
|
||||
{
|
||||
return touched;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// KEYBOARD
|
||||
private static final int[] mappingTable =
|
||||
{
|
||||
RETROK_LEFT, KEYCODE_DPAD_LEFT,
|
||||
RETROK_RIGHT, KEYCODE_DPAD_RIGHT,
|
||||
RETROK_UP, KEYCODE_DPAD_UP,
|
||||
RETROK_DOWN, KEYCODE_DPAD_DOWN,
|
||||
RETROK_RETURN, KEYCODE_ENTER,
|
||||
RETROK_TAB, KEYCODE_TAB,
|
||||
RETROK_DELETE, KEYCODE_DEL,
|
||||
RETROK_RSHIFT, KEYCODE_SHIFT_RIGHT,
|
||||
RETROK_LSHIFT, KEYCODE_SHIFT_LEFT,
|
||||
RETROK_LCTRL, KEYCODE_CTRL_LEFT,
|
||||
RETROK_END, KEYCODE_MOVE_END,
|
||||
RETROK_HOME, KEYCODE_MOVE_HOME,
|
||||
RETROK_PAGEDOWN, KEYCODE_PAGE_DOWN,
|
||||
RETROK_PAGEUP, KEYCODE_PAGE_UP,
|
||||
RETROK_LALT, KEYCODE_ALT_LEFT,
|
||||
RETROK_SPACE, KEYCODE_SPACE,
|
||||
RETROK_ESCAPE, KEYCODE_ESCAPE,
|
||||
// RETROK_BACKSPACE, KEYCODE,
|
||||
RETROK_KP_ENTER, KEYCODE_NUMPAD_ENTER,
|
||||
RETROK_KP_PLUS, KEYCODE_NUMPAD_ADD,
|
||||
RETROK_KP_MINUS, KEYCODE_NUMPAD_SUBTRACT,
|
||||
RETROK_KP_MULTIPLY, KEYCODE_NUMPAD_MULTIPLY,
|
||||
RETROK_KP_DIVIDE, KEYCODE_NUMPAD_DIVIDE,
|
||||
// RETROK_BACKQUOTE, KEYCODE,
|
||||
// RETROK_PAUSE, KEYCODE,
|
||||
RETROK_KP0, KEYCODE_NUMPAD_0,
|
||||
RETROK_KP1, KEYCODE_NUMPAD_1,
|
||||
RETROK_KP2, KEYCODE_NUMPAD_2,
|
||||
RETROK_KP3, KEYCODE_NUMPAD_3,
|
||||
RETROK_KP4, KEYCODE_NUMPAD_4,
|
||||
RETROK_KP5, KEYCODE_NUMPAD_5,
|
||||
RETROK_KP6, KEYCODE_NUMPAD_6,
|
||||
RETROK_KP7, KEYCODE_NUMPAD_7,
|
||||
RETROK_KP8, KEYCODE_NUMPAD_8,
|
||||
RETROK_KP9, KEYCODE_NUMPAD_9,
|
||||
RETROK_0, KEYCODE_0,
|
||||
RETROK_1, KEYCODE_1,
|
||||
RETROK_2, KEYCODE_2,
|
||||
RETROK_3, KEYCODE_3,
|
||||
RETROK_4, KEYCODE_4,
|
||||
RETROK_5, KEYCODE_5,
|
||||
RETROK_6, KEYCODE_6,
|
||||
RETROK_7, KEYCODE_7,
|
||||
RETROK_8, KEYCODE_8,
|
||||
RETROK_9, KEYCODE_9,
|
||||
RETROK_F1, KEYCODE_F1,
|
||||
RETROK_F2, KEYCODE_F2,
|
||||
RETROK_F3, KEYCODE_F3,
|
||||
RETROK_F4, KEYCODE_F4,
|
||||
RETROK_F5, KEYCODE_F5,
|
||||
RETROK_F6, KEYCODE_F6,
|
||||
RETROK_F7, KEYCODE_F7,
|
||||
RETROK_F8, KEYCODE_F8,
|
||||
RETROK_F9, KEYCODE_F9,
|
||||
RETROK_F10, KEYCODE_F10,
|
||||
RETROK_F11, KEYCODE_F11,
|
||||
RETROK_F12, KEYCODE_F12,
|
||||
RETROK_a, KEYCODE_A,
|
||||
RETROK_b, KEYCODE_B,
|
||||
RETROK_c, KEYCODE_C,
|
||||
RETROK_d, KEYCODE_D,
|
||||
RETROK_e, KEYCODE_E,
|
||||
RETROK_f, KEYCODE_F,
|
||||
RETROK_g, KEYCODE_G,
|
||||
RETROK_h, KEYCODE_H,
|
||||
RETROK_i, KEYCODE_I,
|
||||
RETROK_j, KEYCODE_J,
|
||||
RETROK_k, KEYCODE_K,
|
||||
RETROK_l, KEYCODE_L,
|
||||
RETROK_m, KEYCODE_M,
|
||||
RETROK_n, KEYCODE_N,
|
||||
RETROK_o, KEYCODE_O,
|
||||
RETROK_p, KEYCODE_P,
|
||||
RETROK_q, KEYCODE_Q,
|
||||
RETROK_r, KEYCODE_R,
|
||||
RETROK_s, KEYCODE_S,
|
||||
RETROK_t, KEYCODE_T,
|
||||
RETROK_u, KEYCODE_U,
|
||||
RETROK_v, KEYCODE_V,
|
||||
RETROK_w, KEYCODE_W,
|
||||
RETROK_x, KEYCODE_X,
|
||||
RETROK_y, KEYCODE_Y,
|
||||
RETROK_z, KEYCODE_Z,
|
||||
};
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package org.andretro.system;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class Logger
|
||||
{
|
||||
public static void d(String m)
|
||||
{
|
||||
Log.d("andretro", m);
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package org.andretro.system;
|
||||
|
||||
public class PngWriter
|
||||
{
|
||||
public static boolean write(final String aFileName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
package org.andretro.system;
|
||||
import org.andretro.R;
|
||||
import org.andretro.emulator.*;
|
||||
import org.libretro.*;
|
||||
import org.andretro.system.video.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import javax.microedition.khronos.opengles.*;
|
||||
|
||||
import android.content.*;
|
||||
import android.opengl.*;
|
||||
|
||||
import static android.opengl.GLES20.*;
|
||||
|
||||
// NOT THREAD SAFE
|
||||
public final class Present implements GLSurfaceView.Renderer
|
||||
{
|
||||
final LibRetro.VideoFrame frame = new LibRetro.VideoFrame();
|
||||
|
||||
public static class Texture
|
||||
{
|
||||
private static final int id[] = new int[1];
|
||||
private static boolean smoothMode = true;
|
||||
|
||||
private static void create()
|
||||
{
|
||||
glGenTextures(1, id, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, id[0]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
setSmoothMode(smoothMode);
|
||||
}
|
||||
|
||||
public static void setSmoothMode(boolean aEnable)
|
||||
{
|
||||
smoothMode = aEnable;
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aEnable ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aEnable ? GL_LINEAR : GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
private static int programID;
|
||||
private static String vertexShader;
|
||||
private static String fragmentShader;
|
||||
|
||||
// OpenGL Renderer
|
||||
private static String getShaderString(final InputStream aSource)
|
||||
{
|
||||
String source = "";
|
||||
|
||||
try
|
||||
{
|
||||
source = new java.util.Scanner(aSource).useDelimiter("\\A").next();
|
||||
aSource.close();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
private static int buildShader(int aType, final String aSource)
|
||||
{
|
||||
int result = glCreateShader(aType);
|
||||
glShaderSource(result, aSource);
|
||||
glCompileShader(result);
|
||||
|
||||
int[] state = new int[1];
|
||||
glGetShaderiv(result, GL_COMPILE_STATUS, state, 0);
|
||||
if(0 == state[0])
|
||||
{
|
||||
System.out.println(glGetShaderInfoLog(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static GLSurfaceView.Renderer createRenderer(Context aContext)
|
||||
{
|
||||
vertexShader = getShaderString(aContext.getResources().openRawResource(R.raw.vertex_shader));
|
||||
fragmentShader = getShaderString(aContext.getResources().openRawResource(R.raw.fragment_shader));
|
||||
return new Present();
|
||||
}
|
||||
|
||||
@Override public void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config)
|
||||
{
|
||||
// Program
|
||||
programID = glCreateProgram();
|
||||
glAttachShader(programID, buildShader(GL_VERTEX_SHADER, vertexShader));
|
||||
glAttachShader(programID, buildShader(GL_FRAGMENT_SHADER, fragmentShader));
|
||||
glBindAttribLocation(programID, 0, "pos");
|
||||
glBindAttribLocation(programID, 1, "tex");
|
||||
|
||||
glLinkProgram(programID);
|
||||
glUseProgram(programID);
|
||||
|
||||
// Objects
|
||||
Texture.create();
|
||||
VertexData.create();
|
||||
}
|
||||
|
||||
@Override public void onSurfaceChanged(GL10 gl, int aWidth, int aHeight)
|
||||
{
|
||||
glViewport(0, 0, aWidth, aHeight);
|
||||
|
||||
VertexData.setScreenSize(aWidth, aHeight);
|
||||
frame.restarted = true;
|
||||
}
|
||||
|
||||
@Override public void onDrawFrame(GL10 gl)
|
||||
{
|
||||
if(Game.doFrame(frame))
|
||||
{
|
||||
VertexData.setImageData(frame.width, frame.height, frame.aspect, frame.rotation);
|
||||
}
|
||||
|
||||
VertexData.draw();
|
||||
}
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
package org.andretro.system.video;
|
||||
|
||||
import static android.opengl.GLES20.*;
|
||||
import android.graphics.*;
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
class Size
|
||||
{
|
||||
public final float aspect;
|
||||
public final float w;
|
||||
public final float h;
|
||||
|
||||
public Size(Point aPoint)
|
||||
{
|
||||
w = (float)aPoint.x;
|
||||
h = (float)aPoint.y;
|
||||
|
||||
aspect = (w / h);
|
||||
}
|
||||
}
|
||||
|
||||
public class VertexData
|
||||
{
|
||||
private static final float TEXTURESIZE = 1024.0f;
|
||||
private static final int BUFFERSIZE = (16 * 4);
|
||||
private static final int[] id = new int[1];
|
||||
|
||||
private static final float[] vertexData = new float[]
|
||||
{
|
||||
-1, 1, 0, 0, 1, 1, 1, 0, -1, -1, 0, 1, 1, -1, 1, 1,
|
||||
-1, 1, 1, 0, 1, 1, 1, 1, -1, -1, 0, 0, 1, -1, 0, 1,
|
||||
-1, 1, 1, 1, 1, 1, 0, 1, -1, -1, 1, 0, 1, -1, 0, 0,
|
||||
-1, 1, 0, 1, 1, 1, 0, 0, -1, -1, 1, 1, 1, -1, 1, 0
|
||||
};
|
||||
|
||||
private static final Point screenSize = new Point();
|
||||
private static final Point imageSize = new Point();
|
||||
private static final Rect imageArea = new Rect();
|
||||
|
||||
private static float aspect;
|
||||
private static int rotate;
|
||||
private static boolean aspectMode = false;
|
||||
private static float aspectForce = 0.0f;
|
||||
|
||||
private static boolean needUpdate = true;
|
||||
|
||||
public static void create()
|
||||
{
|
||||
glGenBuffers(1, id, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, id[0]);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, false, 4 * 4, 0);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, false, 4 * 4, 4 * 2);
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
public static void setScreenSize(int aWidth, int aHeight)
|
||||
{
|
||||
needUpdate = needUpdate || !screenSize.equals(aWidth, aHeight);
|
||||
screenSize.set(aWidth, aHeight);
|
||||
}
|
||||
|
||||
public static void setImageData(int aWidth, int aHeight, float aAspect, int aRotate)
|
||||
{
|
||||
needUpdate = needUpdate || !imageSize.equals(aWidth, aHeight) || (aRotate != rotate) || (aAspect != aspect);
|
||||
|
||||
imageSize.set(aWidth, aHeight);
|
||||
aspect = aAspect;
|
||||
rotate = aRotate;
|
||||
}
|
||||
|
||||
public static void setForcedAspect(boolean aUseCustom, float aAspect)
|
||||
{
|
||||
needUpdate = needUpdate || (aUseCustom != aspectMode) || (aUseCustom && (aAspect != aspectForce));
|
||||
|
||||
aspectMode = aUseCustom;
|
||||
aspectForce = aAspect;
|
||||
}
|
||||
|
||||
public static Point getScreenSize()
|
||||
{
|
||||
// TODO: Ensure it can't be changed!
|
||||
return screenSize;
|
||||
}
|
||||
|
||||
public static Rect getImageArea()
|
||||
{
|
||||
// TODO: Ensure it can't be changed!
|
||||
return imageArea;
|
||||
}
|
||||
|
||||
public static void draw()
|
||||
{
|
||||
if(needUpdate)
|
||||
{
|
||||
update();
|
||||
needUpdate = false;
|
||||
}
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
private static void update()
|
||||
{
|
||||
final FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(BUFFERSIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
|
||||
final Size scrS = new Size(screenSize);
|
||||
final Size imgS = new Size(imageSize);
|
||||
|
||||
float inputAspect = getBestImageAspect(imgS, (rotate & 1) == 1);
|
||||
|
||||
float width = (!(scrS.aspect < inputAspect)) ? scrS.h * inputAspect : scrS.w;
|
||||
float height = (scrS.aspect < inputAspect) ? scrS.w / inputAspect : scrS.h;
|
||||
|
||||
for(int i = 0; i != 4; i ++)
|
||||
{
|
||||
int idx = (i * 4) + (rotate * 16);
|
||||
|
||||
vertexBuffer.put((i * 4) + 0, (vertexData[idx + 0] * width) / scrS.w);
|
||||
vertexBuffer.put((i * 4) + 1, (vertexData[idx + 1] * height) / scrS.h);
|
||||
vertexBuffer.put((i * 4) + 2, ((vertexData[idx + 2] * imgS.w) - (.5f * vertexData[idx + 2])) / TEXTURESIZE);
|
||||
vertexBuffer.put((i * 4) + 3, ((vertexData[idx + 3] * imgS.h) - (.5f * vertexData[idx + 3])) / TEXTURESIZE);
|
||||
}
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, BUFFERSIZE, vertexBuffer.position(0), GL_STATIC_DRAW);
|
||||
|
||||
// Calculate the position of the upper left pixel of the screen
|
||||
imageArea.left = (int)(scrS.w - width) / 2;
|
||||
imageArea.top = (int)(scrS.h - height) / 2;
|
||||
imageArea.right = imageArea.left + (int)width;
|
||||
imageArea.bottom = imageArea.top + (int)height;
|
||||
}
|
||||
|
||||
private static float getBestImageAspect(Size aImageSize, boolean aInvert)
|
||||
{
|
||||
float result = aImageSize.aspect;
|
||||
|
||||
if(aspectMode && aspectForce > 0.0f) result = aspectForce;
|
||||
else if(!aspectMode && aspect > 0.0f) result = aspect;
|
||||
|
||||
return aInvert ? (1.0f / result) : result;
|
||||
}
|
||||
}
|
@ -1,319 +0,0 @@
|
||||
package org.libretro;
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public final class LibRetro
|
||||
{
|
||||
public static final int RETRO_API_VERSION = 1;
|
||||
|
||||
public static final int RETRO_DEVICE_MASK = 0xff;
|
||||
public static final int RETRO_DEVICE_NONE = 0;
|
||||
public static final int RETRO_DEVICE_JOYPAD = 1;
|
||||
public static final int RETRO_DEVICE_MOUSE = 2;
|
||||
public static final int RETRO_DEVICE_KEYBOARD = 3;
|
||||
public static final int RETRO_DEVICE_LIGHTGUN = 4;
|
||||
public static final int RETRO_DEVICE_ANALOG = 5;
|
||||
public static final int RETRO_DEVICE_POINTER = 6;
|
||||
|
||||
public static final int RETRO_DEVICE_JOYPAD_MULTITAP = ((1 << 8) | RETRO_DEVICE_JOYPAD);
|
||||
public static final int RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE = ((1 << 8) | RETRO_DEVICE_LIGHTGUN);
|
||||
public static final int RETRO_DEVICE_LIGHTGUN_JUSTIFIER = ((2 << 8) | RETRO_DEVICE_LIGHTGUN);
|
||||
public static final int RETRO_DEVICE_LIGHTGUN_JUSTIFIERS = ((3 << 8) | RETRO_DEVICE_LIGHTGUN);
|
||||
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_B = 0;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_Y = 1;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_SELECT = 2;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_START = 3;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_UP = 4;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_DOWN = 5;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_LEFT = 6;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_RIGHT = 7;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_A = 8;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_X = 9;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_L = 10;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_R = 11;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_L2 = 12;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_R2 = 13;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_L3 = 14;
|
||||
public static final int RETRO_DEVICE_ID_JOYPAD_R3 = 15;
|
||||
|
||||
public static final int RETRO_DEVICE_INDEX_ANALOG_LEFT = 0;
|
||||
public static final int RETRO_DEVICE_INDEX_ANALOG_RIGHT = 1;
|
||||
public static final int RETRO_DEVICE_ID_ANALOG_X = 0;
|
||||
public static final int RETRO_DEVICE_ID_ANALOG_Y = 1;
|
||||
|
||||
public static final int RETRO_DEVICE_ID_MOUSE_X = 0;
|
||||
public static final int RETRO_DEVICE_ID_MOUSE_Y = 1;
|
||||
public static final int RETRO_DEVICE_ID_MOUSE_LEFT = 2;
|
||||
public static final int RETRO_DEVICE_ID_MOUSE_RIGHT = 3;
|
||||
|
||||
public static final int RETRO_DEVICE_ID_LIGHTGUN_X = 0;
|
||||
public static final int RETRO_DEVICE_ID_LIGHTGUN_Y = 1;
|
||||
public static final int RETRO_DEVICE_ID_LIGHTGUN_TRIGGER = 2;
|
||||
public static final int RETRO_DEVICE_ID_LIGHTGUN_CURSOR = 3;
|
||||
public static final int RETRO_DEVICE_ID_LIGHTGUN_TURBO = 4;
|
||||
public static final int RETRO_DEVICE_ID_LIGHTGUN_PAUSE = 5;
|
||||
public static final int RETRO_DEVICE_ID_LIGHTGUN_START = 6;
|
||||
|
||||
public static final int RETRO_REGION_NTSC = 0;
|
||||
public static final int RETRO_REGION_PAL = 1;
|
||||
|
||||
public static final int RETRO_MEMORY_MASK = 0xff;
|
||||
public static final int RETRO_MEMORY_SAVE_RAM = 0;
|
||||
public static final int RETRO_MEMORY_RTC = 1;
|
||||
public static final int RETRO_MEMORY_SYSTEM_RAM = 2;
|
||||
public static final int RETRO_MEMORY_VIDEO_RAM = 3;
|
||||
|
||||
public static final int RETRO_MEMORY_SNES_BSX_RAM = ((1 << 8) | RETRO_MEMORY_SAVE_RAM);
|
||||
public static final int RETRO_MEMORY_SNES_BSX_PRAM = ((2 << 8) | RETRO_MEMORY_SAVE_RAM);
|
||||
public static final int RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM = ((3 << 8) | RETRO_MEMORY_SAVE_RAM);
|
||||
public static final int RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM = ((4 << 8) | RETRO_MEMORY_SAVE_RAM);
|
||||
public static final int RETRO_MEMORY_SNES_GAME_BOY_RAM = ((5 << 8) | RETRO_MEMORY_SAVE_RAM);
|
||||
public static final int RETRO_MEMORY_SNES_GAME_BOY_RTC = ((6 << 8) | RETRO_MEMORY_RTC);
|
||||
|
||||
public static final int RETRO_GAME_TYPE_BSX = 0x101;
|
||||
public static final int RETRO_GAME_TYPE_BSX_SLOTTED = 0x102;
|
||||
public static final int RETRO_GAME_TYPE_SUFAMI_TURBO = 0x103;
|
||||
public static final int RETRO_GAME_TYPE_SUPER_GAME_BOY = 0x104;
|
||||
|
||||
public static final int RETRO_PIXEL_FORMAT_0RGB1555 = 0;
|
||||
public static final int RETRO_PIXEL_FORMAT_XRGB8888 = 1;
|
||||
public static final int RETRO_PIXEL_FORMAT_RGB565 = 2;
|
||||
|
||||
public static final int RETROK_UNKNOWN = 0;
|
||||
public static final int RETROK_FIRST = 0;
|
||||
public static final int RETROK_BACKSPACE = 8;
|
||||
public static final int RETROK_TAB = 9;
|
||||
public static final int RETROK_CLEAR = 12;
|
||||
public static final int RETROK_RETURN = 13;
|
||||
public static final int RETROK_PAUSE = 19;
|
||||
public static final int RETROK_ESCAPE = 27;
|
||||
public static final int RETROK_SPACE = 32;
|
||||
public static final int RETROK_EXCLAIM = 33;
|
||||
public static final int RETROK_QUOTEDBL = 34;
|
||||
public static final int RETROK_HASH = 35;
|
||||
public static final int RETROK_DOLLAR = 36;
|
||||
public static final int RETROK_AMPERSAND = 38;
|
||||
public static final int RETROK_QUOTE = 39;
|
||||
public static final int RETROK_LEFTPAREN = 40;
|
||||
public static final int RETROK_RIGHTPAREN = 41;
|
||||
public static final int RETROK_ASTERISK = 42;
|
||||
public static final int RETROK_PLUS = 43;
|
||||
public static final int RETROK_COMMA = 44;
|
||||
public static final int RETROK_MINUS = 45;
|
||||
public static final int RETROK_PERIOD = 46;
|
||||
public static final int RETROK_SLASH = 47;
|
||||
public static final int RETROK_0 = 48;
|
||||
public static final int RETROK_1 = 49;
|
||||
public static final int RETROK_2 = 50;
|
||||
public static final int RETROK_3 = 51;
|
||||
public static final int RETROK_4 = 52;
|
||||
public static final int RETROK_5 = 53;
|
||||
public static final int RETROK_6 = 54;
|
||||
public static final int RETROK_7 = 55;
|
||||
public static final int RETROK_8 = 56;
|
||||
public static final int RETROK_9 = 57;
|
||||
public static final int RETROK_COLON = 58;
|
||||
public static final int RETROK_SEMICOLON = 59;
|
||||
public static final int RETROK_LESS = 60;
|
||||
public static final int RETROK_EQUALS = 61;
|
||||
public static final int RETROK_GREATER = 62;
|
||||
public static final int RETROK_QUESTION = 63;
|
||||
public static final int RETROK_AT = 64;
|
||||
public static final int RETROK_LEFTBRACKET = 91;
|
||||
public static final int RETROK_BACKSLASH = 92;
|
||||
public static final int RETROK_RIGHTBRACKET = 93;
|
||||
public static final int RETROK_CARET = 94;
|
||||
public static final int RETROK_UNDERSCORE = 95;
|
||||
public static final int RETROK_BACKQUOTE = 96;
|
||||
public static final int RETROK_a = 97;
|
||||
public static final int RETROK_b = 98;
|
||||
public static final int RETROK_c = 99;
|
||||
public static final int RETROK_d = 100;
|
||||
public static final int RETROK_e = 101;
|
||||
public static final int RETROK_f = 102;
|
||||
public static final int RETROK_g = 103;
|
||||
public static final int RETROK_h = 104;
|
||||
public static final int RETROK_i = 105;
|
||||
public static final int RETROK_j = 106;
|
||||
public static final int RETROK_k = 107;
|
||||
public static final int RETROK_l = 108;
|
||||
public static final int RETROK_m = 109;
|
||||
public static final int RETROK_n = 110;
|
||||
public static final int RETROK_o = 111;
|
||||
public static final int RETROK_p = 112;
|
||||
public static final int RETROK_q = 113;
|
||||
public static final int RETROK_r = 114;
|
||||
public static final int RETROK_s = 115;
|
||||
public static final int RETROK_t = 116;
|
||||
public static final int RETROK_u = 117;
|
||||
public static final int RETROK_v = 118;
|
||||
public static final int RETROK_w = 119;
|
||||
public static final int RETROK_x = 120;
|
||||
public static final int RETROK_y = 121;
|
||||
public static final int RETROK_z = 122;
|
||||
public static final int RETROK_DELETE = 127;
|
||||
|
||||
public static final int RETROK_KP0 = 256;
|
||||
public static final int RETROK_KP1 = 257;
|
||||
public static final int RETROK_KP2 = 258;
|
||||
public static final int RETROK_KP3 = 259;
|
||||
public static final int RETROK_KP4 = 260;
|
||||
public static final int RETROK_KP5 = 261;
|
||||
public static final int RETROK_KP6 = 262;
|
||||
public static final int RETROK_KP7 = 263;
|
||||
public static final int RETROK_KP8 = 264;
|
||||
public static final int RETROK_KP9 = 265;
|
||||
public static final int RETROK_KP_PERIOD = 266;
|
||||
public static final int RETROK_KP_DIVIDE = 267;
|
||||
public static final int RETROK_KP_MULTIPLY = 268;
|
||||
public static final int RETROK_KP_MINUS = 269;
|
||||
public static final int RETROK_KP_PLUS = 270;
|
||||
public static final int RETROK_KP_ENTER = 271;
|
||||
public static final int RETROK_KP_EQUALS = 272;
|
||||
|
||||
public static final int RETROK_UP = 273;
|
||||
public static final int RETROK_DOWN = 274;
|
||||
public static final int RETROK_RIGHT = 275;
|
||||
public static final int RETROK_LEFT = 276;
|
||||
public static final int RETROK_INSERT = 277;
|
||||
public static final int RETROK_HOME = 278;
|
||||
public static final int RETROK_END = 279;
|
||||
public static final int RETROK_PAGEUP = 280;
|
||||
public static final int RETROK_PAGEDOWN = 281;
|
||||
|
||||
public static final int RETROK_F1 = 282;
|
||||
public static final int RETROK_F2 = 283;
|
||||
public static final int RETROK_F3 = 284;
|
||||
public static final int RETROK_F4 = 285;
|
||||
public static final int RETROK_F5 = 286;
|
||||
public static final int RETROK_F6 = 287;
|
||||
public static final int RETROK_F7 = 288;
|
||||
public static final int RETROK_F8 = 289;
|
||||
public static final int RETROK_F9 = 290;
|
||||
public static final int RETROK_F10 = 291;
|
||||
public static final int RETROK_F11 = 292;
|
||||
public static final int RETROK_F12 = 293;
|
||||
public static final int RETROK_F13 = 294;
|
||||
public static final int RETROK_F14 = 295;
|
||||
public static final int RETROK_F15 = 296;
|
||||
|
||||
public static final int RETROK_NUMLOCK = 300;
|
||||
public static final int RETROK_CAPSLOCK = 301;
|
||||
public static final int RETROK_SCROLLOCK = 302;
|
||||
public static final int RETROK_RSHIFT = 303;
|
||||
public static final int RETROK_LSHIFT = 304;
|
||||
public static final int RETROK_RCTRL = 305;
|
||||
public static final int RETROK_LCTRL = 306;
|
||||
public static final int RETROK_RALT = 307;
|
||||
public static final int RETROK_LALT = 308;
|
||||
public static final int RETROK_RMETA = 309;
|
||||
public static final int RETROK_LMETA = 310;
|
||||
public static final int RETROK_LSUPER = 311;
|
||||
public static final int RETROK_RSUPER = 312;
|
||||
public static final int RETROK_MODE = 313;
|
||||
public static final int RETROK_COMPOSE = 314;
|
||||
|
||||
public static final int RETROK_HELP = 315;
|
||||
public static final int RETROK_PRINT = 316;
|
||||
public static final int RETROK_SYSREQ = 317;
|
||||
public static final int RETROK_BREAK = 318;
|
||||
public static final int RETROK_MENU = 319;
|
||||
public static final int RETROK_POWER = 320;
|
||||
public static final int RETROK_EURO = 321;
|
||||
public static final int RETROK_UNDO = 322;
|
||||
|
||||
public static final int RETROK_LAST = 323;
|
||||
|
||||
|
||||
public static final int RETRO_ENVIRONMENT_SET_ROTATION = 1; // const unsigned * --
|
||||
public static final int RETRO_ENVIRONMENT_GET_OVERSCAN = 2; // bool * --
|
||||
public static final int RETRO_ENVIRONMENT_GET_CAN_DUPE = 3; // bool * --
|
||||
public static final int RETRO_ENVIRONMENT_GET_VARIABLE = 4; // struct retro_variable * --
|
||||
public static final int RETRO_ENVIRONMENT_SET_VARIABLES = 5; // const struct retro_variable * --
|
||||
public static final int RETRO_ENVIRONMENT_SET_MESSAGE = 6; // const struct retro_message * --
|
||||
public static final int RETRO_ENVIRONMENT_SHUTDOWN = 7; // N/A (NULL) --
|
||||
public static final int RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL = 8;
|
||||
public static final int RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY = 9;
|
||||
public static final int RETRO_ENVIRONMENT_SET_PIXEL_FORMAT = 10;
|
||||
|
||||
public static class SystemInfo
|
||||
{
|
||||
public String libraryName;
|
||||
public String libraryVersion;
|
||||
public String validExtensions;
|
||||
|
||||
public boolean needFullPath;
|
||||
public boolean blockExtract;
|
||||
}
|
||||
|
||||
public static class AVInfo
|
||||
{
|
||||
public int baseWidth;
|
||||
public int baseHeight;
|
||||
|
||||
public int maxWidth;
|
||||
public int maxHeight;
|
||||
|
||||
public float aspectRatio;
|
||||
|
||||
public double fps;
|
||||
public double sampleRate;
|
||||
}
|
||||
|
||||
public static class VideoFrame
|
||||
{
|
||||
public boolean restarted = true;
|
||||
|
||||
public int framesToRun;
|
||||
public boolean rewind;
|
||||
|
||||
public int width;
|
||||
public int height;
|
||||
public int pixelFormat;
|
||||
public int rotation;
|
||||
public float aspect;
|
||||
|
||||
public final int[] keyboard = new int[RETROK_LAST];
|
||||
public final int[] buttons = new int[8];
|
||||
|
||||
public short touchX;
|
||||
public short touchY;
|
||||
public boolean touched;
|
||||
|
||||
public final short[] audio = new short[48000];
|
||||
public int audioSamples;
|
||||
}
|
||||
|
||||
public static native boolean loadLibrary(String aPath, String aSystemDirectory);
|
||||
public static native void unloadLibrary();
|
||||
public static native void init();
|
||||
public static native void deinit();
|
||||
public static native int apiVersion();
|
||||
public static native void getSystemInfo(SystemInfo aInfo);
|
||||
public static native void getSystemAVInfo(AVInfo aInfo);
|
||||
public static native void setControllerPortDevice(int aPort, int aDevice);
|
||||
public static native void reset();
|
||||
public static native void run(VideoFrame aVideo);
|
||||
public static native int serializeSize();
|
||||
// public static native boolean serialize(byte[] aData, int aSize);
|
||||
// public static native boolean unserialize(byte[] aData, int aSize);
|
||||
public static native void cheatReset();
|
||||
public static native void cheatSet(int aIndex, boolean aEnabled, String aCode);
|
||||
public static native boolean loadGame(String aPath);
|
||||
public static native void unloadGame();
|
||||
public static native int getRegion();
|
||||
public static native int getMemorySize(int aID);
|
||||
public static native ByteBuffer getMemoryData(int aID);
|
||||
|
||||
// Helpers
|
||||
public static native void setupRewinder(int aDataSize); // 0 or less disables
|
||||
|
||||
public static native boolean writeMemoryRegion(int aID, String aFileName);
|
||||
public static native boolean readMemoryRegion(int aID, String aFileBase);
|
||||
|
||||
public static native boolean serializeToFile(String aPath);
|
||||
public static native boolean unserializeFromFile(String aPath);
|
||||
|
||||
public static native boolean nativeInit();
|
||||
}
|