Emulator(Native Android)

The Uzebox now have a fully functional emulator! Download and discuss it here.
Post Reply
User avatar
Artcfox
Posts: 944
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Emulator(Native Android)

Post by Artcfox » Wed Sep 20, 2017 6:39 am

shockdesign wrote:
Wed Sep 20, 2017 4:34 am
Out of curiosity, are you creating builds off your Github version? I'm finding some odd things where it cannot launch the activity as it cannot find it.. Noticed I had to delete the android-project directory out of the SDL directory as well after untarring it, as there were some conflicts there.

I'm looking through the process. Getting hooks into Android when the app pauses and resumes should be pretty easy. Would just need methods on the emulator side to pause and resume that we can call (native hooks)
I created the filesystem first, and then did a:

Code: Select all

git init
in the directory, and then I checked in the relevant stuff. I just tested by cloning it in another location, following the instructions in the README, and then opening it in Android Studio. I think the reason why it can't find your activity is because you deleted the directory containing its activity:

Code: Select all

/tmp/cuzebox-android/android-project/app/src/main/jni/SDL2/android-project/src/org/libsdl/app/SDLActivity.java
Here are the commands as I've typed them after :

Code: Select all

user@debian:/tmp$ git clone https://github.com/artcfox/cuzebox-android
Cloning into 'cuzebox-android'...
remote: Counting objects: 124, done.
remote: Compressing objects: 100% (85/85), done.
remote: Total 124 (delta 24), reused 124 (delta 24), pack-reused 0
Receiving objects: 100% (124/124), 541.38 KiB | 0 bytes/s, done.
Resolving deltas: 100% (24/24), done.
user@debian:/tmp$ cd cuzebox-android/
user@debian:/tmp/cuzebox-android$ cd android-project/app/src/main/jni
user@debian:/tmp/cuzebox-android/android-project/app/src/main/jni$ tar xf ~/Downloads/SDL2-2.0.5.tar.gz 
user@debian:/tmp/cuzebox-android/android-project/app/src/main/jni$ mv SDL2-2.0.5/ SDL2
user@debian:/tmp/cuzebox-android/android-project/app/src/main/jni$ cd SDL2/include/
user@debian:/tmp/cuzebox-android/android-project/app/src/main/jni/SDL2/include$ ln -s . SDL2
I just did a build from that directory and it runs fine for me. If you need to, I can reboot my LiveCD and create a screen recording starting from a clean Linux install to installing Android Studio, the NDK, cloning my git repo, setting it up, and getting a working .apk file.
shockdesign wrote:
Wed Sep 20, 2017 4:36 am
Also Artcfox, you can change the location of the files from

Code: Select all

/storage/emulated/0/cuzebox
to

Code: Select all

/sdcard/cuzebox
and that should be more compatible with more devices..
I ultimately don't want to hard code it. I figured that there must be a way to get that programmatically. SDL_GetBasePath() returns NULL on Android, but

Code: Select all

SDL_AndroidGetExternalStoragePath()
looks like it's what I want to use, however I don't know how to change the org and app from org.libsdl.app. Any time I've tried it just immediately crashes upon startup. I was hoping that you could help me with that, because apparently it's an Android thing, and I'm not doing it correctly.

Once we can change the app's string from org.libsdl.app to org.uzebox.cuzebox.app or something, then I figured that I'd use SDL_AndroidGetExternalStoragePath() in order to store the Bootloader, .uze files, and the game controller db. Though I might have to modify CUzeBox so it doesn't default to looking for the game controller database in SDL_GetBasePath() since that function returns NULL on Android.

Edit: Changed SDL_GetPrefPath() to SDL_AndroidGetExternalStoragePath().

shockdesign
Posts: 26
Joined: Mon Jan 06, 2014 12:20 pm

Re: Emulator(Native Android)

Post by shockdesign » Wed Sep 20, 2017 7:01 am

Ahhh, because it looks like

Code: Select all

/tmp/cuzebox-android/android-project/app/src/main/java....
contains all the code as well... which would also cause conflicts, but according to what you've said then, you're using the code defined in the SDL2 directory to build the app, not the code a few levels lower.

