Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,42 @@ jobs:
name: LGPT-${{ github.job }}-${{ github.sha }}.zip
path: projects/*.zip
if-no-files-found: error


android:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4.1.7
with:
submodules: recursive

- name: Setup build environment
run: |
sudo apt update
sudo apt install -y make python3-pillow
echo "sdk.dir=$ANDROID_SDK_ROOT" > android/local.properties
$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager "ndk;27.0.12077973"
echo "ndk.dir=$ANDROID_SDK_ROOT/ndk/27.0.12077973" >> android/local.properties

- name: Build Android APK
working-directory: android
run: ./gradlew assembleDebug

- name: Package build
working-directory: projects
run: |
TAG=$(curl -s https://api.github.com/repos/djdiskmachine/lgpt-resources/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4)
curl -L -o lgpt-resources.zip https://github.com/djdiskmachine/lgpt-resources/archive/refs/tags/${TAG}.zip
unzip lgpt-resources.zip
mv lgpt-resources-${TAG}/*/ ./resources/packaging
rm -rf lgpt-resources*
mv ../android/app/build/outputs/apk/debug/app-debug.apk ./LittlePiggyTracker.apk
./resources/packaging/lgpt_package.sh

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: LGPT-${{ github.job }}-${{ github.sha }}.zip
path: projects/*.zip
if-no-files-found: error
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "android"]
path = android
url = git@github.com:djdiskmachine/littlepiggytracker-android.git
1 change: 1 addition & 0 deletions android
Submodule android added at f00d4d
4 changes: 3 additions & 1 deletion projects/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ RG35XXPLUSDIRS := $(LINUXDIRS) $(DUMMYMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS)
STEAMDIRS := $(LINUXDIRS) $(JACKDIRS) $(RTAUDIODIRS) $(RTMIDIDIRS) $(SDLDIRS)
X64DIRS := $(LINUXDIRS) $(RTMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS)
X86DIRS := $(LINUXDIRS) $(RTMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS)
ANDROIDDIRS := $(LINUXDIRS) $(DUMMYMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS) $(ANDROIDJNIDIRS)

#---------------------------------------------------------------------------------
# Consoles/Embedded
Expand Down Expand Up @@ -330,6 +331,7 @@ RG35XXPLUSFILES := $(LINUXFILES) $(SDLAUDIOFILES) $(DUMMYMIDIFILES)
STEAMFILES := $(LINUXFILES) $(RTAUDIOFILES) $(RTMIDIFILES) $(JACKFILES)
X64FILES := $(LINUXFILES) $(RTMIDIFILES) $(SDLAUDIOFILES)
X86FILES := $(LINUXFILES) $(RTMIDIFILES) $(SDLAUDIOFILES)
ANDROIDFILES := $(LINUXFILES) $(DUMMYMIDIFILES) $(SDLAUDIOFILES) $(ANDROIDJNIFILES)

#---------------------------------------------------------------------------------
# Consoles/Embedded
Expand Down Expand Up @@ -464,7 +466,7 @@ W32FILES := \
#---------------------------------------------------------------------------------

TARGET := $(TITLE)
BUILD := build$(PLATFORM)
BUILD ?= build$(PLATFORM)
SOURCES := $($(PLATFORM)DIRS) $(COMMONDIRS)
INCLUDES :=

Expand Down
102 changes: 102 additions & 0 deletions projects/Makefile.ANDROID
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
-include $(PWD)/rules_base

#---------------------------------------------------------------------------------
# Android-specific Makefile for LittleGPTracker
# This Makefile produces libmain.so for SDL2 Android apps
#---------------------------------------------------------------------------------

# Determine ABI and set toolchain accordingly
ABI ?= arm64-v8a
NDK_PATH ?= $(ANDROID_NDK_HOME)

# Override BUILD directory to be ABI-specific
BUILD := build$(PLATFORM)_$(ABI)

ifeq ($(ABI),armeabi-v7a)
TOOLCHAIN_PREFIX := armv7a-linux-androideabi
ARCH_FLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon
ANDROID_API := 21
else ifeq ($(ABI),arm64-v8a)
TOOLCHAIN_PREFIX := aarch64-linux-android
ARCH_FLAGS := -march=armv8-a
ANDROID_API := 21
else
$(error Unsupported ABI: $(ABI))
endif

# Set up NDK toolchain
TOOLCHAIN := $(NDK_PATH)/toolchains/llvm/prebuilt/linux-x86_64
CC := $(TOOLCHAIN)/bin/$(TOOLCHAIN_PREFIX)$(ANDROID_API)-clang
CXX := $(TOOLCHAIN)/bin/$(TOOLCHAIN_PREFIX)$(ANDROID_API)-clang++
AR := $(TOOLCHAIN)/bin/llvm-ar
STRIP := $(TOOLCHAIN)/bin/llvm-strip

# Platform definition
PLATFORM := ANDROID

# Android-specific defines
DEFINES := \
-DPLATFORM_$(PLATFORM) \
-DANDROID \
-D__ANDROID__ \
-DCPP_MEMORY \
-DSDL2 \
-DSDLAUDIO \
-DDUMMYMIDI

# Android doesn't support RtMidi - use dummy MIDI instead
# -DRTMIDI \
# -D_FEAT_MIDI_MULTITHREAD

# Add _64BIT for arm64-v8a builds
ifeq ($(ABI),arm64-v8a)
DEFINES += -D_64BIT
endif
# SDL2 paths (these should be set by Gradle)
SDL_INCLUDE ?= /path/to/SDL2/include
SDL_LIB ?= /path/to/SDL2/libs/$(ABI)

# Optimization and compilation flags
OPT_FLAGS := -O2 -fno-strict-aliasing
# For debugging, use:
# OPT_FLAGS := -g -O0

INCLUDES := -I$(SDL_INCLUDE) -I$(PWD)/../sources

# Android requires position-independent code
CFLAGS := $(OPT_FLAGS) $(DEFINES) $(INCLUDES) $(ARCH_FLAGS) \
-fPIC \
-ffunction-sections \
-fdata-sections \
-Wall \
-Wno-unused-variable

CXXFLAGS := $(CFLAGS) -std=gnu++11 -fexceptions -frtti

# Linker flags for shared library
LDFLAGS := -shared \
$(ARCH_FLAGS) \
-Wl,--gc-sections \
-Wl,--no-undefined \
-L$(SDL_LIB)

# Libraries to link
LIBS := -lSDL2 \
-lGLESv2 \
-lGLESv1_CM \
-llog \
-landroid \
-lOpenSLES

# Android-specific JNI extras
ANDROIDJNIDIRS := ../sources/System/Android
ANDROIDJNIFILES := AndroidJNI.o

# Output configuration
OUTPUT := ../libmain_$(ABI)
EXTENSION := so

# Build rule for shared library
%.so: $(OFILES)
$(CXX) $(LDFLAGS) -o $@ $(OFILES) $(LIBS)
$(STRIP) --strip-unneeded $@
20 changes: 20 additions & 0 deletions projects/resources/ANDROID/mapping.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!--
MAPPING FOR ANDROID KEYBOARD/CONTROLLER
enable DUMPEVENT to help with mapping
-->
<MAPPINGS>
<!-- Arrow keys for navigation -->
<MAP src="key:0:up" dst="/event/i" />
<MAP src="key:0:down" dst="/event/k" />
<MAP src="key:0:left" dst="/event/j" />
<MAP src="key:0:right" dst="/event/l" />

<!-- Letter keys for buttons -->
<MAP src="key:0:a" dst="/event/b" />
<MAP src="key:0:s" dst="/event/a" />
<MAP src="key:0:space" dst="/event/start" />

<!-- Q/W for shoulders -->
<MAP src="key:0:q" dst="/event/lshoulder" />
<MAP src="key:0:w" dst="/event/rshoulder" />
</MAPPINGS>
2 changes: 2 additions & 0 deletions projects/resources/packaging/lgpt_package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ collect_resources() { #1PLATFORM #2lgpt.*-exe
if [ "$1" == "PSP" ] ||
[ "$1" == "GARLIC" ] ||
[ "$1" == "RG35XXPLUS" ] ||
[ "$1" == "ANDROID" ] ||
[ "$1" == "BITTBOY" ]; then # All files go in the root folder
zip -9 $PACKAGE -j $CONTENTS
elif [ "$1" == "MACOS" ]; then # .app is a folder
Expand Down Expand Up @@ -55,5 +56,6 @@ collect_resources BITTBOY lgpt-bittboy.elf
collect_resources GARLICPLUS lgpt-garlicplus.elf
collect_resources RG35XXPLUS lgpt-rg35xxplus.elf
collect_resources MACOS LittleGPTracker.app
collect_resources ANDROID LittlePiggyTracker.apk
# collect_resources RS97 lgpt.dge
# collect_resources STEAM lgpt.steam-exe
36 changes: 28 additions & 8 deletions sources/Adapters/LINUX/System/LINUXSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ void LINUXSystem::Boot(int argc,char **argv) {
FileSystem::Install(new UnixFileSystem());

// Install aliases
#ifdef __ANDROID__
// On Android, we MUST use external storage so users can access files via
// file manager
const char* storagePath = SDL_AndroidGetExternalStoragePath();
if (storagePath) {
Trace::Log("ANDROID", "External storage path: %s", storagePath);
Path::SetAlias("bin", storagePath);
Path::SetAlias("root", storagePath);
} else {
Trace::Error("Failed to get Android external storage - app won't be able to access files!");
// Still set internal storage as last resort, but warn user
storagePath = SDL_AndroidGetInternalStoragePath();
if (storagePath) {
Trace::Error("Using internal storage (not accessible via file manager): %s", storagePath);
Path::SetAlias("bin", storagePath);
Path::SetAlias("root", storagePath);
}
}
#else
char buff[1024];
ssize_t len = ::readlink("/proc/self/exe",buff,sizeof(buff)-1);
if (len != -1)
Expand All @@ -76,18 +95,19 @@ void LINUXSystem::Boot(int argc,char **argv) {
}
Path::SetAlias("bin",dirname(buff)) ;
Path::SetAlias("root",".") ;
#endif

// always use stdout, user can capture in launch script
Trace::GetInstance()->SetLogger(*(new StdOutLogger()));
// always use stdout, user can capture in launch script
Trace::GetInstance()->SetLogger(*(new StdOutLogger()));

// Process arguments
Config::GetInstance()->ProcessArguments(argc,argv) ;
// Process arguments
Config::GetInstance()->ProcessArguments(argc, argv);

// Install GUI Factory
I_GUIWindowFactory::Install(new GUIFactory()) ;
// Install GUI Factory
I_GUIWindowFactory::Install(new GUIFactory());

// Install Timers
TimerService::GetInstance()->Install(new SDLTimerService()) ;
// Install Timers
TimerService::GetInstance()->Install(new SDLTimerService());

#ifdef JACKAUDIO
Trace::Log("System","Installing JACK audio") ;
Expand Down
7 changes: 7 additions & 0 deletions sources/Adapters/SDL2/GUI/SDLEventManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,19 @@ int SDLEventManager::MainLoop()
switch (event.window.event)
{
case SDL_WINDOWEVENT_EXPOSED:
// SDL2 docs: surface re-acquisition is NOT needed
// on expose, only on resize. Just update content.
appWindow->Update() ;
break;
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
sdlWindow->ProcessExpose() ;
break;
}
break ;
case SDL_APP_DIDENTERFOREGROUND:
sdlWindow->ProcessExpose() ;
break ;
case SDL_USEREVENT:
sdlWindow->ProcessUserEvent(event) ;
break ;
Expand Down
30 changes: 19 additions & 11 deletions sources/Adapters/SDL2/GUI/SDLGUIWindowImp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
SDLGUIWindowImp *instance_ ;

unsigned short appWidth=320 ;
unsigned short appHeight=240 ;
unsigned short appHeight = 240;

SDLGUIWindowImp::SDLGUIWindowImp(GUICreateWindowParams &p)
{
Expand All @@ -37,7 +37,7 @@ SDLGUIWindowImp::SDLGUIWindowImp(GUICreateWindowParams &p)
if (displayModeRet < 0) {
Trace::Error("DISPLAY","No display mode found. Error Code: %d.", displayModeRet);
}

NAssert(displayModeRet >= 0);

#if defined(PLATFORM_PSP)
Expand All @@ -48,18 +48,24 @@ SDLGUIWindowImp::SDLGUIWindowImp(GUICreateWindowParams &p)
int screenWidth = 320;
int screenHeight = 240;
windowed_ = false;
#else
#elif defined(__ANDROID__)
// Use full screen dimensions on Android
int screenWidth = displayMode.w;
int screenHeight = displayMode.h;
#endif

#if defined(RS97)
windowed_ = false;
SDL_Log("DISPLAY: Android - using full display: %dx%d", screenWidth, screenHeight);
#else
int screenWidth = displayMode.w;
int screenHeight = displayMode.h;
#endif

#if defined(RS97)
/* Pick the best bitdepth for the RS97 as it will select 32 as its default, even though that's slow */
bitDepth_ = 16;
#else
#else
bitDepth_ = SDL_BITSPERPIXEL(displayMode.format);
#endif
#endif

