Skip to content

Commit

Permalink
ANDROID: Rework the virtual gamepad controller
Browse files Browse the repository at this point in the history
- Use a SVG asset to allow for better scalability
- Make the controller visible when touching the screen
- Allow for oblique moving by placing finger between two directions
- Add more buttons on the center area of the screen (GUIDE, START, LEFT
  STICK, RIGHT STICK) and simplify right area (only four buttons)
- Cleanup now unused code
  • Loading branch information
lephilousophe committed Jul 21, 2024
1 parent d343e4e commit 59b3bfe
Show file tree
Hide file tree
Showing 14 changed files with 616 additions and 298 deletions.
49 changes: 24 additions & 25 deletions backends/graphics/android/android-graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,7 @@
#include "backends/graphics/opengl/pipelines/pipeline.h"

#include "graphics/blit.h"

static void loadBuiltinTexture(JNI::BitmapResources resource, OpenGL::Surface *surf) {
const Graphics::Surface *src = JNI::getBitmapResource(resource);
if (!src) {
error("Failed to fetch touch arrows bitmap");
}

surf->allocate(src->w, src->h);
Graphics::Surface *dst = surf->getSurface();

Graphics::crossBlit(
(byte *)dst->getPixels(), (const byte *)src->getPixels(),
dst->pitch, src->pitch,
src->w, src->h,
src->format, dst->format);

delete src;
}
#include "graphics/managed_surface.h"

//
// AndroidGraphicsManager
Expand All @@ -72,10 +55,6 @@ AndroidGraphicsManager::AndroidGraphicsManager() :
// Initialize our OpenGL ES context.
initSurface();

_touchcontrols = createSurface(_defaultFormatAlpha);
loadBuiltinTexture(JNI::BitmapResources::TOUCH_ARROWS_BITMAP, _touchcontrols);
_touchcontrols->updateGLTexture();

// not in 3D, not in GUI
dynamic_cast<OSystem_Android *>(g_system)->applyTouchSettings(false, false);
dynamic_cast<OSystem_Android *>(g_system)->applyOrientationSettings();
Expand All @@ -85,6 +64,8 @@ AndroidGraphicsManager::~AndroidGraphicsManager() {
ENTER();

deinitSurface();

delete _touchcontrols;
}