Okay..so I was building from the wrong directory.. Also means I can probably rejig things around to clean things up a bit...

You're right, didn't realise you had access to

Code: Select all

SDL_AndroidGetExternalStoragePath()
, you should use that.. :D

I'm going to pull in the changes from your repo now..

User avatar
Artcfox
Posts: 944
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Emulator(Native Android)

Post by Artcfox » Wed Sep 20, 2017 7:13 am

Cool, I'm glad you got that working :-)

There should be any changes to my repo... Jubatian updated his repo, but you shouldn't use my new branch, because he reimplemented those changes differently.

User avatar
Artcfox
Posts: 944
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Emulator(Native Android)

Post by Artcfox » Wed Sep 20, 2017 9:42 am

I figured out the pause/resume thing, I'm just waiting on Jubatian to integrate it into his repo (I figure it will be easier if we can just track his upstream).

The solution was this:

Code: Select all

diff --git a/android-project/app/src/main/jni/src/cuzebox/main.c b/android-project/app/src/main/jni/src/cuzebox/main.c
index f415958..71e7859 100644
--- a/android-project/app/src/main/jni/src/cuzebox/main.c
+++ b/android-project/app/src/main/jni/src/cuzebox/main.c
@@ -80,6 +80,9 @@ static auint main_t5_cc;
 /* Request for discarding frame limitation */
 static boole main_nolimit = FALSE;
 
+/* Keeps track of clock ticks */
+static auint main_ctick;
+
 /* Request frame merging (flicker reduction) */
 #ifdef FLAG_DISPLAY_FRAMEMERGE
 static boole main_fmerge = TRUE;
@@ -106,6 +109,14 @@ static boole main_isadvfr = FALSE;
 
 
 