const char * driverName = SDL_GetVideoDriver(0);

Trace::Log("DISPLAY","Using driver %s. Screen (%d,%d) Bpp:%d",driverName,screenWidth,screenHeight,bitDepth_);
Expand All @@ -79,8 +85,8 @@ SDLGUIWindowImp::SDLGUIWindowImp(GUICreateWindowParams &p)
}

#ifdef PLATFORM_PSP
mult_ = 1;
#else
mult_ = 1;
#else
int multFromSize=MIN(screenHeight/appHeight,screenWidth/appWidth);
const char *mult=Config::GetInstance()->GetValue("SCREENMULT") ;
if (mult)
Expand Down Expand Up @@ -519,6 +525,8 @@ void SDLGUIWindowImp::ProcessExpose()
{
// Expose and resize events will cause a new surface to be needed.
surface_ = SDL_GetWindowSurface(window_);
_window->ForceFullRedraw(); // surface re-acquired: force full bitmap+char
// redraw
_window->Update() ;
}

Expand Down
2 changes: 1 addition & 1 deletion sources/Adapters/Unix/FileSystem/UnixFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#ifdef _64BIT
#if defined(_64BIT) || defined(__ANDROID__)
#include <dirent.h>
#else
#include <sys/dir.h>
Expand Down
14 changes: 12 additions & 2 deletions sources/Adapters/Unix/Process/UnixProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,23 @@ SysSemaphore *UnixProcessFactory::CreateNewSemaphore(int initialcount, int maxco
} ;

UnixSysSemaphore::UnixSysSemaphore(int initialcount,int maxcount) {
#ifdef __ANDROID__
// Android doesn't reliably support named semaphores, use unnamed ones
sem_init(&unnamed_sem_, 0, initialcount);
sem_ = &unnamed_sem_;
#else
sem_=sem_open("n0ssemaphore",O_CREAT,S_IRUSR|S_IWUSR , 0 );
} ;
#endif
}

UnixSysSemaphore::~UnixSysSemaphore() {
#ifdef __ANDROID__
sem_destroy(&unnamed_sem_);
#else
sem_close(sem_) ;
sem_unlink("n0ssemaphore") ;
} ;
#endif
}

SysSemaphoreResult UnixSysSemaphore::Wait() {
sem_wait(sem_) ;
Expand Down
Loading
Loading