void AndroidGraphicsManager::initSurface() {
Expand Down Expand Up @@ -118,8 +99,10 @@ void AndroidGraphicsManager::initSurface() {
if (_touchcontrols) {
_touchcontrols->recreate();
_touchcontrols->updateGLTexture();
} else {
_touchcontrols = createSurface(_defaultFormatAlpha);
}
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
this, JNI::egl_surface_width, JNI::egl_surface_height);

handleResize(JNI::egl_surface_width, JNI::egl_surface_height);
Expand All @@ -132,7 +115,7 @@ void AndroidGraphicsManager::deinitSurface() {
LOGD("deinitializing 2D surface");

// Deregister us from touch control
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
nullptr, 0, 0);
if (_touchcontrols) {
_touchcontrols->destroy();
Expand All @@ -157,7 +140,7 @@ void AndroidGraphicsManager::resizeSurface() {
error("JNI::initSurface failed");
}

dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
this, JNI::egl_surface_width, JNI::egl_surface_height);

handleResize(JNI::egl_surface_width, JNI::egl_surface_height);
Expand Down Expand Up @@ -246,6 +229,22 @@ void AndroidGraphicsManager::syncVirtkeyboardState(bool virtkeybd_on) {
_forceRedraw = true;
}

void AndroidGraphicsManager::touchControlInitSurface(const Graphics::ManagedSurface &surf) {
if (_touchcontrols->getWidth() == surf.w && _touchcontrols->getHeight() == surf.h) {
return;
}

_touchcontrols->allocate(surf.w, surf.h);
Graphics::Surface *dst = _touchcontrols->getSurface();

Graphics::crossBlit(
(byte *)dst->getPixels(), (const byte *)surf.getPixels(),
dst->pitch, surf.pitch,
surf.w, surf.h,
surf.format, dst->format);
_touchcontrols->updateGLTexture();
}

void AndroidGraphicsManager::touchControlDraw(int16 x, int16 y, int16 w, int16 h, const Common::Rect &clip) {
_targetBuffer->enableBlend(OpenGL::Framebuffer::kBlendModeTraditionalTransparency);
OpenGL::Pipeline *pipeline = getPipeline();
Expand Down
1 change: 1 addition & 0 deletions backends/graphics/android/android-graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class AndroidGraphicsManager :

float getHiDPIScreenFactor() const override;

void touchControlInitSurface(const Graphics::ManagedSurface &surf) override;
void touchControlNotifyChanged() override;
void touchControlDraw(int16 x, int16 y, int16 w, int16 h, const Common::Rect &clip) override;

Expand Down
46 changes: 20 additions & 26 deletions backends/graphics3d/android/android-graphics3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

#include "common/tokenizer.h"
#include "graphics/blit.h"
#include "graphics/managed_surface.h"
#include "graphics/opengl/shader.h"
#include "graphics/opengl/context.h"

Expand All @@ -54,26 +55,6 @@
#define CONTEXT_RESET_ENABLE(gl_param) if (!(saved ## gl_param)) { GLCALL(glDisable(gl_param)); }
#define CONTEXT_RESET_DISABLE(gl_param) if (saved ## gl_param) { GLCALL(glEnable(gl_param)); }

static GLES8888Texture *loadBuiltinTexture(JNI::BitmapResources resource) {
const Graphics::Surface *src = JNI::getBitmapResource(JNI::BitmapResources::TOUCH_ARROWS_BITMAP);
if (!src) {
error("Failed to fetch touch arrows bitmap");
}

GLES8888Texture *ret = new GLES8888Texture();
ret->allocBuffer(src->w, src->h);
Graphics::Surface *dst = ret->surface();

Graphics::crossBlit(
(byte *)dst->getPixels(), (const byte *)src->getPixels(),
dst->pitch, src->pitch,
src->w, src->h,
src->format, dst->format);

delete src;
return ret;
}

AndroidGraphics3dManager::AndroidGraphics3dManager() :
_screenChangeID(0),
_graphicsMode(0),
Expand All @@ -94,7 +75,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
_mouse_hotspot(),
_mouse_dont_scale(false),
_show_mouse(false),
_touchcontrols_texture(nullptr),
_touchcontrols_texture(new GLES8888Texture()),
_old_touch_mode(OSystem_Android::TOUCH_MODE_TOUCHPAD) {

if (JNI::egl_bits_per_pixel == 16) {
Expand All @@ -112,8 +93,6 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
}
_mouse_texture = _mouse_texture_palette;

_touchcontrols_texture = loadBuiltinTexture(JNI::BitmapResources::TOUCH_ARROWS_BITMAP);

initSurface();

// in 3D, not in GUI
Expand Down Expand Up @@ -218,7 +197,7 @@ void AndroidGraphics3dManager::initSurface() {
if (_touchcontrols_texture) {
_touchcontrols_texture->reinit();
}
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
this, JNI::egl_surface_width, JNI::egl_surface_height);

updateScreenRect();
Expand Down Expand Up @@ -256,7 +235,7 @@ void AndroidGraphics3dManager::deinitSurface() {
_mouse_texture_palette->release();
}

dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
nullptr, 0, 0);
if (_touchcontrols_texture) {
_touchcontrols_texture->release();
Expand Down Expand Up @@ -286,7 +265,7 @@ void AndroidGraphics3dManager::resizeSurface() {
initOverlay();
}

dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
this, JNI::egl_surface_width, JNI::egl_surface_height);

updateScreenRect();
Expand Down Expand Up @@ -1103,6 +1082,21 @@ bool AndroidGraphics3dManager::setState(const AndroidCommonGraphics::State &stat
return true;
}

void AndroidGraphics3dManager::touchControlInitSurface(const Graphics::ManagedSurface &surf) {
if (_touchcontrols_texture->width() == surf.w && _touchcontrols_texture->height() == surf.h) {
return;
}

_touchcontrols_texture->allocBuffer(surf.w, surf.h);
Graphics::Surface *dst = _touchcontrols_texture->surface();

Graphics::crossBlit(
(byte *)dst->getPixels(), (const byte *)surf.getPixels(),
dst->pitch, surf.pitch,
surf.w, surf.h,
surf.format, dst->format);
}

void AndroidGraphics3dManager::touchControlNotifyChanged() {
// Make sure we redraw the screen
_force_redraw = true;
Expand Down
1 change: 1 addition & 0 deletions backends/graphics3d/android/android-graphics3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class AndroidGraphics3dManager :
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
#endif

void touchControlInitSurface(const Graphics::ManagedSurface &surf) override;
void touchControlNotifyChanged() override;
void touchControlDraw(int16 x, int16 y, int16 w, int16 h, const Common::Rect &clip) override;

Expand Down
4 changes: 4 additions & 0 deletions backends/platform/android/android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,10 @@ void OSystem_Android::initBackend() {
_audio_thread_exit = false;
pthread_create(&_audio_thread, 0, audioThreadFunc, this);

JNI::DPIValues dpi;
JNI::getDPI(dpi);
_touchControls.init(dpi[2]);

_graphicsManager = new AndroidGraphicsManager();

// renice this thread to boost the audio thread
Expand Down
6 changes: 3 additions & 3 deletions backends/platform/android/android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ APK_MAIN = ScummVM-debug.apk
APK_MAIN_RELEASE = ScummVM-release-unsigned.apk
AAB_MAIN_RELEASE = ScummVM-release.aab

DIST_FILES_HELP = $(PATH_DIST)/android-help.zip
DIST_FILES_PLATFORM = $(PATH_DIST)/android-help.zip $(PATH_DIST)/gamepad.svg

$(PATH_BUILD):
$(MKDIR) $(PATH_BUILD)
Expand All @@ -38,9 +38,9 @@ $(PATH_BUILD)/local.properties: configure.stamp | $(PATH_BUILD)
$(PATH_BUILD)/src.properties: configure.stamp | $(PATH_BUILD)
$(ECHO) "srcdir=$(realpath $(srcdir))\n" > $(PATH_BUILD)/src.properties

$(PATH_BUILD_ASSETS): $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_HELP) | $(PATH_BUILD)
$(PATH_BUILD_ASSETS): $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_PLATFORM) | $(PATH_BUILD)
$(INSTALL) -d $(PATH_BUILD_ASSETS)
$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_HELP) $(PATH_BUILD_ASSETS)/
$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_ENGINEDATA_BIG) $(DIST_FILES_SOUNDFONTS) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_FILES_PLATFORM) $(PATH_BUILD_ASSETS)/
ifneq ($(DIST_FILES_SHADERS),)
$(INSTALL) -d $(PATH_BUILD_ASSETS)/shaders
$(INSTALL) -c -m 644 $(DIST_FILES_SHADERS) $(PATH_BUILD_ASSETS)/shaders
Expand Down
67 changes: 0 additions & 67 deletions backends/platform/android/jni-android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ jmethodID JNI::_MID_isConnectionLimited = 0;
jmethodID JNI::_MID_setWindowCaption = 0;
jmethodID JNI::_MID_showVirtualKeyboard = 0;
jmethodID JNI::_MID_showOnScreenControls = 0;
jmethodID JNI::_MID_getBitmapResource = 0;
jmethodID JNI::_MID_setTouchMode = 0;
jmethodID JNI::_MID_getTouchMode = 0;
jmethodID JNI::_MID_setOrientation = 0;
Expand Down Expand Up @@ -434,71 +433,6 @@ void JNI::showOnScreenControls(int enableMask) {
}
}