+/*
+** Stops the speed of the emulator from going wonky when task switching on mobile platforms
+*/
+static int main_eventfilter(void* userdata, SDL_Event* sdlevent)
+{
+ if (sdlevent->type == SDL_APP_WILLENTERFOREGROUND){ main_ptick = main_ctick = SDL_GetTicks(); }
+ return 1;
+}
 
 
 /*
@@ -113,8 +124,8 @@ static boole main_isadvfr = FALSE;
 */
 static void main_loop(void)
 {
- auint ctick = SDL_GetTicks();
- auint tdif  = ctick - main_ptick;
+ main_ctick = SDL_GetTicks();
+ auint tdif  = main_ctick - main_ptick;
  auint drift = main_tdrift;
  auint favg;
  auint ccur;
@@ -168,7 +179,7 @@ static void main_loop(void)
  /* Now the drift can be saved */
 
  main_tdrift = drift;
- main_ptick  = ctick;
+ main_ptick  = main_ctick;
  main_fdrop  = fdtmp;
  main_frc   ++;
  if (main_tfrac >= 2U){ main_tfrac = 0U; }
@@ -413,6 +424,7 @@ int main (int argc, char** argv)
 #ifdef __EMSCRIPTEN__
  emscripten_set_main_loop(&main_loop, 0, 1);
 #else
+ SDL_SetEventFilter(main_eventfilter, NULL);
  while (!main_exit){ main_loop(); }
 
  ecpu = cu_avr_get_state();
We can let the OS take care of pausing and resuming for us, we just need to make sure that CUzeBox isn't aware that any time has passed upon resuming otherwise it will do terrible things to the speed of the emulator and its sound output.

User avatar
Artcfox
Posts: 944
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Emulator(Native Android)

Post by Artcfox » Wed Sep 20, 2017 10:42 am

Okay, so I sync'd my master branch with Jubatian's upstream code, and then created a new branch of mine based off that new master that has the pause-resume-fix on it.

I figure you should be safe if you work off my master branch, as the other branches will become defunct once those features are properly integrated into the upstream cuzebox. Any other branch you can think of as backups of my private working branches (that I may delete once the feature is merged upstream), but are there in case anyone wants to try those experimental features out on their own.

Oh, and BTW using

Code: Select all

/sdcard/cuzebox
as a path crashes on my Pixel XL. Also, the external storage location is way different from that, so I'll see if I can come up with a better solution.

User avatar
Jubatian
Posts: 1355
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: Emulator(Native Android)

Post by Jubatian » Wed Sep 20, 2017 6:56 pm

Code: Select all

SDL_AndroidGetExternalStoragePath()
Did you solve the issue relating this function? I mean this:
Artcfox wrote:
Wed Sep 20, 2017 6:39 am
(...), however I don't know how to change the org and app from org.libsdl.app. Any time I've tried it just immediately crashes upon startup. I was hoping that you could help me with that, because apparently it's an Android thing, and I'm not doing it correctly.
If this could be solved, then I would have some ideas to generalize this mess to get everything loaded from the right place. Where the controller DB should be on this system? It also has SDL_AndroidGetInternalStoragePath, which points to some read-only storage specific to the application. I guess on this system there is no way to have a shared game controller DB (which would be the best, since then you configure once and then every SDL2 app would work with whatever controller you have), if it is so, then probably this is where the controller DB should be.

You also talk about crashes related to paths. The emulator should survive SDL_GetBasePath() returning NULL or it doens't then?

I also added a different handler for CPU starvation in a recent commit which if works should be more cross-platform (it doesn't depend on this Android & a few others specific event or even SDL2).

User avatar
Artcfox
Posts: 944
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Emulator(Native Android)

Post by Artcfox » Wed Sep 20, 2017 8:47 pm

Jubatian wrote:
Wed Sep 20, 2017 6:56 pm

Code: Select all

SDL_AndroidGetExternalStoragePath()
Did you solve the issue relating this function? I mean this:
Artcfox wrote:
Wed Sep 20, 2017 6:39 am
(...), however I don't know how to change the org and app from org.libsdl.app. Any time I've tried it just immediately crashes upon startup. I was hoping that you could help me with that, because apparently it's an Android thing, and I'm not doing it correctly.
If this could be solved, then I would have some ideas to generalize this mess to get everything loaded from the right place. Where the controller DB should be on this system? It also has SDL_AndroidGetInternalStoragePath, which points to some read-only storage specific to the application. I guess on this system there is no way to have a shared game controller DB (which would be the best, since then you configure once and then every SDL2 app would work with whatever controller you have), if it is so, then probably this is where the controller DB should be.

You also talk about crashes related to paths. The emulator should survive SDL_GetBasePath() returning NULL or it doens't then?

I also added a different handler for CPU starvation in a recent commit which if works should be more cross-platform (it doesn't depend on this Android & a few others specific event or even SDL2).
I'm leaning towards SDL_AndroidGetExternalStoragePath(). It correctly handles when SDL_GetBasePath() is NULL. The problem was when I changed the bootloader path to /sdcard/cuzebox (since that path didn't exist on my device) CUzeBox terminated because it didn't find a valid game file.

SDL_AndroidGetInternalStoragePath is not read-only, because SDL_GetPrefPath is exactly SDL_AndroidGetInternalStoragePath with a trailing / appended to it as shown below, but the user doesn't have access to that, and it gets wiped if you uninstall the application.

Code: Select all

char *
SDL_GetBasePath(void)
{
    /* The current working directory is / on Android */
    return NULL;
}

char *
SDL_GetPrefPath(const char *org, const char *app)
{
    const char *path = SDL_AndroidGetInternalStoragePath();
    if (path) {
        size_t pathlen = SDL_strlen(path)+2;
        char *fullpath = (char *)SDL_malloc(pathlen);
        if (!fullpath) {
            SDL_OutOfMemory();
            return NULL;
        }
        SDL_snprintf(fullpath, pathlen, "%s/", path);
        return fullpath;
    }
    return NULL;
}
That's where app preferences are suggested to be stored. However, I think that we want people to be able to modify that database, along with adding ROMS, rather than waiting for an update to the Android app. In case the Android app gets a lot of attention, I think it's best not to distribute it with all the games (especially certain ports).

Actually for usability, I'm thinking the best thing might be to store the default bootloader (Called Bootloader.hex with no version, so when it gets updated it isn't misleading), game controller db, an eeprom.bin file that has the bits pre-set so the bootloader defaults to booting to the menu, and an independent game or two (that uses all FOSS assets) inside the app's asset folder (actually stored compressed inside the .zip), and then use SDL functions to extract them into the path returned by SDL_AndroidGetExternalStoragePath() if that path doesn't already exist. Otherwise if it can't find the bootloader, then the app will terminate immediately upon opening, which is a bad experience. If a user really screws something up, they can just wipe that folder, and have the app re-extract things there, since I don't think uninstalling an app will wipe the external storage directory.

Another idea I had was if the path returned by SDL_AndroidGetExternalStoragePath() doesn't already exist, one of the first things it should exact into that folder are two files called INSTRUCT.UZE and INSTRUCT.TXT that would display "HOW TO RUN/ADD GAMES ON ANDROID" as it's name in the bootloader menu. and when you run it, it would print out instructions on the screen describing the things like needing a game controller or keyboard plugged into the OTG cable (and Bluetooth once we get that working). The file INSTRUCT.TXT would be populated by the emulator itself to contain the full path to the app's data directory on that particular device, and displayed by the INSTRUCT.UZE file. Also, since a user might not know to have a keyboard/game controller plugged in, I would modify the app so touching anywhere on the screen acts like the START button (which I've already done as a test). Without that, a user would not be able to load the INSTRUCT.UZE file to see what they need to do in order to use it properly.