Graphics::Surface *JNI::getBitmapResource(BitmapResources resource) {
JNIEnv *env = JNI::getEnv();

jobject bitmap = env->CallObjectMethod(_jobj, _MID_getBitmapResource, (int) resource);

if (env->ExceptionCheck()) {
LOGE("Can't get bitmap resource");

env->ExceptionDescribe();
env->ExceptionClear();

return nullptr;
}

if (bitmap == nullptr) {
LOGE("Bitmap resource was not found");
return nullptr;
}

AndroidBitmapInfo bitmap_info;
if (AndroidBitmap_getInfo(env, bitmap, &bitmap_info) != ANDROID_BITMAP_RESULT_SUCCESS) {
LOGE("Error reading bitmap info");
env->DeleteLocalRef(bitmap);
return nullptr;
}

Graphics::PixelFormat fmt;
switch(bitmap_info.format) {
case ANDROID_BITMAP_FORMAT_RGBA_8888:
#ifdef SCUMM_BIG_ENDIAN
fmt = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
#else
fmt = Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
#endif
break;
case ANDROID_BITMAP_FORMAT_RGBA_4444:
fmt = Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0);
break;
case ANDROID_BITMAP_FORMAT_RGB_565:
fmt = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
break;
default:
LOGE("Bitmap has unsupported format");
env->DeleteLocalRef(bitmap);
return nullptr;
}