shockdesign
Posts: 26
Joined: Mon Jan 06, 2014 12:20 pm

Re: Emulator(Native Android)

Post by shockdesign » Thu Sep 21, 2017 12:51 am

Artcfox wrote:
Wed Sep 20, 2017 6:39 am
however I don't know how to change the org and app from org.libsdl.app. Any time I've tried it just immediately crashes upon startup. I was hoping that you could help me with that, because apparently it's an Android thing, and I'm not doing it correctly.

Once we can change the app's string from org.libsdl.app to org.uzebox.cuzebox.app or something, then I figured that I'd use SDL_AndroidGetExternalStoragePath() in order to store the Bootloader, .uze files, and the game controller db. Though I might have to modify CUzeBox so it doesn't default to looking for the game controller database in SDL_GetBasePath() since that function returns NULL on Android.
Changing the bundle id shouldn't be difficult, not sure why it's crashing on startup... but I'll look into that..

User avatar
Artcfox
Posts: 944
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: Emulator(Native Android)

Post by Artcfox » Thu Sep 21, 2017 6:33 am

L4rry wrote:
Sun Sep 17, 2017 8:54 pm
I'd suggest testing tilt based controls as an input option for directional movement as well. Could be interesting. Maybe action buttons can be configurable per game on where you press on the screen. Maybe top half could be jump, maybe fast paced tapping could be shooting. Dunno. Maybe using the strengths of smartphone capability to do something interesting? Never liked the onscreen controls for retro gaming on a smart phone. No tactile feedback and it takes away graphical real estate. Not sure if there is a real solution for that really.
So in trying to add Joystick support, it turns out that SDL2 on Android automatically configures a joystick for the tilt sensor unless you tell it not to. So I divided the touch screen up into left and right, so top 10% on the left is LT, top 10% on the right is RT, and then the next 40% on the left is SELECT, the next 40% on the right is START, and then the next 25% on the left is Y, the next 25% on the right is X, and finally the bottom 25% on the left is B and the bottom 25% on the right is A. I figured out why it wasn't running on older devices, because I used too new of a signature, and I dropped the min API level required down to 12. I disabled frame merge and set it to small screen so it would run the fastest on the most devices, and attached is that build.
Attachments
cuzebox-tilt-touchscreen-hq.zip
high quality, no frame merge
(2.82 MiB) Downloaded 94 times
cuzebox-tilt-touchscreen.zip
low quality
(2.82 MiB) Downloaded 96 times

User avatar
L4rry
Posts: 239
Joined: Sun Dec 28, 2014 7:19 am
Location: Cape Town, South Africa

Re: Emulator(Native Android)

Post by L4rry » Fri Sep 22, 2017 7:53 pm

Awesome! Thanks for the effort. I'll give it a try as soon as I can. I haven't tried out Uzebox on Android at all yet so looking forward. I'll try and give you some feedback once I get there.

Post Reply

Who is online

Users browsing this forum: nicksen782 and 2 guests