void *src_pixels = nullptr;
if (AndroidBitmap_lockPixels(env, bitmap, &src_pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
LOGE("Error locking bitmap pixels");
env->DeleteLocalRef(bitmap);
return nullptr;
}

Graphics::Surface *ret = new Graphics::Surface();
ret->create(bitmap_info.width, bitmap_info.height, fmt);
ret->copyRectToSurface(src_pixels, bitmap_info.stride,
0, 0, bitmap_info.width, bitmap_info.height);

AndroidBitmap_unlockPixels(env, bitmap);
env->DeleteLocalRef(bitmap);

return ret;
}

void JNI::setTouchMode(int touchMode) {
JNIEnv *env = JNI::getEnv();

Expand Down Expand Up @@ -819,7 +753,6 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager,
FIND_METHOD(, isConnectionLimited, "()Z");
FIND_METHOD(, showVirtualKeyboard, "(Z)V");
FIND_METHOD(, showOnScreenControls, "(I)V");
FIND_METHOD(, getBitmapResource, "(I)Landroid/graphics/Bitmap;");
FIND_METHOD(, setTouchMode, "(I)V");
FIND_METHOD(, getTouchMode, "()I");
FIND_METHOD(, setOrientation, "(I)V");
Expand Down
6 changes: 0 additions & 6 deletions backends/platform/android/jni-android.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ class JNI {
virtual ~JNI();

public:
enum struct BitmapResources {
TOUCH_ARROWS_BITMAP = 0
};

static bool pause;
static sem_t pause_sem;

Expand Down Expand Up @@ -92,7 +88,6 @@ class JNI {
static bool isConnectionLimited();
static void showVirtualKeyboard(bool enable);
static void showOnScreenControls(int enableMask);
static Graphics::Surface *getBitmapResource(BitmapResources resource);
static void setTouchMode(int touchMode);
static int getTouchMode();
static void setOrientation(int touchMode);
Expand Down Expand Up @@ -155,7 +150,6 @@ class JNI {
static jmethodID _MID_setWindowCaption;
static jmethodID _MID_showVirtualKeyboard;
static jmethodID _MID_showOnScreenControls;
static jmethodID _MID_getBitmapResource;
static jmethodID _MID_setTouchMode;
static jmethodID _MID_getTouchMode;
static jmethodID _MID_setOrientation;
Expand Down
1 change: 0 additions & 1 deletion backends/platform/android/org/scummvm/scummvm/ScummVM.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ final public native void pushEvent(int type, int arg1, int arg2, int arg3,
abstract protected void setWindowCaption(String caption);
abstract protected void showVirtualKeyboard(boolean enable);
abstract protected void showOnScreenControls(int enableMask);
abstract protected Bitmap getBitmapResource(int resource);
abstract protected void setTouchMode(int touchMode);
abstract protected int getTouchMode();
abstract protected void setOrientation(int orientation);
Expand Down
17 changes: 0 additions & 17 deletions backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -777,23 +777,6 @@ public void run() {
});
}

@Override
protected Bitmap getBitmapResource(int resource) {
int id;
switch(resource) {
case 0: // TOUCH_ARROWS_BITMAP
id = R.drawable.touch_arrows;
break;
default:
return null;
}

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;

return BitmapFactory.decodeResource(getResources(), id, opts);
}

@Override
protected void setTouchMode(final int touchMode) {
if (_events.getTouchMode() == touchMode) {
Expand Down
Loading

0 comments on commit 59b3bfe

Please sign in to comment.