[Scummvm-git-logs] scummvm master -> e7b6cff4dd01542ec593e9e2ecb1fe0909b15019

aquadran noreply at scummvm.org
Sun Nov 28 23:04:59 UTC 2021


This automated email contains information about 29 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
dd038d72e8 OPENGL: Fix compilation with USE_BUILTIN_OPENGL
706de81bb0 ANDROID: Switch to GLES2
5d56c1cdf0 ANDROID: Merge 3D graphics backend
5248999c95 ANDROID: Better debug of which graphic backend is used
bb2871cd63 ANDROID: Implement modes completely to allow switching between 3D and 2D
74c12b5e5a ANDROID: Use 5551 format for overlay instead of 4444
7352207555 ANDROID: Free frame buffer when it's unused
2a444f981e ANDROID: Fix indentation
881f48b24d ANDROID: Set up scissor box when resizing
9ce3b692c6 ANDROID: Reinitialize some state before stopping 3D manager
0988f3d6d8 ANDROID: Fix OpenGL debug in 3D backend
f0aef09021 ANDROID: Make sure glDrawArrays succeeds
ebeb731ad7 ANDROID: Disable depth test as we don't use it in final rendering
e4390abd86 ANDROID: Introduce back the touch controls for 3D
faa8986fc8 ANDROID: Display the game below the overlay menu
d4e9c0eca4 ANDROID: Always enable blending when drawing all the layers
20df3369b4 ANDROID: Rework 3D screen setup
7145b3c2f2 ANDROID: Add support for kSupportsArbitraryResolutions in 3D
2792b474e1 ANDROID: Remove superfluous ifdefs
8a6f74b5a1 ANDROID: Remove global variables
8321056107 ANDROID: Remove superfluous asserts
40a036ac0b ANDROID: Use nullptr where appropriate
afcb0c54e7 ANDROID: Use real size instead of magical constant
3cb81ff31c ANDROID: Don't use unsigned int
2bb9d5f3df ANDROID: Remove outdated piece of code
5b62141b8f ANDROID: Fix code style
d6f37a161b ANDROID: Remove again updateEventScale
ba136b6f29 COMMON: Add JOYSTICK_BUTTON_INVALID to be used when no button is pressed
e7b6cff4dd ANDROID: The virtual controls now generate fake joystick events


Commit: dd038d72e8924d0d8d9fb28788b5f57c71adee58
    https://github.com/scummvm/scummvm/commit/dd038d72e8924d0d8d9fb28788b5f57c71adee58
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
OPENGL: Fix compilation with USE_BUILTIN_OPENGL

GL_FUNC2_DEF doesn't have the same arguments as GL_FUNC_DEF

Changed paths:
    backends/graphics/opengl/context.cpp


diff --git a/backends/graphics/opengl/context.cpp b/backends/graphics/opengl/context.cpp
index adedb5442c..7b4c6c1c2f 100644
--- a/backends/graphics/opengl/context.cpp
+++ b/backends/graphics/opengl/context.cpp
@@ -97,7 +97,7 @@ void OpenGLGraphicsManager::initializeGLContext() {
 
 #ifdef USE_BUILTIN_OPENGL
 #define GL_FUNC_DEF(ret, name, param) g_context.name = &name
-#define GL_FUNC_2_DEF GL_FUNC_DEF
+// GL_FUNC2_DEF will be defined in opengl-func.h
 #else
 #define GL_FUNC_DEF GL_EXT_FUNC_DEF
 #define GL_FUNC_2_DEF(ret, name, extName, param) \


Commit: 706de81bb0b5e8b3136f1b5a18e537e33a7934b5
    https://github.com/scummvm/scummvm/commit/706de81bb0b5e8b3136f1b5a18e537e33a7934b5
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Switch to GLES2

Changed paths:
    backends/graphics/opengl/opengl-func.h
    backends/graphics/opengl/opengl-sys.h
    backends/platform/android/graphics.cpp
    backends/platform/android/org/scummvm/scummvm/ScummVM.java
    configure
    dists/android/AndroidManifest.xml


diff --git a/backends/graphics/opengl/opengl-func.h b/backends/graphics/opengl/opengl-func.h
index 4e44c13d0f..539b0a07ab 100644
--- a/backends/graphics/opengl/opengl-func.h
+++ b/backends/graphics/opengl/opengl-func.h
@@ -79,16 +79,10 @@ GL_FUNC_DEF(void, glEnable, (GLenum cap));
 GL_FUNC_DEF(void, glDisable, (GLenum cap));
 GL_FUNC_DEF(GLboolean, glIsEnabled, (GLenum cap));
 GL_FUNC_DEF(void, glClear, (GLbitfield mask));
-GL_FUNC_DEF(void, glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha));
 GL_FUNC_DEF(void, glViewport, (GLint x, GLint y, GLsizei width, GLsizei height));
-GL_FUNC_DEF(void, glMatrixMode, (GLenum mode));
-GL_FUNC_DEF(void, glLoadIdentity, ());
-GL_FUNC_DEF(void, glLoadMatrixf, (const GLfloat *m));
-GL_FUNC_DEF(void, glShadeModel, (GLenum mode));
 GL_FUNC_DEF(void, glHint, (GLenum target, GLenum mode));
 GL_FUNC_DEF(void, glClearColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha));
 GL_FUNC_DEF(void, glBlendFunc, (GLenum sfactor, GLenum dfactor));
-GL_FUNC_DEF(void, glEnableClientState, (GLenum array));
 GL_FUNC_DEF(void, glPixelStorei, (GLenum pname, GLint param));
 GL_FUNC_DEF(void, glScissor, (GLint x, GLint y, GLsizei width, GLsizei height));
 GL_FUNC_DEF(void, glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels));
@@ -98,13 +92,22 @@ GL_FUNC_DEF(void, glGenTextures, (GLsizei n, GLuint *textures));
 GL_FUNC_DEF(void, glBindTexture, (GLenum target, GLuint texture));
 GL_FUNC_DEF(void, glTexParameteri, (GLenum target, GLenum pname, GLint param));
 GL_FUNC_DEF(void, glTexImage2D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels));
-GL_FUNC_DEF(void, glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer));
-GL_FUNC_DEF(void, glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer));
 GL_FUNC_DEF(void, glDrawArrays, (GLenum mode, GLint first, GLsizei count));
 GL_FUNC_DEF(void, glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels));
 GL_FUNC_DEF(const GLubyte *, glGetString, (GLenum name));
 GL_FUNC_DEF(GLenum, glGetError, ());
 
+#if !USE_FORCED_GLES2
+GL_FUNC_DEF(void, glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha));
+GL_FUNC_DEF(void, glMatrixMode, (GLenum mode));
+GL_FUNC_DEF(void, glLoadIdentity, ());
+GL_FUNC_DEF(void, glLoadMatrixf, (const GLfloat *m));
+GL_FUNC_DEF(void, glShadeModel, (GLenum mode));
+GL_FUNC_DEF(void, glEnableClientState, (GLenum array));
+GL_FUNC_DEF(void, glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer));
+GL_FUNC_DEF(void, glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer));
+#endif
+
 #if !USE_FORCED_GLES
 GL_FUNC_2_DEF(void, glEnableVertexAttribArray, glEnableVertexAttribArrayARB, (GLuint index));
 GL_FUNC_2_DEF(void, glDisableVertexAttribArray, glDisableVertexAttribArrayARB, (GLuint index));
diff --git a/backends/graphics/opengl/opengl-sys.h b/backends/graphics/opengl/opengl-sys.h
index dc6f66ac71..d741766a8f 100644
--- a/backends/graphics/opengl/opengl-sys.h
+++ b/backends/graphics/opengl/opengl-sys.h
@@ -60,6 +60,10 @@
 
 #ifdef __ANDROID__
 	#include <GLES/gl.h>
+	#include <GLES2/gl2.h>
+	// These types are ScummVM specific
+	typedef GLuint GLprogram;
+	typedef GLuint GLshader;
 	#define USE_BUILTIN_OPENGL
 #else
 	#include "backends/graphics/opengl/opengl-defs.h"
diff --git a/backends/platform/android/graphics.cpp b/backends/platform/android/graphics.cpp
index 5611e1dc3e..c074540d68 100644
--- a/backends/platform/android/graphics.cpp
+++ b/backends/platform/android/graphics.cpp
@@ -65,8 +65,7 @@ void AndroidGraphicsManager::initSurface() {
 	JNI::initSurface();
 
 	// Notify the OpenGL code about our context.
-	// FIXME: Support OpenGL ES 2 contexts
-	setContextType(OpenGL::kContextGLES);
+	setContextType(OpenGL::kContextGLES2);
 
 	// We default to RGB565 and RGBA5551 which is closest to the actual output
 	// mode we setup.
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
index 73f6f5e439..77cdc04da6 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
@@ -192,8 +192,11 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
 		// devices so we have to filter/rank the configs ourselves.
 		_egl_config = chooseEglConfig(configs);
 
+		int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+		int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2,
+		                      EGL10.EGL_NONE };
 		_egl_context = _egl.eglCreateContext(_egl_display, _egl_config,
-											EGL10.EGL_NO_CONTEXT, null);
+		                                     EGL10.EGL_NO_CONTEXT, attrib_list);
 
 		if (_egl_context == EGL10.EGL_NO_CONTEXT)
 			throw new Exception(String.format(Locale.ROOT, "Failed to create context: 0x%x",
diff --git a/configure b/configure
index 4ea2014d9f..a379b2a0fd 100755
--- a/configure
+++ b/configure
@@ -5352,8 +5352,9 @@ esac
 if test "$_opengl_mode" = auto ; then
 	case $_backend in
 		android)
-			# Android always runs in GLES mode
-			_opengl_mode=gles
+			# We require API level 16 while GLES2 APIs have been added in level 8 so we are safe for compilation
+			_opengl_mode=gles2
+			_opengl_game_es2=yes
 			;;
 		sdl)
 			case $_sdlversion in
@@ -5478,7 +5479,8 @@ echocheck "OpenGL for game"
 
 if test "$_opengl_game" = auto ; then
 	_opengl_game=no
-	if (test "$_backend" = "sdl" && test "$_opengl" = yes) || test "$_backend" = "android3d" || test "$_backend" = "switch"; then
+	if (test "$_backend" = "sdl" && test "$_opengl" = yes) || test "$_backend" = "android" || test "$_backend" = "android3d" \
+		|| test "$_backend" = "switch"; then
 		# Try different header filenames
 		# 1) GL/gl.h         This is usually used on POSIX and Windows systems
 		# 2) OpenGL/gl.h     This is used on Mac OS X
@@ -6153,7 +6155,7 @@ case $_host_os in
 		# -lgcc is carefully placed here - we want to catch
 		# all toolchain symbols in *our* libraries rather
 		# than pick up anything unhygenic from the Android libs.
-		LIBS="-Wl,-Bstatic $static_libs -Wl,-Bdynamic -lgcc $system_libs -llog -landroid -lGLESv1_CM"
+		LIBS="-Wl,-Bstatic $static_libs -Wl,-Bdynamic -lgcc $system_libs -llog -landroid -lGLESv2"
 		;;
 	ds)
 		# Moved -Wl,--gc-sections here to avoid it interfering with the library checks
diff --git a/dists/android/AndroidManifest.xml b/dists/android/AndroidManifest.xml
index 1bc93ccf2b..bb97bcae37 100644
--- a/dists/android/AndroidManifest.xml
+++ b/dists/android/AndroidManifest.xml
@@ -23,6 +23,9 @@
 	<uses-feature
 		android:name="android.software.leanback"
 		android:required="false" />
+	<uses-feature
+		android:glEsVersion="0x00020000"
+		android:required="true" />
 
 	<supports-screens
 		android:largeScreens="true"


Commit: 5d56c1cdf0193b60c0ebd1b3b2ea2b7913457a77
    https://github.com/scummvm/scummvm/commit/5d56c1cdf0193b60c0ebd1b3b2ea2b7913457a77
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Merge 3D graphics backend

Move each graphic part in backends/graphics and backends/graphics3d

Changed paths:
  A backends/graphics/android/android-graphics.cpp
  A backends/graphics/android/android-graphics.h
  A backends/graphics3d/android/android-graphics3d.cpp
  A backends/graphics3d/android/android-graphics3d.h
  A backends/graphics3d/android/texture.cpp
  A backends/graphics3d/android/texture.h
  A backends/graphics3d/android/touchcontrols.cpp
  A backends/graphics3d/android/touchcontrols.h
  A dists/android/assets/arrows.tga
  R backends/platform/android/graphics.cpp
  R backends/platform/android/graphics.h
    backends/module.mk
    backends/platform/android/android.cpp
    backends/platform/android/android.h
    backends/platform/android/android.mk
    backends/platform/android/events.cpp
    backends/platform/android/module.mk


diff --git a/backends/platform/android/graphics.cpp b/backends/graphics/android/android-graphics.cpp
similarity index 80%
rename from backends/platform/android/graphics.cpp
rename to backends/graphics/android/android-graphics.cpp
index c074540d68..7b306b9283 100644
--- a/backends/platform/android/graphics.cpp
+++ b/backends/graphics/android/android-graphics.cpp
@@ -37,8 +37,8 @@
 // for the Android port
 #define FORBIDDEN_SYMBOL_EXCEPTION_printf
 
+#include "backends/graphics/android/android-graphics.h"
 #include "backends/platform/android/android.h"
-#include "backends/platform/android/graphics.h"
 #include "backends/platform/android/jni-android.h"
 
 //
@@ -142,3 +142,32 @@ bool AndroidGraphicsManager::notifyMousePosition(Common::Point &mouse) {
 
 	return true;
 }
+
+AndroidCommonGraphics::State AndroidGraphicsManager::getState() const {
+	State state;
+
+	state.screenWidth   = getWidth();
+	state.screenHeight  = getHeight();
+	state.aspectRatio   = getFeatureState(OSystem::kFeatureAspectRatioCorrection);
+	state.fullscreen    = getFeatureState(OSystem::kFeatureFullscreenMode);
+	state.cursorPalette = getFeatureState(OSystem::kFeatureCursorPalette);
+#ifdef USE_RGB_COLOR
+	state.pixelFormat   = getScreenFormat();
+#endif
+	return state;
+}
+
+bool AndroidGraphicsManager::setState(const AndroidCommonGraphics::State &state) {
+	beginGFXTransaction();
+
+#ifdef USE_RGB_COLOR
+		initSize(state.screenWidth, state.screenHeight, &state.pixelFormat);
+#else
+		initSize(state.screenWidth, state.screenHeight, nullptr);
+#endif
+		setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio);
+		setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen);
+		setFeatureState(OSystem::kFeatureCursorPalette, state.cursorPalette);
+
+	return endGFXTransaction() == OSystem::kTransactionSuccess;
+}
diff --git a/backends/platform/android/graphics.h b/backends/graphics/android/android-graphics.h
similarity index 54%
rename from backends/platform/android/graphics.h
rename to backends/graphics/android/android-graphics.h
index 37bd3285f8..7bcc446e17 100644
--- a/backends/platform/android/graphics.h
+++ b/backends/graphics/android/android-graphics.h
@@ -20,26 +20,65 @@
  *
  */
 
-#ifndef ANDROID_GRAPHICS_H
-#define ANDROID_GRAPHICS_H
+#ifndef BACKENDS_GRAPHICS_ANDROID_ANDROID_GRAPHICS_H
+#define BACKENDS_GRAPHICS_ANDROID_ANDROID_GRAPHICS_H
 
 #include "common/scummsys.h"
 #include "backends/graphics/opengl/opengl-graphics.h"
 
-class AndroidGraphicsManager : public OpenGL::OpenGLGraphicsManager {
+class AndroidCommonGraphics {
+public:
+	virtual ~AndroidCommonGraphics() {}
+
+	virtual void initSurface() = 0;
+	virtual void deinitSurface() = 0;
+
+	virtual Common::Point getMousePosition() = 0;
+	virtual bool notifyMousePosition(Common::Point &mouse) = 0;
+
+	/**
+	 * A (subset) of the graphic manager's state. This is used when switching
+	 * between different Android graphic managers at runtime.
+	 */
+	struct State {
+		int screenWidth, screenHeight;
+		bool aspectRatio;
+		bool fullscreen;
+		bool cursorPalette;
+
+#ifdef USE_RGB_COLOR
+		Graphics::PixelFormat pixelFormat;
+#endif
+	};
+
+	/**
+	 * Gets the current state of the graphics manager.
+	 */
+	virtual State getState() const = 0;
+
+	/**
+	 * Sets up a basic state of the graphics manager.
+	 */
+	virtual bool setState(const State &state) = 0;
+};
+
+class AndroidGraphicsManager : public OpenGL::OpenGLGraphicsManager, public AndroidCommonGraphics {
 public:
 	AndroidGraphicsManager();
 	virtual ~AndroidGraphicsManager();
 
-	void initSurface();
-	void deinitSurface();
+	virtual void initSurface() override;
+	virtual void deinitSurface() override;
+
+	virtual AndroidCommonGraphics::State getState() const override;
+	virtual bool setState(const AndroidCommonGraphics::State &state) override;
 
 	void updateScreen() override;
 
 	void displayMessageOnOSD(const Common::U32String &msg) override;
 
-	bool notifyMousePosition(Common::Point &mouse);
-	Common::Point getMousePosition() { return Common::Point(_cursorX, _cursorY); }
+	virtual bool notifyMousePosition(Common::Point &mouse) override;
+	virtual Common::Point getMousePosition() override { return Common::Point(_cursorX, _cursorY); }
 
 	float getHiDPIScreenFactor() const override;
 
diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
new file mode 100644
index 0000000000..63bd4077d4
--- /dev/null
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -0,0 +1,932 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#if defined(__ANDROID__)
+
+// Allow use of stuff in <time.h>
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+
+// Disable printf override in common/forbidden.h to avoid
+// clashes with log.h from the Android SDK.
+// That header file uses
+//   __attribute__ ((format(printf, 3, 4)))
+// which gets messed up by our override mechanism; this could
+// be avoided by either changing the Android SDK to use the equally
+// legal and valid
+//   __attribute__ ((format(printf, 3, 4)))
+// or by refining our printf override to use a varadic macro
+// (which then wouldn't be portable, though).
+// Anyway, for now we just disable the printf override globally
+// for the Android port
+#define FORBIDDEN_SYMBOL_EXCEPTION_printf
+
+#include "common/tokenizer.h"
+#include "graphics/conversion.h"
+#include "graphics/opengl/shader.h"
+#include "graphics/opengl/context.h"
+
+#include "backends/graphics3d/android/android-graphics3d.h"
+#include "backends/platform/android/android.h"
+#include "backends/platform/android/jni-android.h"
+
+AndroidGraphics3dManager::AndroidGraphics3dManager() :
+	_screenChangeID(0),
+	_graphicsMode(0),
+	_opengl(false),
+	_fullscreen(true),
+	_ar_correction(true),
+	_force_redraw(false),
+	_game_texture(0),
+	_game_pbuf(),
+	_frame_buffer(0),
+	_cursorX(0),
+	_cursorY(0),
+	_overlay_texture(0),
+	_show_overlay(false),
+	_mouse_texture(0),
+	_mouse_texture_palette(0),
+	_mouse_texture_rgb(0),
+	_mouse_hotspot(),
+	_mouse_keycolor(0),
+	_show_mouse(false),
+	_use_mouse_palette(false)
+{
+	_game_texture = new GLESFakePalette565Texture();
+	_overlay_texture = new GLES4444Texture();
+	_mouse_texture_palette = new GLESFakePalette5551Texture();
+	_mouse_texture = _mouse_texture_palette;
+
+	initSurface();
+}
+
+AndroidGraphics3dManager::~AndroidGraphics3dManager() {
+	deinitSurface();
+
+	delete _game_texture;
+	delete _overlay_texture;
+	delete _mouse_texture_palette;
+	delete _mouse_texture_rgb;
+
+}
+
+static void logExtensions() {
+	const char *ext_string =
+		reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
+
+	LOGI("Extensions:");
+
+	Common::String exts;
+	Common::StringTokenizer tokenizer(ext_string, " ");
+	while (!tokenizer.empty()) {
+		Common::String token = tokenizer.nextToken();
+
+		exts += token + " ";
+		if (exts.size() > 100) {
+			LOGI("\t%s", exts.c_str());
+			exts = "";
+		}
+	}
+
+	if (exts.size() > 0)
+		LOGI("\t%s", exts.c_str());
+}
+
+
+void AndroidGraphics3dManager::initSurface() {
+	LOGD("initializing surface");
+
+	assert(!JNI::haveSurface());
+
+	JNI::initSurface();
+
+	_screenChangeID = JNI::surface_changeid;
+
+	// Initialize OpenGLES context.
+	OpenGLContext.initialize(OpenGL::kOGLContextGLES2);
+	logExtensions();
+	GLESTexture::initGL();
+
+	if (_game_texture)
+		_game_texture->reinit();
+
+	if (_overlay_texture) {
+		_overlay_texture->reinit();
+		initOverlay();
+	}
+
+	if (_mouse_texture)
+		_mouse_texture->reinit();
+
+	initViewport();
+	updateScreenRect();
+	// double buffered, flip twice
+	clearScreen(kClearUpdate, 2);
+	updateEventScale();
+
+	_touchControls.init(JNI::egl_surface_width, JNI::egl_surface_height);
+}
+
+void AndroidGraphics3dManager::deinitSurface() {
+	if (!JNI::haveSurface())
+		return;
+
+	LOGD("deinitializing surface");
+
+	_screenChangeID = JNI::surface_changeid;
+
+	// release texture resources
+	if (_game_texture)
+		_game_texture->release();
+
+	if (_overlay_texture)
+		_overlay_texture->release();
+
+	if (_mouse_texture)
+		_mouse_texture->release();
+
+	OpenGL::ContextGL::destroy();
+
+	JNI::deinitSurface();
+}
+
+void AndroidGraphics3dManager::updateScreen() {
+	//ENTER();
+
+	GLTHREADCHECK;
+
+	if (!JNI::haveSurface())
+		return;
+
+		if (_game_pbuf) {
+			int pitch = _game_texture->width() * _game_texture->getPixelFormat().bytesPerPixel;
+			_game_texture->updateBuffer(0, 0, _game_texture->width(), _game_texture->height(),
+					_game_pbuf.getRawBuffer(), pitch);
+		}
+
+		if (!_force_redraw &&
+				!_game_texture->dirty() &&
+				!_overlay_texture->dirty() &&
+				!_mouse_texture->dirty())
+			return;
+
+		_force_redraw = false;
+
+		if (_frame_buffer) {
+			_frame_buffer->detach();
+			glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
+		}
+
+		// clear pointer leftovers in dead areas
+		clearScreen(kClear);
+
+		_game_texture->drawTextureRect();
+		if (!_show_overlay) {
+			glEnable(GL_BLEND);
+			_touchControls.draw();
+		}
+
+		int cs = _mouse_targetscale;
+
+		if (_show_overlay) {
+			// ugly, but the modern theme sets a wacko factor, only god knows why
+			cs = 1;
+
+			GLCALL(_overlay_texture->drawTextureRect());
+		}
+
+		if (_show_mouse && !_mouse_texture->isEmpty()) {
+			const Common::Point &mouse = g_system->getEventManager()->getMousePos();
+			if (_show_overlay) {
+				_mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height());
+			}
+	}
+
+	if (!JNI::swapBuffers())
+		LOGW("swapBuffers failed: 0x%x", glGetError());
+
+	if (_frame_buffer)
+		_frame_buffer->attach();
+}
+
+void AndroidGraphics3dManager::displayMessageOnOSD(const Common::U32String &msg) {
+	ENTER("%s", msg.encode().c_str());
+
+	JNI::displayMessageOnOSD(msg);
+}
+
+bool AndroidGraphics3dManager::notifyMousePosition(Common::Point &mouse) {
+	clipMouse(mouse);
+	setMousePosition(mouse.x, mouse.y);
+	return true;
+}
+
+const OSystem::GraphicsMode *AndroidGraphics3dManager::getSupportedGraphicsModes() const {
+	static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+		{ "default", "Default", 0 },
+		{ 0, 0, 0 },
+	};
+
+	return s_supportedGraphicsModes;
+}
+
+int AndroidGraphics3dManager::getDefaultGraphicsMode() const {
+	return 0;
+}
+
+bool AndroidGraphics3dManager::setGraphicsMode(int mode, uint flags) {
+	return true;
+}
+
+int AndroidGraphics3dManager::getGraphicsMode() const {
+	return _graphicsMode;
+}
+
+bool AndroidGraphics3dManager::hasFeature(OSystem::Feature f) const {
+	if (f == OSystem::kFeatureCursorPalette ||
+			f == OSystem::kFeatureOpenGLForGame ||
+			f == OSystem::kFeatureAspectRatioCorrection) {
+		return true;
+	}
+	return false;
+}
+
+void AndroidGraphics3dManager::setFeatureState(OSystem::Feature f, bool enable) {
+	switch (f) {
+	case OSystem::kFeatureCursorPalette:
+		_use_mouse_palette = enable;
+		if (!enable)
+			disableCursorPalette();
+		break;
+	case OSystem::kFeatureFullscreenMode:
+		_fullscreen = enable;
+		updateScreenRect();
+		break;
+	case OSystem::kFeatureAspectRatioCorrection:
+		_ar_correction = enable;
+		updateScreenRect();
+		break;
+	default:
+		break;
+	}
+}
+
+bool AndroidGraphics3dManager::getFeatureState(OSystem::Feature f) const {
+	switch (f) {
+	case OSystem::kFeatureCursorPalette:
+		return _use_mouse_palette;
+	case OSystem::kFeatureFullscreenMode:
+		return _fullscreen;
+	case OSystem::kFeatureAspectRatioCorrection:
+		return _ar_correction;
+	default:
+		return false;
+	}
+}
+
+void AndroidGraphics3dManager::showOverlay() {
+	ENTER();
+
+	_show_overlay = true;
+	_force_redraw = true;
+
+	updateEventScale();
+
+	warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2);
+
+	GLCALL(glDisable(GL_SCISSOR_TEST));
+}
+
+void AndroidGraphics3dManager::hideOverlay() {
+	ENTER();
+
+	_show_overlay = false;
+
+	updateEventScale();
+
+	warpMouse(_game_texture->width() / 2, _game_texture->height() / 2);
+
+	// double buffered, flip twice
+	clearScreen(kClearUpdate, 2);
+
+	GLCALL(glEnable(GL_SCISSOR_TEST));
+}
+
+void AndroidGraphics3dManager::clearOverlay() {
+	ENTER();
+
+	GLTHREADCHECK;
+
+	_overlay_texture->fillBuffer(0);
+}
+
+void AndroidGraphics3dManager::grabOverlay(Graphics::Surface &surface) const {
+	ENTER("%p, %d", buf, pitch);
+
+	GLTHREADCHECK;
+
+	const Graphics::Surface *overlaySurface = _overlay_texture->surface_const();
+
+	assert(surface.w >= overlaySurface->w);
+	assert(surface.h >= overlaySurface->h);
+	assert(surface.format.bytesPerPixel == sizeof(uint16));
+	assert(overlaySurface->format.bytesPerPixel == sizeof(uint16));
+
+	const byte *src = (const byte *)overlaySurface->getPixels();
+	byte *dst = (byte *)surface.getPixels();
+	Graphics::copyBlit(dst, src, surface.pitch, overlaySurface->pitch, overlaySurface->w, overlaySurface->h, sizeof(uint16));
+}
+
+void AndroidGraphics3dManager::copyRectToOverlay(const void *buf, int pitch,
+										int x, int y, int w, int h) {
+	ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
+
+	GLTHREADCHECK;
+
+	_overlay_texture->updateBuffer(x, y, w, h, buf, pitch);
+}
+
+int16 AndroidGraphics3dManager::getOverlayHeight() const {
+	return _overlay_texture->height();
+}
+
+int16 AndroidGraphics3dManager::getOverlayWidth() const {
+	return _overlay_texture->width();
+}
+
+Graphics::PixelFormat AndroidGraphics3dManager::getOverlayFormat() const {
+	return _overlay_texture->getPixelFormat();
+}
+
+int16 AndroidGraphics3dManager::getHeight() const {
+	return _game_texture->height();
+}
+
+int16 AndroidGraphics3dManager::getWidth() const {
+	return _game_texture->width();
+}
+
+void AndroidGraphics3dManager::setPalette(const byte *colors, uint start, uint num) {
+	ENTER("%p, %u, %u", colors, start, num);
+
+#ifdef USE_RGB_COLOR
+	assert(_game_texture->hasPalette());
+#endif
+
+	GLTHREADCHECK;
+
+	if (!_use_mouse_palette)
+		setCursorPaletteInternal(colors, start, num);
+
+	const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
+	byte *p = _game_texture->palette() + start * 2;
+
+	for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+		WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
+}
+
+void AndroidGraphics3dManager::grabPalette(byte *colors, uint start, uint num) const {
+	ENTER("%p, %u, %u", colors, start, num);
+
+#ifdef USE_RGB_COLOR
+	assert(_game_texture->hasPalette());
+#endif
+
+	GLTHREADCHECK;
+
+	const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
+	const byte *p = _game_texture->palette_const() + start * 2;
+
+	for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+		pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]);
+}
+
+Graphics::Surface *AndroidGraphics3dManager::lockScreen() {
+	ENTER();
+
+	GLTHREADCHECK;
+
+	Graphics::Surface *surface = _game_texture->surface();
+	assert(surface->getPixels());
+
+	return surface;
+}
+
+void AndroidGraphics3dManager::unlockScreen() {
+	ENTER();
+
+	GLTHREADCHECK;
+
+	assert(_game_texture->dirty());
+}
+
+void AndroidGraphics3dManager::fillScreen(uint32 col) {
+	ENTER("%u", col);
+
+	GLTHREADCHECK;
+
+	_game_texture->fillBuffer(col);
+}
+
+void AndroidGraphics3dManager::copyRectToScreen(const void *buf, int pitch,
+										int x, int y, int w, int h) {
+	ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
+
+	GLTHREADCHECK;
+
+	_game_texture->updateBuffer(x, y, w, h, buf, pitch);
+}
+
+void AndroidGraphics3dManager::initSize(uint width, uint height,
+								const Graphics::PixelFormat *format) {
+	setupScreen(width, height, true, true);
+}
+
+void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
+								const Graphics::PixelFormat *format) {
+	ENTER("%d, %d, %p", width, height, format);
+
+	GLTHREADCHECK;
+
+#ifdef USE_RGB_COLOR
+	initTexture(&_game_texture, width, height, format);
+#else
+	_game_texture->allocBuffer(width, height);
+#endif
+#ifdef USE_GLES2
+	_frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight());
+	_frame_buffer->attach();
+#endif
+
+	updateScreenRect();
+	updateEventScale();
+
+	// Don't know mouse size yet - it gets reallocated in
+	// setMouseCursor.  We need the palette allocated before
+	// setMouseCursor however, so just take a guess at the desired
+	// size (it's small).
+	_mouse_texture_palette->allocBuffer(20, 20);
+
+	clearScreen(kClear);
+}
+
+int AndroidGraphics3dManager::getScreenChangeID() const {
+	return _screenChangeID;
+}
+
+bool AndroidGraphics3dManager::showMouse(bool visible) {
+	ENTER("%d", visible);
+
+	_show_mouse = visible;
+
+	return true;
+}
+
+void AndroidGraphics3dManager::warpMouse(int x, int y) {
+	ENTER("%d, %d", x, y);
+
+	Common::Event e;
+
+	e.type = Common::EVENT_MOUSEMOVE;
+	e.mouse.x = x;
+	e.mouse.y = y;
+
+	clipMouse(e.mouse);
+
+	setMousePosition(e.mouse.x, e.mouse.y);
+
+	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(e);
+}
+
+void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
+										int hotspotX, int hotspotY,
+										uint32 keycolor, bool dontScale,
+										const Graphics::PixelFormat *format) {
+	ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
+			keycolor, dontScale, format);
+
+	GLTHREADCHECK;
+
+#ifdef USE_RGB_COLOR
+	if (format && format->bytesPerPixel > 1) {
+		if (_mouse_texture != _mouse_texture_rgb) {
+			LOGD("switching to rgb mouse cursor");
+
+			assert(!_mouse_texture_rgb);
+			_mouse_texture_rgb = new GLES5551Texture();
+			_mouse_texture_rgb->setLinearFilter(_graphicsMode == 1);
+		}
+
+		_mouse_texture = _mouse_texture_rgb;
+	} else {
+		if (_mouse_texture != _mouse_texture_palette)
+			LOGD("switching to paletted mouse cursor");
+
+		_mouse_texture = _mouse_texture_palette;
+
+		delete _mouse_texture_rgb;
+		_mouse_texture_rgb = 0;
+	}
+#endif
+
+	_mouse_texture->allocBuffer(w, h);
+
+	if (_mouse_texture == _mouse_texture_palette) {
+		assert(keycolor < 256);
+
+		byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+		WRITE_UINT16(p, READ_UINT16(p) | 1);
+
+		_mouse_keycolor = keycolor;
+
+		p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+		WRITE_UINT16(p, READ_UINT16(p) & ~1);
+	}
+
+	if (w == 0 || h == 0)
+		return;
+
+	if (_mouse_texture == _mouse_texture_palette) {
+		_mouse_texture->updateBuffer(0, 0, w, h, buf, w);
+	} else {
+		uint16 pitch = _mouse_texture->pitch();
+
+		byte *tmp = new byte[pitch * h];
+
+		// meh, a n-bit cursor without alpha bits... this is so silly
+		if (!crossBlit(tmp, (const byte *)buf, pitch, w * format->bytesPerPixel, w, h,
+						_mouse_texture->getPixelFormat(),
+						*format)) {
+			LOGE("crossblit failed");
+
+			delete[] tmp;
+
+			_mouse_texture->allocBuffer(0, 0);
+
+			return;
+		}
+
+		if (format->bytesPerPixel == 2) {
+			const uint16 *s = (const uint16 *)buf;
+			uint16 *d = (uint16 *)tmp;
+			for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
+				for (uint16 x = 0; x < w; ++x, d++)
+					if (*s++ == (keycolor & 0xffff))
+						*d = 0;
+		}
+		else if (format->bytesPerPixel == 4) {
+			const uint32 *s = (const uint32 *)buf;
+			uint16 *d = (uint16 *)tmp;
+			for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
+				for (uint16 x = 0; x < w; ++x, d++)
+					if (*s++ == (keycolor & 0xffff))
+						*d = 0;
+		}
+		else {
+			error("AndroidGraphics3dManager::setMouseCursor: invalid bytesPerPixel %d", format->bytesPerPixel);
+		}
+
+		_mouse_texture->updateBuffer(0, 0, w, h, tmp, pitch);
+
+		delete[] tmp;
+	}
+
+	_mouse_hotspot = Common::Point(hotspotX, hotspotY);
+	// TODO: Adapt to the new "do not scale" cursor logic.
+	_mouse_targetscale = 1;
+}
+
+void AndroidGraphics3dManager::setCursorPaletteInternal(const byte *colors,
+												uint start, uint num) {
+	const Graphics::PixelFormat &pf =
+		_mouse_texture_palette->getPalettePixelFormat();
+	byte *p = _mouse_texture_palette->palette() + start * 2;
+
+	for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+		WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
+
+	p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+	WRITE_UINT16(p, READ_UINT16(p) & ~1);
+}
+
+void AndroidGraphics3dManager::setCursorPalette(const byte *colors,
+										uint start, uint num) {
+	ENTER("%p, %u, %u", colors, start, num);
+
+	GLTHREADCHECK;
+
+	if (!_mouse_texture->hasPalette()) {
+		LOGD("switching to paletted mouse cursor");
+
+		_mouse_texture = _mouse_texture_palette;
+
+		delete _mouse_texture_rgb;
+		_mouse_texture_rgb = 0;
+	}
+
+	setCursorPaletteInternal(colors, start, num);
+	_use_mouse_palette = true;
+}
+
+void AndroidGraphics3dManager::disableCursorPalette() {
+	// when disabling the cursor palette, and we're running a clut8 game,
+	// it expects the game palette to be used for the cursor
+	if (_game_texture->hasPalette()) {
+		const byte *src = _game_texture->palette_const();
+		byte *dst = _mouse_texture_palette->palette();
+
+		const Graphics::PixelFormat &pf_src =
+			_game_texture->getPalettePixelFormat();
+		const Graphics::PixelFormat &pf_dst =
+			_mouse_texture_palette->getPalettePixelFormat();
+
+		uint8 r, g, b;
+
+		for (uint i = 0; i < 256; ++i, src += 2, dst += 2) {
+			pf_src.colorToRGB(READ_UINT16(src), r, g, b);
+			WRITE_UINT16(dst, pf_dst.RGBToColor(r, g, b));
+		}
+
+		byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+		WRITE_UINT16(p, READ_UINT16(p) & ~1);
+	}
+}
+
+bool AndroidGraphics3dManager::lockMouse(bool lock) {
+	_show_mouse = lock;
+	return true;
+}
+
+void AndroidGraphics3dManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) {
+	setupScreen(screenW, screenH, fullscreen, accel3d, true);
+}
+
+void AndroidGraphics3dManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame) {
+	_opengl = accel3d;
+	initViewport();
+
+	if (_opengl) {
+		// resize game texture
+		initSizeIntern(screenW, screenH, 0);
+		if (isGame)
+			_game_texture->setGameTexture();
+		// format is not used by the gfx_opengl driver, use fake format
+		_game_pbuf.set(Graphics::PixelFormat(), 0);
+
+	} else {
+		Graphics::PixelFormat format = GLES565Texture::pixelFormat();
+		initSizeIntern(screenW, screenH, &format);
+		// as there is no support for the texture surface's lock/unlock mechanism in gfx_tinygl/...
+		// do not use _game_texture->surface()->pixels directly
+		_game_pbuf.create(_game_texture->getPixelFormat(),
+				_game_texture->width() * _game_texture->height(), DisposeAfterUse::YES);
+	}
+}
+
+void AndroidGraphics3dManager::clipMouse(Common::Point &p) const {
+	const GLESBaseTexture *tex = getActiveTexture();
+
+	p.x = CLIP(p.x, tex->getDrawRect().left, tex->getDrawRect().right);
+	p.y = CLIP(p.y, tex->getDrawRect().top, tex->getDrawRect().bottom);
+}
+
+#ifdef USE_RGB_COLOR
+Graphics::PixelFormat AndroidGraphics3dManager::getScreenFormat() const {
+	return _game_texture->getPixelFormat();
+}
+
+Common::List<Graphics::PixelFormat> AndroidGraphics3dManager::getSupportedFormats() const {
+	Common::List<Graphics::PixelFormat> res;
+	res.push_back(GLES565Texture::pixelFormat());
+	res.push_back(GLES5551Texture::pixelFormat());
+	res.push_back(GLES4444Texture::pixelFormat());
+	res.push_back(Graphics::PixelFormat::createFormatCLUT8());
+
+	return res;
+}
+#endif
+
+void AndroidGraphics3dManager::updateScreenRect() {
+	Common::Rect rect(0, 0, JNI::egl_surface_width, JNI::egl_surface_height);
+
+	_overlay_texture->setDrawRect(rect);
+
+	uint16 w = _game_texture->width();
+	uint16 h = _game_texture->height();
+
+	if (w && h && _ar_correction) {
+
+		float dpi[2];
+		JNI::getDPI(dpi);
+
+		float screen_ar;
+		if (dpi[0] != 0.0 && dpi[1] != 0.0) {
+			// horizontal orientation
+			screen_ar = (dpi[1] * JNI::egl_surface_width) /
+						(dpi[0] * JNI::egl_surface_height);
+		} else {
+			screen_ar = float(JNI::egl_surface_width) / float(JNI::egl_surface_height);
+		}
+
+		float game_ar = float(w) / float(h);
+
+		if (screen_ar > game_ar) {
+			rect.setWidth(round(JNI::egl_surface_height * game_ar));
+			rect.moveTo((JNI::egl_surface_width - rect.width()) / 2, 0);
+		} else {
+			rect.setHeight(round(JNI::egl_surface_width / game_ar));
+			rect.moveTo((JNI::egl_surface_height - rect.height()) / 2, 0);
+		}
+	}
+
+	_game_texture->setDrawRect(rect);
+}
+
+const GLESBaseTexture *AndroidGraphics3dManager::getActiveTexture() const {
+	if (_show_overlay)
+		return _overlay_texture;
+	else
+		return _game_texture;
+}
+
+void AndroidGraphics3dManager::initOverlay() {
+	// minimum of 320x200
+	// (surface can get smaller when opening the virtual keyboard on *QVGA*)
+	int overlay_width = MAX(JNI::egl_surface_width, 320);
+	int overlay_height = MAX(JNI::egl_surface_height, 200);
+
+	// the 'normal' theme layout uses a max height of 400 pixels. if the
+	// surface is too big we use only a quarter of the size so that the widgets
+	// don't get too small. if the surface height has less than 800 pixels, this
+	// enforces the 'lowres' layout, which will be scaled back up by factor 2x,
+	// but this looks way better than the 'normal' layout scaled by some
+	// calculated factors
+//	while (overlay_height > 480) {
+//		overlay_width /= 2;
+//		overlay_height /= 2;
+//	}
+
+	LOGI("overlay size is %ux%u", overlay_width, overlay_height);
+
+	_overlay_texture->allocBuffer(overlay_width, overlay_height);
+	_overlay_texture->setDrawRect(0, 0,
+									JNI::egl_surface_width, JNI::egl_surface_height);
+}
+
+void AndroidGraphics3dManager::initViewport() {
+	LOGD("initializing viewport");
+
+	assert(JNI::haveSurface());
+
+	GLCALL(glDisable(GL_CULL_FACE));
+	GLCALL(glDisable(GL_DEPTH_TEST));
+
+	GLCALL(glEnable(GL_BLEND));
+	GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+
+	GLCALL(glViewport(0, 0, JNI::egl_surface_width, JNI::egl_surface_height));
+	LOGD("viewport size: %dx%d", JNI::egl_surface_width, JNI::egl_surface_height);
+}
+
+void AndroidGraphics3dManager::updateEventScale() {
+	const GLESBaseTexture *texture = getActiveTexture();
+	if (texture) {
+		dynamic_cast<OSystem_Android *>(g_system)->updateEventScale(texture->width(), texture->height());
+	}
+}
+
+void AndroidGraphics3dManager::clearScreen(FixupType type, byte count) {
+	assert(count > 0);
+
+	bool sm = _show_mouse;
+	_show_mouse = false;
+
+	GLCALL(glDisable(GL_SCISSOR_TEST));
+
+	for (byte i = 0; i < count; ++i) {
+		// clear screen
+		GLCALL(glClearColor(0, 0, 0, 1 << 16));
+		if (_opengl) {
+			GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
+		} else {
+			GLCALL(glClear(GL_COLOR_BUFFER_BIT));
+		}
+
+		switch (type) {
+		case kClear:
+			break;
+
+		case kClearSwap:
+			JNI::swapBuffers();
+			break;
+
+		case kClearUpdate:
+			_force_redraw = true;
+			updateScreen();
+			break;
+		}
+	}
+
+	if (!_show_overlay)
+		GLCALL(glEnable(GL_SCISSOR_TEST));
+
+	_show_mouse = sm;
+	_force_redraw = true;
+}
+
+#ifdef USE_RGB_COLOR
+void AndroidGraphics3dManager::initTexture(GLESBaseTexture **texture,
+									uint width, uint height,
+									const Graphics::PixelFormat *format) {
+	assert(texture);
+	Graphics::PixelFormat format_clut8 =
+		Graphics::PixelFormat::createFormatCLUT8();
+	Graphics::PixelFormat format_current;
+	Graphics::PixelFormat format_new;
+
+	if (*texture)
+		format_current = (*texture)->getPixelFormat();
+	else
+		format_current = Graphics::PixelFormat();
+
+	if (format)
+		format_new = *format;
+	else
+		format_new = format_clut8;
+
+	if (format_current != format_new) {
+		if (*texture)
+			LOGD("switching pixel format from: %s",
+					(*texture)->getPixelFormat().toString().c_str());
+
+		delete *texture;
+
+		if (format_new == GLES565Texture::pixelFormat())
+			*texture = new GLES565Texture();
+		else if (format_new == GLES5551Texture::pixelFormat())
+			*texture = new GLES5551Texture();
+		else if (format_new == GLES4444Texture::pixelFormat())
+			*texture = new GLES4444Texture();
+		else {
+			// TODO what now?
+			if (format_new != format_clut8)
+				LOGE("unsupported pixel format: %s",
+					format_new.toString().c_str());
+
+			*texture = new GLESFakePalette565Texture;
+		}
+
+		LOGD("new pixel format: %s",
+				(*texture)->getPixelFormat().toString().c_str());
+	}
+
+	(*texture)->allocBuffer(width, height);
+}
+#endif
+
+AndroidCommonGraphics::State AndroidGraphics3dManager::getState() const {
+	AndroidCommonGraphics::State state;
+
+	state.screenWidth   = getWidth();
+	state.screenHeight  = getHeight();
+	state.aspectRatio   = getFeatureState(OSystem::kFeatureAspectRatioCorrection);
+	state.fullscreen    = getFeatureState(OSystem::kFeatureFullscreenMode);
+	state.cursorPalette = getFeatureState(OSystem::kFeatureCursorPalette);
+#ifdef USE_RGB_COLOR
+	state.pixelFormat   = getScreenFormat();
+#endif
+	return state;
+}
+
+bool AndroidGraphics3dManager::setState(const AndroidCommonGraphics::State &state) {
+#ifdef USE_RGB_COLOR
+		initSize(state.screenWidth, state.screenHeight, &state.pixelFormat);
+#else
+		initSize(state.screenWidth, state.screenHeight, nullptr);
+#endif
+		setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio);
+		setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen);
+		setFeatureState(OSystem::kFeatureCursorPalette, state.cursorPalette);
+
+		return true;
+}
+
+#endif
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
new file mode 100644
index 0000000000..1ea67f3290
--- /dev/null
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -0,0 +1,182 @@
+/* ResidualVM - Graphic Adventure Engine
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS3D_ANDROID_ANDROID_GRAPHICS3D_H
+#define BACKENDS_GRAPHICS3D_ANDROID_ANDROID_GRAPHICS3D_H
+
+#include "common/scummsys.h"
+#include "graphics/opengl/framebuffer.h"
+
+#include "backends/graphics/graphics.h"
+#include "backends/graphics/android/android-graphics.h"
+#include "backends/graphics3d/android/texture.h"
+#include "backends/graphics3d/android/touchcontrols.h"
+
+class AndroidGraphics3dManager : public GraphicsManager, public AndroidCommonGraphics {
+public:
+	AndroidGraphics3dManager();
+	virtual ~AndroidGraphics3dManager();
+
+	virtual void initSurface() override;
+	virtual void deinitSurface() override;
+
+	virtual AndroidCommonGraphics::State getState() const override;
+	virtual bool setState(const AndroidCommonGraphics::State &state) override;
+
+	void updateScreen() override;
+
+	void displayMessageOnOSD(const Common::U32String &msg);
+
+	virtual bool notifyMousePosition(Common::Point &mouse) override;
+	virtual Common::Point getMousePosition() override { return Common::Point(_cursorX, _cursorY); }
+	void setMousePosition(int x, int y) { _cursorX = x; _cursorY = y; }
+
+	virtual void beginGFXTransaction() {}
+	virtual OSystem::TransactionError endGFXTransaction() { return OSystem::kTransactionSuccess; }
+
+	virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
+	virtual int getDefaultGraphicsMode() const override;
+	virtual bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) override;
+	virtual int getGraphicsMode() const override;
+
+	virtual bool hasFeature(OSystem::Feature f) const override;
+	virtual void setFeatureState(OSystem::Feature f, bool enable) override;
+	virtual bool getFeatureState(OSystem::Feature f) const override;
+
+	virtual void showOverlay() override;
+	virtual void hideOverlay() override;
+	virtual void clearOverlay() override;
+	virtual void grabOverlay(Graphics::Surface &surface) const override;
+	virtual void copyRectToOverlay(const void *buf, int pitch,
+									int x, int y, int w, int h) override;
+	virtual int16 getOverlayHeight() const override;
+	virtual int16 getOverlayWidth() const override;
+	virtual Graphics::PixelFormat getOverlayFormat() const override;
+	virtual bool isOverlayVisible() const override { return _show_overlay; }
+
+	virtual int16 getHeight() const override;
+	virtual int16 getWidth() const override;
+
+	// PaletteManager API
+	virtual void setPalette(const byte *colors, uint start, uint num) override;
+	virtual void grabPalette(byte *colors, uint start, uint num) const override;
+	virtual void copyRectToScreen(const void *buf, int pitch, int x, int y,
+									int w, int h) override;
+	virtual Graphics::Surface *lockScreen() override;
+	virtual void unlockScreen() override;
+	virtual void fillScreen(uint32 col);
+
+	virtual void setShakePos(int shakeXOffset, int shakeYOffset) {};
+	virtual void setFocusRectangle(const Common::Rect& rect) {}
+	virtual void clearFocusRectangle() {}
+
+	virtual void initSize(uint width, uint height,
+							const Graphics::PixelFormat *format) override;
+	virtual int getScreenChangeID() const override;
+
+	virtual bool showMouse(bool visible) override;
+	virtual void warpMouse(int x, int y) override;
+	virtual bool lockMouse(bool lock) override;
+	virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
+								int hotspotY, uint32 keycolor,
+								bool dontScale,
+								const Graphics::PixelFormat *format) override;
+	virtual void setCursorPalette(const byte *colors, uint start, uint num) override;
+
+
+	void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d);
+
+	void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame);
+	void updateScreenRect();
+	const GLESBaseTexture *getActiveTexture() const;
+	void clipMouse(Common::Point &p) const;
+
+#ifdef USE_RGB_COLOR
+	virtual Graphics::PixelFormat getScreenFormat() const override;
+	virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
+#endif
+
+protected:
+	void setSystemMousePosition(int x, int y) {}
+
+	bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format);
+
+	void refreshScreen();
+
+	void *getProcAddress(const char *name) const;
+
+private:
+	void setCursorPaletteInternal(const byte *colors, uint start, uint num);
+	void disableCursorPalette();
+	void initOverlay();
+	void initViewport();
+	void updateEventScale();
+	void initSizeIntern(uint width, uint height, const Graphics::PixelFormat *format);
+
+	enum FixupType {
+		kClear = 0,		// glClear
+		kClearSwap,		// glClear + swapBuffers
+		kClearUpdate	// glClear + updateScreen
+	};
+
+	void clearScreen(FixupType type, byte count = 1);
+#ifdef USE_RGB_COLOR
+	void initTexture(GLESBaseTexture **texture, uint width, uint height,
+						const Graphics::PixelFormat *format);
+#endif
+
+private:
+	int _screenChangeID;
+	int _graphicsMode;
+	bool _opengl;
+	bool _fullscreen;
+	bool _ar_correction;
+	bool _force_redraw;
+
+	// Game layer
+	GLESBaseTexture *_game_texture;
+	Graphics::PixelBuffer _game_pbuf;
+	OpenGL::FrameBuffer *_frame_buffer;
+
+	/**
+	 * The position of the mouse cursor, in window coordinates.
+	 */
+	int _cursorX, _cursorY;
+
+	// Overlay layer
+	GLES4444Texture *_overlay_texture;
+	bool _show_overlay;
+
+	// Mouse layer
+	GLESBaseTexture *_mouse_texture;
+	GLESBaseTexture *_mouse_texture_palette;
+	GLES5551Texture *_mouse_texture_rgb;
+	Common::Point _mouse_hotspot;
+	uint32 _mouse_keycolor;
+	int _mouse_targetscale;
+	bool _show_mouse;
+	bool _use_mouse_palette;
+
+	TouchControls _touchControls;
+};
+
+#endif
diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
new file mode 100644
index 0000000000..3faa689409
--- /dev/null
+++ b/backends/graphics3d/android/texture.cpp
@@ -0,0 +1,469 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#if defined(__ANDROID__)
+
+// Allow use of stuff in <time.h>
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+
+// Disable printf override in common/forbidden.h to avoid
+// clashes with log.h from the Android SDK.
+// That header file uses
+//   __attribute__ ((format(printf, 3, 4)))
+// which gets messed up by our override mechanism; this could
+// be avoided by either changing the Android SDK to use the equally
+// legal and valid
+//   __attribute__ ((format(printf, 3, 4)))
+// or by refining our printf override to use a varadic macro
+// (which then wouldn't be portable, though).
+// Anyway, for now we just disable the printf override globally
+// for the Android port
+#define FORBIDDEN_SYMBOL_EXCEPTION_printf
+
+#include "base/main.h"
+#include "graphics/surface.h"
+#include "graphics/opengl/shader.h"
+#include "graphics/opengl/context.h"
+
+#include "common/rect.h"
+#include "common/array.h"
+#include "common/util.h"
+
+#include "backends/platform/android/android.h"
+#include "backends/platform/android/jni-android.h"
+#include "backends/graphics3d/android/texture.h"
+
+// Supported GL extensions
+static bool npot_supported = false;
+
+OpenGL::ShaderGL * g_box_shader;
+GLuint g_verticesVBO;
+
+template<class T>
+static T nextHigher2(T k) {
+	if (k == 0)
+		return 1;
+	--k;
+
+	for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)
+		k = k | k >> i;
+
+	return k + 1;
+}
+
+const GLfloat vertices[] = {
+	0.0, 0.0,
+	1.0, 0.0,
+	0.0, 1.0,
+	1.0, 1.0,
+};
+
+void GLESBaseTexture::initGL() {
+	npot_supported = OpenGLContext.NPOTSupported;
+
+	const char* attributes[] = { "position", "texcoord", NULL };
+	g_box_shader = OpenGL::ShaderGL::fromStrings("control", OpenGL::BuiltinShaders::controlVertex, OpenGL::BuiltinShaders::controlFragment, attributes);
+	g_verticesVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
+	g_box_shader->enableVertexAttribute("position", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
+	g_box_shader->enableVertexAttribute("texcoord", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
+}
+
+GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
+									Graphics::PixelFormat pixelFormat) :
+	_glFormat(glFormat),
+	_glType(glType),
+	_glFilter(GL_NEAREST),
+	_texture_name(0),
+	_surface(),
+	_texture_width(0),
+	_texture_height(0),
+	_draw_rect(),
+	_all_dirty(false),
+	_dirty_rect(),
+	_pixelFormat(pixelFormat),
+	_palettePixelFormat(),
+	_is_game_texture(false)
+{
+	GLCALL(glGenTextures(1, &_texture_name));
+}
+
+GLESBaseTexture::~GLESBaseTexture() {
+	release();
+}
+
+void GLESBaseTexture::release() {
+	if (_texture_name) {
+		GLCALL(glDeleteTextures(1, &_texture_name));
+		_texture_name = 0;
+	}
+}
+
+void GLESBaseTexture::reinit() {
+	GLCALL(glGenTextures(1, &_texture_name));
+
+	initSize();
+
+	setDirty();
+}
+
+void GLESBaseTexture::initSize() {
+	// Allocate room for the texture now, but pixel data gets uploaded
+	// later (perhaps with multiple TexSubImage2D operations).
+	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+	GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
+	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
+	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+	GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glFormat,
+						_texture_width, _texture_height,
+						0, _glFormat, _glType, 0));
+}
+
+void GLESBaseTexture::setLinearFilter(bool value) {
+	if (value)
+		_glFilter = GL_LINEAR;
+	else
+		_glFilter = GL_NEAREST;
+
+	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+
+	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
+}
+
+void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
+	_surface.w = w;
+	_surface.h = h;
+	_surface.format = _pixelFormat;
+
+	if (w == _texture_width && h == _texture_height)
+		return;
+
+	if (npot_supported) {
+		_texture_width = _surface.w;
+		_texture_height = _surface.h;
+	} else {
+		_texture_width = nextHigher2(_surface.w);
+		_texture_height = nextHigher2(_surface.h);
+	}
+
+	initSize();
+}
+
+void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
+//	LOGD("*** Texture %p: Drawing %dx%d rect to (%d,%d)", this, w, h, x, y);
+
+	assert(g_box_shader);
+	g_box_shader->use();
+
+	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+	const GLfloat offsetX    = float(x) / float(JNI::egl_surface_width);
+	const GLfloat offsetY    = float(y) / float(JNI::egl_surface_height);
+	const GLfloat sizeW      = float(w) / float(JNI::egl_surface_width);
+	const GLfloat sizeH      = float(h) / float(JNI::egl_surface_height);
+	Math::Vector4d clipV = Math::Vector4d(clip.left, clip.top, clip.right, clip.bottom);
+	clipV.x() /= _texture_width; clipV.y() /= _texture_height;
+	clipV.z() /= _texture_width; clipV.w() /= _texture_height;
+//	LOGD("*** Drawing at (%f,%f) , size %f x %f", float(x) / float(_surface.w), float(y) / float(_surface.h),  tex_width, tex_height);
+
+	g_box_shader->setUniform("offsetXY", Math::Vector2d(offsetX, offsetY));
+	g_box_shader->setUniform("sizeWH", Math::Vector2d(sizeW, sizeH));
+	g_box_shader->setUniform("clip", clipV);
+	g_box_shader->setUniform("flipY", !_is_game_texture);
+
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+	clearDirty();
+}
+
+const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const {
+	return _pixelFormat;
+}
+
+GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
+							Graphics::PixelFormat pixelFormat) :
+	GLESBaseTexture(glFormat, glType, pixelFormat),
+	_pixels(0),
+	_buf(0) {
+}
+
+GLESTexture::~GLESTexture() {
+	delete[] _buf;
+	delete[] _pixels;
+}
+
+void GLESTexture::allocBuffer(GLuint w, GLuint h) {
+	GLuint oldw = _surface.w;
+	GLuint oldh = _surface.h;
+
+	GLESBaseTexture::allocBuffer(w, h);
+
+	_surface.pitch = w * _pixelFormat.bytesPerPixel;
+
+	if (_surface.w == oldw && _surface.h == oldh) {
+		fillBuffer(0);
+		return;
+	}
+
+	delete[] _buf;
+	delete[] _pixels;
+
+	_pixels = new byte[w * h * _surface.format.bytesPerPixel];
+	assert(_pixels);
+
+	_surface.setPixels(_pixels);
+
+	fillBuffer(0);
+
+	_buf = new byte[w * h * _surface.format.bytesPerPixel];
+	assert(_buf);
+}
+
+void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
+								const void *buf, int pitch_buf) {
+	setDirtyRect(Common::Rect(x, y, x + w, y + h));
+
+	const byte *src = (const byte *)buf;
+	byte *dst = _pixels + y * _surface.pitch + x * _surface.format.bytesPerPixel;
+
+	do {
+		memcpy(dst, src, w * _surface.format.bytesPerPixel);
+		dst += _surface.pitch;
+		src += pitch_buf;
+	} while (--h);
+}
+
+void GLESTexture::fillBuffer(uint32 color) {
+	assert(_surface.getPixels());
+
+	if (_pixelFormat.bytesPerPixel == 1 ||
+			((color & 0xff) == ((color >> 8) & 0xff)))
+		memset(_pixels, color & 0xff, _surface.pitch * _surface.h);
+	else
+		Common::fill(_pixels, _pixels + _surface.pitch * _surface.h,
+						(uint16)color);
+
+	setDirty();
+}
+
+void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
+	if (_all_dirty) {
+		_dirty_rect.top = 0;
+		_dirty_rect.left = 0;
+		_dirty_rect.bottom = _surface.h;
+		_dirty_rect.right = _surface.w;
+
+		_all_dirty = false;
+	}
+
+	if (!_dirty_rect.isEmpty()) {
+		byte *_tex;
+
+		int16 dwidth = _dirty_rect.width();
+		int16 dheight = _dirty_rect.height();
+
+		if (dwidth == _surface.w) {
+			_tex = _pixels + _dirty_rect.top * _surface.pitch;
+		} else {
+			_tex = _buf;
+
+			byte *src = _pixels + _dirty_rect.top * _surface.pitch +
+						_dirty_rect.left * _surface.format.bytesPerPixel;
+			byte *dst = _buf;
+
+			uint16 l = dwidth * _surface.format.bytesPerPixel;
+
+			for (uint16 i = 0; i < dheight; ++i) {
+				memcpy(dst, src, l);
+				src += _surface.pitch;
+				dst += l;
+			}
+		}
+
+		GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+		GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
+
+		GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
+								_dirty_rect.left, _dirty_rect.top,
+								dwidth, dheight, _glFormat, _glType, _tex));
+	}
+
+	GLESBaseTexture::drawTexture(x, y, w, h, clip);
+}
+
+GLES4444Texture::GLES4444Texture() :
+	GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) {
+}
+
+GLES4444Texture::~GLES4444Texture() {
+}
+
+GLES8888Texture::GLES8888Texture() :
+	GLESTexture(GL_RGBA, GL_UNSIGNED_BYTE, pixelFormat()) {
+}
+
+GLES8888Texture::~GLES8888Texture() {
+}
+
+GLES5551Texture::GLES5551Texture() :
+	GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixelFormat()) {
+}
+
+GLES5551Texture::~GLES5551Texture() {
+}
+
+GLES565Texture::GLES565Texture() :
+	GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixelFormat()) {
+}
+
+GLES565Texture::~GLES565Texture() {
+}
+
+GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
+									Graphics::PixelFormat pixelFormat) :
+	GLESBaseTexture(glFormat, glType, pixelFormat),
+	_palette(0),
+	_pixels(0),
+	_buf(0)
+{
+	_palettePixelFormat = pixelFormat;
+	_fake_format = Graphics::PixelFormat::createFormatCLUT8();
+
+	_palette = new uint16[256];
+	assert(_palette);
+
+	memset(_palette, 0, 256 * 2);
+}
+
+GLESFakePaletteTexture::~GLESFakePaletteTexture() {
+	delete[] _buf;
+	delete[] _pixels;
+	delete[] _palette;
+}
+
+void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
+	GLuint oldw = _surface.w;
+	GLuint oldh = _surface.h;
+
+	GLESBaseTexture::allocBuffer(w, h);
+
+	_surface.format = Graphics::PixelFormat::createFormatCLUT8();
+	_surface.pitch = w;
+
+	if (_surface.w == oldw && _surface.h == oldh) {
+		fillBuffer(0);
+		return;
+	}
+
+	delete[] _buf;
+	delete[] _pixels;
+
+	_pixels = new byte[w * h];
+	assert(_pixels);
+
+	// fixup surface, for the outside this is a CLUT8 surface
+	_surface.setPixels(_pixels);
+
+	fillBuffer(0);
+
+	_buf = new uint16[w * h];
+	assert(_buf);
+}
+
+void GLESFakePaletteTexture::fillBuffer(uint32 color) {
+	assert(_surface.getPixels());
+	memset(_surface.getPixels(), color & 0xff, _surface.pitch * _surface.h);
+	setDirty();
+}
+
+void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w,
+											GLuint h, const void *buf,
+											int pitch_buf) {
+	setDirtyRect(Common::Rect(x, y, x + w, y + h));
+
+	const byte *src = (const byte *)buf;
+	byte *dst = _pixels + y * _surface.pitch + x;
+
+	do {
+		memcpy(dst, src, w);
+		dst += _surface.pitch;
+		src += pitch_buf;
+	} while (--h);
+}
+
+void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
+	if (_all_dirty) {
+		_dirty_rect.top = 0;
+		_dirty_rect.left = 0;
+		_dirty_rect.bottom = _surface.h;
+		_dirty_rect.right = _surface.w;
+
+		_all_dirty = false;
+	}
+
+	if (!_dirty_rect.isEmpty()) {
+		int16 dwidth = _dirty_rect.width();
+		int16 dheight = _dirty_rect.height();
+
+		byte *src = _pixels + _dirty_rect.top * _surface.pitch +
+					_dirty_rect.left;
+		uint16 *dst = _buf;
+		uint pitch_delta = _surface.pitch - dwidth;
+
+		for (uint16 j = 0; j < dheight; ++j) {
+			for (uint16 i = 0; i < dwidth; ++i)
+				*dst++ = _palette[*src++];
+			src += pitch_delta;
+		}
+
+		GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+
+		GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
+								_dirty_rect.left, _dirty_rect.top,
+								dwidth, dheight, _glFormat, _glType, _buf));
+	}
+
+	GLESBaseTexture::drawTexture(x, y, w, h, clip);
+}
+
+const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const {
+	return _fake_format;
+}
+
+GLESFakePalette565Texture::GLESFakePalette565Texture() :
+	GLESFakePaletteTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+							GLES565Texture::pixelFormat()) {
+}
+
+GLESFakePalette565Texture::~GLESFakePalette565Texture() {
+}
+
+GLESFakePalette5551Texture::GLESFakePalette5551Texture() :
+	GLESFakePaletteTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
+							GLES5551Texture::pixelFormat()) {
+}
+
+GLESFakePalette5551Texture::~GLESFakePalette5551Texture() {
+}
+
+#endif
diff --git a/backends/graphics3d/android/texture.h b/backends/graphics3d/android/texture.h
new file mode 100644
index 0000000000..b05711c6b1
--- /dev/null
+++ b/backends/graphics3d/android/texture.h
@@ -0,0 +1,312 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS3D_ANDROID_TEXTURE_H
+#define BACKENDS_GRAPHICS3D_ANDROID_TEXTURE_H
+
+#if defined(__ANDROID__)
+
+#define GL_GLEXT_PROTOTYPES
+#include <GLES/gl.h>
+
+#include "graphics/surface.h"
+#include "graphics/pixelformat.h"
+
+#include "common/rect.h"
+#include "common/array.h"
+
+class GLESBaseTexture {
+public:
+	static void initGL();
+
+protected:
+	GLESBaseTexture(GLenum glFormat, GLenum glType,
+					Graphics::PixelFormat pixelFormat);
+
+public:
+	virtual ~GLESBaseTexture();
+
+	void release();
+	void reinit();
+	void initSize();
+
+	void setLinearFilter(bool value);
+
+	virtual void allocBuffer(GLuint w, GLuint h);
+
+	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
+								const void *buf, int pitch_buf) = 0;
+	virtual void fillBuffer(uint32 color) = 0;
+
+	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
+		drawTexture(x, y, w, h, Common::Rect(0, 0, width(), height()));
+	}
+	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip);
+
+
+	inline void setDrawRect(const Common::Rect &rect) {
+		_draw_rect = rect;
+	}
+
+	inline void setDrawRect(int16 w, int16 h) {
+		_draw_rect = Common::Rect(w, h);
+	}
+
+	inline void setDrawRect(int16 x1, int16 y1, int16 x2, int16 y2) {
+		_draw_rect = Common::Rect(x1, y1, x2, y2);
+	}
+
+	inline const Common::Rect &getDrawRect() const {
+		return _draw_rect;
+	}
+
+	inline void drawTextureRect() {
+		drawTexture(_draw_rect.left, _draw_rect.top,
+					_draw_rect.width(), _draw_rect.height());
+	}
+
+	inline void drawTextureOrigin() {
+			drawTexture(0, 0, _surface.w, _surface.h);
+	}
+
+	inline GLuint width() const {
+		return _surface.w;
+	}
+
+	inline GLuint height() const {
+		return _surface.h;
+	}
+
+	inline GLuint texWidth() const {
+		return _texture_width;
+	}
+
+	inline GLuint texHeight() const {
+		return _texture_height;
+	}
+
+	inline uint16 pitch() const {
+		return _surface.pitch;
+	}
+
+	inline bool isEmpty() const {
+		return _surface.w == 0 || _surface.h == 0;
+	}
+
+	inline const Graphics::Surface *surface_const() const {
+		return &_surface;
+	}
+
+	inline Graphics::Surface *surface() {
+		setDirty();
+		return &_surface;
+	}
+
+	virtual const byte *palette_const() const {
+		return 0;
+	};
+
+	virtual byte *palette() {
+		return 0;
+	};
+
+	inline bool hasPalette() const {
+		return _palettePixelFormat.bytesPerPixel > 0;
+	}
+
+	inline bool dirty() const {
+		return _all_dirty || !_dirty_rect.isEmpty();
+	}
+
+	virtual const Graphics::PixelFormat &getPixelFormat() const;
+
+	inline const Graphics::PixelFormat &getPalettePixelFormat() const {
+		return _palettePixelFormat;
+	}
+
+	GLuint getTextureName() const {
+		return _texture_name;
+	}
+
+	void setGameTexture() {
+		_is_game_texture = true;
+	}
+
+protected:
+	inline void setDirty() {
+		_all_dirty = true;
+	}
+
+	inline void clearDirty() {
+		_all_dirty = false;
+		_dirty_rect.top = 0;
+		_dirty_rect.left = 0;
+		_dirty_rect.bottom = 0;
+		_dirty_rect.right = 0;
+	}
+
+	inline void setDirtyRect(const Common::Rect& r) {
+		if (!_all_dirty) {
+			if (_dirty_rect.isEmpty())
+				_dirty_rect = r;
+			else
+				_dirty_rect.extend(r);
+		}
+	}
+
+	GLenum _glFormat;
+	GLenum _glType;
+	GLint _glFilter;
+
+	GLuint _texture_name;
+	Graphics::Surface _surface;
+	GLuint _texture_width;
+	GLuint _texture_height;
+
+	Common::Rect _draw_rect;
+
+	bool _all_dirty;
+	Common::Rect _dirty_rect;
+
+	Graphics::PixelFormat _pixelFormat;
+	Graphics::PixelFormat _palettePixelFormat;
+
+	bool _is_game_texture;
+};
+
+class GLESTexture : public GLESBaseTexture {
+protected:
+	GLESTexture(GLenum glFormat, GLenum glType,
+				Graphics::PixelFormat pixelFormat);
+
+public:
+	virtual ~GLESTexture();
+
+	virtual void allocBuffer(GLuint w, GLuint h);
+
+	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
+								const void *buf, int pitch_buf);
+	virtual void fillBuffer(uint32 color);
+
+	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
+		drawTexture(x, y, w, h, Common::Rect(0, 0, width(), height()));
+	}
+	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip);
+
+protected:
+	byte *_pixels;
+	byte *_buf;
+};
+
+class GLES8888Texture : public GLESTexture {
+public:
+	GLES8888Texture();
+	virtual ~GLES8888Texture();
+
+	static Graphics::PixelFormat pixelFormat() {
+		return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+	}
+};
+
+// RGBA4444 texture
+class GLES4444Texture : public GLESTexture {
+public:
+	GLES4444Texture();
+	virtual ~GLES4444Texture();
+
+	static Graphics::PixelFormat pixelFormat() {
+		return Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0);
+	}
+};
+
+// RGBA5551 texture
+class GLES5551Texture : public GLESTexture {
+public:
+	GLES5551Texture();
+	virtual ~GLES5551Texture();
+
+	static inline Graphics::PixelFormat pixelFormat() {
+		return Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0);
+	}
+};
+
+// RGB565 texture
+class GLES565Texture : public GLESTexture {
+public:
+	GLES565Texture();
+	virtual ~GLES565Texture();
+
+	static inline Graphics::PixelFormat pixelFormat() {
+		return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
+	}
+};
+
+class GLESFakePaletteTexture : public GLESBaseTexture {
+protected:
+	GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
+							Graphics::PixelFormat pixelFormat);
+
+public:
+	virtual ~GLESFakePaletteTexture();
+
+	virtual void allocBuffer(GLuint w, GLuint h);
+	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
+								const void *buf, int pitch_buf);
+	virtual void fillBuffer(uint32 color);
+
+	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
+		drawTexture(x, y, w, h, Common::Rect(0, 0, width(), height()));
+	}
+	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip);
+
+	virtual const byte *palette_const() const {
+		return (byte *)_palette;
+	};
+
+	virtual byte *palette() {
+		setDirty();
+		return (byte *)_palette;
+	};
+
+	virtual const Graphics::PixelFormat &getPixelFormat() const;
+
+protected:
+	Graphics::PixelFormat _fake_format;
+	uint16 *_palette;
+	byte *_pixels;
+	uint16 *_buf;
+};
+
+class GLESFakePalette565Texture : public GLESFakePaletteTexture {
+public:
+	GLESFakePalette565Texture();
+	virtual ~GLESFakePalette565Texture();
+};
+
+class GLESFakePalette5551Texture : public GLESFakePaletteTexture {
+public:
+	GLESFakePalette5551Texture();
+	virtual ~GLESFakePalette5551Texture();
+};
+
+#endif
+#endif
diff --git a/backends/graphics3d/android/touchcontrols.cpp b/backends/graphics3d/android/touchcontrols.cpp
new file mode 100644
index 0000000000..fd53e39052
--- /dev/null
+++ b/backends/graphics3d/android/touchcontrols.cpp
@@ -0,0 +1,314 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#if defined(__ANDROID__)
+
+// Allow use of stuff in <time.h>
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+
+//
+// Disable printf override in common/forbidden.h to avoid
+// clashes with log.h from the Android SDK.
+// That header file uses
+//   __attribute__ ((format(printf, 3, 4)))
+// which gets messed up by our override mechanism; this could
+// be avoided by either changing the Android SDK to use the equally
+// legal and valid
+//   __attribute__ ((format(printf, 3, 4)))
+// or by refining our printf override to use a varadic macro
+// (which then wouldn't be portable, though).
+// Anyway, for now we just disable the printf override globally
+// for the Android port
+#define FORBIDDEN_SYMBOL_EXCEPTION_printf
+
+#include "common/fs.h"
+#include "common/stream.h"
+#include "common/archive.h"
+#include "image/tga.h"
+
+#include "backends/graphics3d/android/texture.h"
+#include "backends/graphics3d/android/touchcontrols.h"
+#include "backends/platform/android/android.h"
+
+// action type
+enum {
+	JACTION_DOWN = 0,
+	JACTION_UP = 1,
+	JACTION_MULTIPLE = 2,
+	JACTION_POINTER_DOWN = 5,
+	JACTION_POINTER_UP = 6
+};
+
+static Common::Rect clipFor(const Common::KeyCode &cs) {
+	switch (cs) {
+	case Common::KEYCODE_UP:
+	case Common::KEYCODE_PAGEUP:
+		return Common::Rect(0, 0, 128, 128);
+	case Common::KEYCODE_RIGHT:
+		return Common::Rect(128, 0, 256, 128);
+	case Common::KEYCODE_DOWN:
+	case Common::KEYCODE_PAGEDOWN:
+		return Common::Rect(256, 0, 384, 128);
+	case Common::KEYCODE_LEFT:
+		return Common::Rect(384, 0, 512, 128);
+	case Common::KEYCODE_i:
+		return Common::Rect(0, 128, 128, 256);
+	case Common::KEYCODE_p:
+		return Common::Rect(128, 128, 256, 256);
+	case Common::KEYCODE_u:
+		return Common::Rect(256, 128, 384, 256);
+	case Common::KEYCODE_e:
+	case Common::KEYCODE_l:
+		return Common::Rect(384, 128, 512, 256);
+	default: // unreachable
+		return Common::Rect(0, 0, 1, 1);
+	}
+}
+
+TouchControls::TouchControls() :
+	_arrows_texture(NULL),
+	_joystickPressing(Common::KEYCODE_INVALID),
+	_centerPressing(Common::KEYCODE_INVALID),
+	_rightPressing(Common::KEYCODE_INVALID),
+	_screen_width(0),
+	_screen_height(0) {
+
+	for (int p = 0; p < kNumPointers; ++p) {
+		Pointer &pp = _pointers[p];
+		pp.currentX = pp.currentY = pp.startX = pp.startY = 0;
+		pp.active = false;
+		pp.function = kTouchAreaNone;
+	}
+
+	for (int i = 0; i < 4; ++i)
+		_activePointers[i] = -1;
+}
+
+TouchControls::~TouchControls() {
+	if (_arrows_texture) {
+		delete _arrows_texture;
+		_arrows_texture = 0;
+	}
+}
+
+uint16 TouchControls::getTouchArea(int x, int y) {
+	float xPercent = float(x) / _screen_width;
+
+	if (xPercent < 0.3)
+		return kTouchAreaJoystick;
+	else if (xPercent < 0.8)
+		return kTouchAreaCenter;
+	else
+		return kTouchAreaRight;
+}
+
+static Common::KeyCode determineKey(int dX, int dY, Common::KeyCode def = Common::KEYCODE_INVALID) {
+	if (dX * dX + dY * dY < 50 * 50)
+		return def;
+
+	if (dY > abs(dX))
+		return Common::KEYCODE_DOWN;
+	if (dX > abs(dY))
+		return Common::KEYCODE_RIGHT;
+	if (-dY > abs(dX))
+		return Common::KEYCODE_UP;
+	if (-dX > abs(dY))
+		return Common::KEYCODE_LEFT;
+
+	return Common::KEYCODE_INVALID;
+}
+
+static GLES8888Texture *loadBuiltinTexture(const char *filename) {
+	Common::ArchiveMemberPtr member = SearchMan.getMember(filename);
+	Common::SeekableReadStream *str = member->createReadStream();
+	Image::TGADecoder dec;
+	dec.loadStream(*str);
+	const void *pixels = dec.getSurface()->getPixels();
+
+	GLES8888Texture *ret = new GLES8888Texture();
+	uint16 w = dec.getSurface()->w;
+	uint16 h = dec.getSurface()->h;
+	uint16 pitch = dec.getSurface()->pitch;
+	ret->allocBuffer(w, h);
+	ret->updateBuffer(0, 0, w, h, pixels, pitch);
+
+	delete str;
+	return ret;
+}
+
+void TouchControls::init(int width, int height) {
+	_arrows_texture = loadBuiltinTexture("arrows.tga");
+	_screen_width = width;
+	_screen_height = height;
+}
+
+const uint _numRightKeycodes = 4;
+const Common::KeyCode _rightKeycodes[] = { Common::KEYCODE_i, Common::KEYCODE_p, Common::KEYCODE_u, Common::KEYCODE_e };
+
+void TouchControls::draw() {
+	if (_joystickPressing != Common::KEYCODE_INVALID) {
+		Common::Rect clip = clipFor(_joystickPressing);
+		_arrows_texture->drawTexture(2 * _screen_width / 10, _screen_height / 2, 64, 64, clip);
+	}
+
+	if (_centerPressing != Common::KEYCODE_INVALID) {
+		Common::Rect clip = clipFor(_centerPressing);
+		_arrows_texture->drawTexture(_screen_width / 2, _screen_height / 2, 64, 64, clip);
+	}
+
+	if (_rightPressing != Common::KEYCODE_INVALID) {
+		Common::Rect clip = clipFor(_rightPressing);
+		_arrows_texture->drawTexture( 8 * _screen_width / 10, _screen_height / 2, 64, 64, clip);
+	}
+}
+
+void TouchControls::update(int ptr, int action, int x, int y) {
+	if (ptr > kNumPointers)
+		return;
+
+	TouchArea touchArea = (TouchArea) getTouchArea(x, y);
+
+	switch (action) {
+	case JACTION_POINTER_DOWN:
+	case JACTION_DOWN:
+		if (touchArea > kTouchAreaNone && -1 == pointerFor(touchArea)) {
+			pointerFor(touchArea) = ptr;
+			_pointers[ptr].active = true;
+			_pointers[ptr].function = touchArea;
+			_pointers[ptr].startX = _pointers[ptr].currentX = x;
+			_pointers[ptr].startY = _pointers[ptr].currentY = y;
+			// fall through to move case to initialize _{joy,center,right}Pressing
+		} else {
+			return;
+		}
+
+	case JACTION_MULTIPLE: {
+		_pointers[ptr].currentX = x;
+		_pointers[ptr].currentY = y;
+		int dX = x - _pointers[ptr].startX;
+		int dY = y - _pointers[ptr].startY;
+
+		switch (_pointers[ptr].function) {
+		case kTouchAreaJoystick: {
+			Common::KeyCode newPressing = determineKey(dX, dY);
+			if (newPressing != _joystickPressing) {
+				keyUp(_joystickPressing);
+				keyDown(newPressing);
+				_joystickPressing = newPressing;
+			} else if(abs(dY) > 150) {
+			   keyDown(Common::KEYCODE_LSHIFT);
+			} else if(abs(dY) <= 150){
+			   keyUp(Common::KEYCODE_LSHIFT);
+			}
+			return;
+		}
+
+		case kTouchAreaCenter:
+			_centerPressing = determineKey(dX, dY, Common::KEYCODE_RETURN);
+			return;
+
+		case kTouchAreaRight:
+			_rightPressing = determineKey(dX, dY, Common::KEYCODE_i);
+			switch (_rightPressing) {
+			case Common::KEYCODE_LEFT:
+			case Common::KEYCODE_RIGHT:
+				_rightPressing = _rightKeycodes[abs(dX / 100) % _numRightKeycodes];
+				break;
+
+			case Common::KEYCODE_UP:
+				_rightPressing = Common::KEYCODE_PAGEUP;
+				break;
+
+			case Common::KEYCODE_DOWN:
+				_rightPressing = Common::KEYCODE_PAGEDOWN;
+				break;
+
+			default:
+				break;
+			}
+
+		default:
+			return;
+		}
+		return;
+	}
+
+	case JACTION_UP:
+	case JACTION_POINTER_UP: {
+		switch (_pointers[ptr].function) {
+		case kTouchAreaJoystick:
+			pointerFor(kTouchAreaJoystick) = -1;
+			if (_joystickPressing != Common::KEYCODE_INVALID) {
+				keyUp(_joystickPressing);
+				_joystickPressing = Common::KEYCODE_INVALID;
+				keyUp(Common::KEYCODE_LSHIFT);
+			}
+			break;
+
+		case kTouchAreaCenter:
+			pointerFor(kTouchAreaCenter) = -1;
+			keyPress(_centerPressing);
+			_centerPressing = Common::KEYCODE_INVALID;
+			break;
+
+		case kTouchAreaRight:
+			pointerFor(kTouchAreaRight) = -1;
+			keyPress(_rightPressing);
+			_rightPressing = Common::KEYCODE_INVALID;
+			break;
+
+		case kTouchAreaNone:
+		default:
+			break;
+		}
+		_pointers[ptr].active = false;
+		_pointers[ptr].function = kTouchAreaNone;
+		return;
+	}
+	}
+}
+
+int &TouchControls::pointerFor(TouchArea ta) {
+	return _activePointers[ta - kTouchAreaNone];
+}
+
+void TouchControls::keyDown(Common::KeyCode kc) {
+	Common::Event ev;
+	ev.type = Common::EVENT_KEYDOWN;
+	ev.kbd.keycode = kc;
+	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
+}
+
+void TouchControls::keyUp(Common::KeyCode kc) {
+	Common::Event ev;
+	ev.type = Common::EVENT_KEYUP;
+	ev.kbd.keycode = kc;
+	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
+}
+
+void TouchControls::keyPress(Common::KeyCode kc) {
+	Common::Event ev;
+	ev.kbd.keycode = kc;
+	dynamic_cast<OSystem_Android *>(g_system)->pushKeyPressEvent(ev);
+}
+
+#endif
diff --git a/backends/graphics3d/android/touchcontrols.h b/backends/graphics3d/android/touchcontrols.h
new file mode 100644
index 0000000000..83716488ed
--- /dev/null
+++ b/backends/graphics3d/android/touchcontrols.h
@@ -0,0 +1,73 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ANDROID_TOUCHCONTROLS_H_
+#define ANDROID_TOUCHCONTROLS_H_
+
+#if defined(__ANDROID__)
+
+#include "common/events.h"
+
+#include "backends/graphics3d/android/texture.h"
+
+class TouchControls {
+public:
+	TouchControls();
+	~TouchControls();
+
+	void init(int width, int height);
+	void draw();
+	void update(int ptr, int action, int x, int y);
+
+private:
+	int _screen_width, _screen_height;
+
+	enum TouchArea{
+		kTouchAreaJoystick = 0xffff,
+		kTouchAreaCenter = 0xfffe,
+		kTouchAreaRight = 0xfffd,
+		kTouchAreaNone = 0xfffc,
+	};
+
+	uint16 getTouchArea(int x, int y);
+
+	struct Pointer {
+		uint16 startX, startY;
+		uint16 currentX, currentY;
+		TouchArea function;
+		bool active;
+	};
+
+	enum { kNumPointers = 5 };
+	Pointer _pointers[kNumPointers];
+	int _activePointers[4];
+	Common::KeyCode _joystickPressing, _centerPressing, _rightPressing;
+	int &pointerFor(TouchArea ta);
+	GLESTexture *_arrows_texture;
+	void keyDown(Common::KeyCode kc);
+	void keyUp(Common::KeyCode kc);
+	void keyPress(Common::KeyCode kc);
+};
+
+#endif
+
+#endif
diff --git a/backends/module.mk b/backends/module.mk
index e61c1d0b93..6b99e37b33 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -232,6 +232,10 @@ endif
 
 ifeq ($(BACKEND),android)
 MODULE_OBJS += \
+	graphics/android/android-graphics.o \
+	graphics3d/android/android-graphics3d.o \
+	graphics3d/android/texture.o \
+	graphics3d/android/touchcontrols.o \
 	mutex/pthread/pthread-mutex.o
 endif
 
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index 0d3e7c9f4a..34e492409b 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -54,6 +54,7 @@
 #include "common/mutex.h"
 #include "common/events.h"
 #include "common/config-manager.h"
+#include "graphics/cursorman.h"
 
 #include "backends/audiocd/default/default-audiocd.h"
 #include "backends/events/default/default-events.h"
@@ -65,9 +66,10 @@
 #include "backends/keymapper/keymapper-defaults.h"
 #include "backends/keymapper/standard-actions.h"
 
+#include "backends/graphics/android/android-graphics.h"
+#include "backends/graphics3d/android/android-graphics3d.h"
 #include "backends/platform/android/jni-android.h"
 #include "backends/platform/android/android.h"
-#include "backends/platform/android/graphics.h"
 
 const char *android_log_tag = "ScummVM";
 
@@ -88,6 +90,37 @@ extern "C" {
 	}
 }
 
+#ifdef ANDROID_DEBUG_GL
+static const char *getGlErrStr(GLenum error) {
+	switch (error) {
+	case GL_INVALID_ENUM:
+		return "GL_INVALID_ENUM";
+	case GL_INVALID_VALUE:
+		return "GL_INVALID_VALUE";
+	case GL_INVALID_OPERATION:
+		return "GL_INVALID_OPERATION";
+	case GL_STACK_OVERFLOW:
+		return "GL_STACK_OVERFLOW";
+	case GL_STACK_UNDERFLOW:
+		return "GL_STACK_UNDERFLOW";
+	case GL_OUT_OF_MEMORY:
+		return "GL_OUT_OF_MEMORY";
+	}
+
+	static char buf[40];
+	snprintf(buf, sizeof(buf), "(Unknown GL error code 0x%x)", error);
+
+	return buf;
+}
+
+void checkGlError(const char *expr, const char *file, int line) {
+	GLenum error = glGetError();
+
+	if (error != GL_NO_ERROR)
+		LOGE("GL ERROR: %s on %s (%s:%d)", getGlErrStr(error), expr, file, line);
+}
+#endif
+
 OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) :
 	_audio_sample_rate(audio_sample_rate),
 	_audio_buffer_size(audio_buffer_size),
@@ -657,4 +690,70 @@ Common::String OSystem_Android::getSystemProperty(const char *name) const {
 	return Common::String(value, len);
 }
 
+bool OSystem_Android::setGraphicsMode(int mode, uint flags) {
+	bool render3d = flags & OSystem::kGfxModeRender3d;
+
+	// Very hacky way to set up the old graphics manager state, in case we
+	// switch from SDL->OpenGL or OpenGL->SDL.
+	//
+	// This is a probably temporary workaround to fix bugs like #5799
+	// "SDL/OpenGL: Crash when switching renderer backend".
+	//
+	// It's also used to restore state from 3D to 2D GFX manager
+	AndroidCommonGraphics *androidGraphicsManager = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager);
+	AndroidCommonGraphics::State gfxManagerState = androidGraphicsManager->getState();
+	bool supports3D = _graphicsManager->hasFeature(kFeatureOpenGLForGame);
+
+	bool switchedManager = false;
+
+	// If the new mode and the current mode are not from the same graphics
+	// manager, delete and create the new mode graphics manager
+	if (render3d && !supports3D) {
+		debug(1, "switching to 3D graphics");
+		delete _graphicsManager;
+		AndroidGraphics3dManager *manager = new AndroidGraphics3dManager();
+		_graphicsManager = manager;
+		androidGraphicsManager = manager;
+		switchedManager = true;
+	} else if (!render3d && supports3D) {
+		debug(1, "switching to 2D graphics");
+		delete _graphicsManager;
+		AndroidGraphicsManager *manager = new AndroidGraphicsManager();
+		_graphicsManager = manager;
+		androidGraphicsManager = manager;
+		switchedManager = true;
+	}
+
+	if (switchedManager) {
+		// Setup the graphics mode and size first
+		// This is needed so that we can check the supported pixel formats when
+		// restoring the state.
+		_graphicsManager->beginGFXTransaction();
+		if (!_graphicsManager->setGraphicsMode(mode, flags))
+			return false;
+		_graphicsManager->initSize(gfxManagerState.screenWidth, gfxManagerState.screenHeight);
+		_graphicsManager->endGFXTransaction();
+
+		// This failing will probably have bad consequences...
+		if (!androidGraphicsManager->setState(gfxManagerState)) {
+			return false;
+		}
+
+		// Next setup the cursor again
+		CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
+		CursorMan.popCursor();
+
+		// Next setup cursor palette if needed
+		if (_graphicsManager->getFeatureState(kFeatureCursorPalette)) {
+			CursorMan.pushCursorPalette(0, 0, 0);
+			CursorMan.popCursorPalette();
+		}
+
+		_graphicsManager->beginGFXTransaction();
+		return true;
+	} else {
+		return _graphicsManager->setGraphicsMode(mode, flags);
+	}
+}
+
 #endif
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 91ddfad90e..9ae9e8bdf7 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -57,6 +57,39 @@ extern const char *android_log_tag;
 #define ENTER(fmt, args...) do {  } while (false)
 #endif
 
+#ifdef ANDROID_DEBUG_GL
+extern void checkGlError(const char *expr, const char *file, int line);
+
+#ifdef ANDROID_DEBUG_GL_CALLS
+#define GLCALLLOG(x, before) \
+	do { \
+		if (before) \
+			LOGD("calling '%s' (%s:%d)", x, __FILE__, __LINE__); \
+		else \
+			LOGD("returned from '%s' (%s:%d)", x, __FILE__, __LINE__); \
+	} while (false)
+#else
+#define GLCALLLOG(x, before) do {  } while (false)
+#endif
+
+#define GLCALL(x) \
+	do { \
+		GLCALLLOG(#x, true); \
+		(x); \
+		GLCALLLOG(#x, false); \
+		checkGlError(#x, __FILE__, __LINE__); \
+	} while (false)
+
+#define GLTHREADCHECK \
+	do { \
+		assert(pthread_self() == _main_thread); \
+	} while (false)
+
+#else
+#define GLCALL(x) do { (x); } while (false)
+#define GLTHREADCHECK do {  } while (false)
+#endif
+
 class OSystem_Android : public ModularGraphicsBackend, Common::EventSource {
 private:
 	// passed from the dark side
@@ -94,6 +127,8 @@ public:
 
 public:
 	void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6);
+	void pushEvent(const Common::Event &event);
+	void pushKeyPressEvent(Common::Event &event);
 
 private:
 	Common::Queue<Common::Event> _event_queue;
@@ -114,9 +149,6 @@ private:
 	int _secondPointerId;
 	int _thirdPointerId;
 
-
-	void pushEvent(const Common::Event &event);
-
 public:
 	bool pollEvent(Common::Event &event) override;
 	Common::HardwareInputSet *getHardwareInputSet() override;
@@ -145,6 +177,10 @@ public:
 	bool setTextInClipboard(const Common::U32String &text) override;
 	bool isConnectionLimited() override;
 	Common::String getSystemLanguage() const override;
+
+	bool setGraphicsMode(int mode, uint flags) override;
+
+	void updateEventScale(uint32 w, uint32 h);
 };
 
 #endif
diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index a257895d84..984ef506ee 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -1,6 +1,8 @@
 # Android specific build targets
 PATH_DIST = $(srcdir)/dists/android
 
+DIST_ANDROID_CONTROLS = $(PATH_DIST)/assets/arrows.tga
+
 GRADLE_FILES = $(shell find $(PATH_DIST)/gradle -type f) $(PATH_DIST)/gradlew $(PATH_DIST)/build.gradle
 
 PATH_BUILD = ./android_project
@@ -25,9 +27,13 @@ $(PATH_BUILD_GRADLE): $(GRADLE_FILES) | $(PATH_BUILD)
 	$(ECHO) "android.enableJetifier=true\n" >> $(PATH_BUILD)/gradle.properties
 	$(ECHO) "sdk.dir=$(realpath $(ANDROID_SDK_ROOT))\n" > $(PATH_BUILD)/local.properties
 
-$(PATH_BUILD_ASSETS): $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) | $(PATH_BUILD)
+$(PATH_BUILD_ASSETS): $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_ANDROID_CONTROLS) | $(PATH_BUILD)
 	$(INSTALL) -d $(PATH_BUILD_ASSETS)
-	$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(PATH_BUILD_ASSETS)/
+	$(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(DIST_FILES_NETWORKING) $(DIST_FILES_VKEYBD) $(DIST_FILES_DOCS) $(DIST_ANDROID_CONTROLS) $(PATH_BUILD_ASSETS)/
+ifneq ($(DIST_FILES_SHADERS),)
+	$(INSTALL) -d $(PATH_BUILD_ASSETS)/shaders
+	$(INSTALL) -c -m 644 $(DIST_FILES_SHADERS) $(PATH_BUILD_ASSETS)/shaders
+endif
 
 $(PATH_BUILD_LIBSCUMMVM): libscummvm.so | $(PATH_BUILD)
 	$(INSTALL) -d  $(PATH_BUILD_LIB)
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
index a714082f1f..54924807a8 100644
--- a/backends/platform/android/events.cpp
+++ b/backends/platform/android/events.cpp
@@ -41,8 +41,8 @@
 
 #include <android/input.h>
 
+#include "backends/graphics/android/android-graphics.h"
 #include "backends/platform/android/android.h"
-#include "backends/platform/android/graphics.h"
 #include "backends/platform/android/jni-android.h"
 
 // floating point. use sparingly
@@ -373,6 +373,13 @@ static const Common::KeyCode jkeymap[] = {
 	Common::KEYCODE_PASTE // AKEYCODE_PASTE
 };
 
+void OSystem_Android::updateEventScale(uint32 w, uint32 h) {
+	if ((h != 0) && (w != 0)) {
+	    _eventScaleY = 100 * 480 / h;
+	    _eventScaleX = 100 * 640 / w;
+	}
+}
+
 void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 								int arg4, int arg5, int arg6) {
 	Common::Event e;
@@ -557,7 +564,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 
 			e.type = Common::EVENT_MOUSEMOVE;
 
-			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+			e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 
 			{
 				int16 *c;
@@ -601,7 +608,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 				return;
 			}
 
-			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+			e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 
 			pushEvent(e);
 
@@ -610,7 +617,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 
 	case JE_DOWN:
 //		LOGD("JE_DOWN");
-		_touch_pt_down = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+		_touch_pt_down = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 		_touch_pt_scroll.x = -1;
 		_touch_pt_scroll.y = -1;
 		break;
@@ -648,7 +655,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 		e.type = Common::EVENT_MOUSEMOVE;
 
 		if (_touchpad_mode) {
-			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+			e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 		} else {
 			e.mouse.x = arg1;
 			e.mouse.y = arg2;
@@ -720,7 +727,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 		e.type = Common::EVENT_MOUSEMOVE;
 
 		if (_touchpad_mode) {
-			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+			e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 		} else {
 			e.mouse.x = arg1;
 			e.mouse.y = arg2;
@@ -789,7 +796,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 		e.type = Common::EVENT_MOUSEMOVE;
 
 		if (_touchpad_mode) {
-			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+			e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 		} else {
 			e.mouse.x = arg3;
 			e.mouse.y = arg4;
@@ -880,7 +887,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 					return;
 				}
 
-//				e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+//				e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 //
 //				_event_queue_lock->lock();
 //
@@ -972,7 +979,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 		return;
 
 	case JE_BALL:
-		e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+		e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 
 		switch (arg1) {
 		case AMOTION_EVENT_ACTION_DOWN:
@@ -1129,7 +1136,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 				break;
 			}
 
-			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+			e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 
 			break;
 
@@ -1156,7 +1163,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 		switch (arg1) {
 		// AMOTION_EVENT_ACTION_MOVE is 2 in NDK (https://developer.android.com/ndk/reference/group/input)
 		case AMOTION_EVENT_ACTION_MOVE:
-			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+			e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 			e.type = Common::EVENT_MOUSEMOVE;
 
 			// already multiplied by 100
@@ -1192,7 +1199,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 					break;
 				}
 
-				e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+				e.mouse = dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->getMousePosition();
 
 				break;
 
@@ -1245,15 +1252,15 @@ bool OSystem_Android::pollEvent(Common::Event &event) {
 
 			if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) {
 				// surface changed
-				dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->deinitSurface();
-				dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->initSurface();
+				dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->deinitSurface();
+				dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->initSurface();
 
 				event.type = Common::EVENT_SCREEN_CHANGED;
 
 				return true;
 			} else {
 				// surface lost
-				dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->deinitSurface();
+				dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->deinitSurface();
 			}
 		}
 
@@ -1287,7 +1294,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) {
 
 	if (Common::isMouseEvent(event)) {
 		if (_graphicsManager)
-			return dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->notifyMousePosition(event.mouse);
+			return dynamic_cast<AndroidCommonGraphics *>(_graphicsManager)->notifyMousePosition(event.mouse);
 	}
 
 	return true;
@@ -1299,4 +1306,13 @@ void OSystem_Android::pushEvent(const Common::Event &event) {
 	_event_queue_lock->unlock();
 }
 
+void OSystem_Android::pushKeyPressEvent(Common::Event &event) {
+	_event_queue_lock->lock();
+	event.type = Common::EVENT_KEYDOWN;
+	_event_queue.push(event);
+	event.type = Common::EVENT_KEYUP;
+	_event_queue.push(event);
+	_event_queue_lock->unlock();
+}
+
 #endif
diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk
index 1f7164d0d1..3a6fe8f515 100644
--- a/backends/platform/android/module.mk
+++ b/backends/platform/android/module.mk
@@ -4,7 +4,6 @@ MODULE_OBJS := \
 	jni-android.o \
 	asset-archive.o \
 	android.o \
-	graphics.o \
 	events.o \
 	options.o \
 	snprintf.o
diff --git a/dists/android/assets/arrows.tga b/dists/android/assets/arrows.tga
new file mode 100644
index 0000000000..1e168d31ec
Binary files /dev/null and b/dists/android/assets/arrows.tga differ


Commit: 5248999c9544e5eade8d47dcccbd40023a75939d
    https://github.com/scummvm/scummvm/commit/5248999c9544e5eade8d47dcccbd40023a75939d
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Better debug of which graphic backend is used

Changed paths:
    backends/graphics/android/android-graphics.cpp
    backends/graphics3d/android/android-graphics3d.cpp
    backends/platform/android/android.cpp


diff --git a/backends/graphics/android/android-graphics.cpp b/backends/graphics/android/android-graphics.cpp
index 7b306b9283..4ca106c084 100644
--- a/backends/graphics/android/android-graphics.cpp
+++ b/backends/graphics/android/android-graphics.cpp
@@ -59,7 +59,7 @@ AndroidGraphicsManager::~AndroidGraphicsManager() {
 }
 
 void AndroidGraphicsManager::initSurface() {
-	LOGD("initializing surface");
+	LOGD("initializing 2D surface");
 
 	assert(!JNI::haveSurface());
 	JNI::initSurface();
@@ -78,7 +78,7 @@ void AndroidGraphicsManager::deinitSurface() {
 	if (!JNI::haveSurface())
 		return;
 
-	LOGD("deinitializing surface");
+	LOGD("deinitializing 2D surface");
 
 	notifyContextDestroy();
 
diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 63bd4077d4..91e38d4a29 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -112,7 +112,7 @@ static void logExtensions() {
 
 
 void AndroidGraphics3dManager::initSurface() {
-	LOGD("initializing surface");
+	LOGD("initializing 3D surface");
 
 	assert(!JNI::haveSurface());
 
@@ -149,7 +149,7 @@ void AndroidGraphics3dManager::deinitSurface() {
 	if (!JNI::haveSurface())
 		return;
 
-	LOGD("deinitializing surface");
+	LOGD("deinitializing 3D surface");
 
 	_screenChangeID = JNI::surface_changeid;
 
@@ -339,7 +339,7 @@ void AndroidGraphics3dManager::clearOverlay() {
 }
 
 void AndroidGraphics3dManager::grabOverlay(Graphics::Surface &surface) const {
-	ENTER("%p, %d", buf, pitch);
+	ENTER("%p", &surface);
 
 	GLTHREADCHECK;
 
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index 34e492409b..7b875ee54c 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -708,15 +708,16 @@ bool OSystem_Android::setGraphicsMode(int mode, uint flags) {
 
 	// If the new mode and the current mode are not from the same graphics
 	// manager, delete and create the new mode graphics manager
+	debug(5, "requesting 3D: %d, supporting 3D: %d", render3d, supports3D);
 	if (render3d && !supports3D) {
-		debug(1, "switching to 3D graphics");
+		debug(5, "switching to 3D graphics");
 		delete _graphicsManager;
 		AndroidGraphics3dManager *manager = new AndroidGraphics3dManager();
 		_graphicsManager = manager;
 		androidGraphicsManager = manager;
 		switchedManager = true;
 	} else if (!render3d && supports3D) {
-		debug(1, "switching to 2D graphics");
+		debug(5, "switching to 2D graphics");
 		delete _graphicsManager;
 		AndroidGraphicsManager *manager = new AndroidGraphicsManager();
 		_graphicsManager = manager;


Commit: bb2871cd6362a825c5a0e6d257dcef0ca0197896
    https://github.com/scummvm/scummvm/commit/bb2871cd6362a825c5a0e6d257dcef0ca0197896
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Implement modes completely to allow switching between 3D and 2D

Changed paths:
    backends/platform/android/android.cpp
    backends/platform/android/android.h


diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index 7b875ee54c..954527543f 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -690,6 +690,21 @@ Common::String OSystem_Android::getSystemProperty(const char *name) const {
 	return Common::String(value, len);
 }
 
+const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const {
+	// We only support one mode
+	static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+		{ "default", "Default", 0 },
+		{ 0, 0, 0 },
+	};
+
+	return s_supportedGraphicsModes;
+}
+
+int OSystem_Android::getDefaultGraphicsMode() const {
+	// We only support one mode
+	return 0;
+}
+
 bool OSystem_Android::setGraphicsMode(int mode, uint flags) {
 	bool render3d = flags & OSystem::kGfxModeRender3d;
 
@@ -757,4 +772,9 @@ bool OSystem_Android::setGraphicsMode(int mode, uint flags) {
 	}
 }
 
+int OSystem_Android::getGraphicsMode() const {
+	// We only support one mode
+	return 0;
+}
+
 #endif
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 9ae9e8bdf7..6b0f6998f1 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -178,7 +178,10 @@ public:
 	bool isConnectionLimited() override;
 	Common::String getSystemLanguage() const override;
 
+	const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
+	int getDefaultGraphicsMode() const override;
 	bool setGraphicsMode(int mode, uint flags) override;
+	int getGraphicsMode() const override;
 
 	void updateEventScale(uint32 w, uint32 h);
 };


Commit: 74c12b5e5a6f4b350d1ea18dfe04da949791dab5
    https://github.com/scummvm/scummvm/commit/74c12b5e5a6f4b350d1ea18dfe04da949791dab5
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Use 5551 format for overlay instead of 4444

This allows for more color (but only 1 bit of alpha)

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/android/android-graphics3d.h


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 91e38d4a29..0b49800847 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -71,7 +71,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
 	_use_mouse_palette(false)
 {
 	_game_texture = new GLESFakePalette565Texture();
-	_overlay_texture = new GLES4444Texture();
+	_overlay_texture = new GLES5551Texture();
 	_mouse_texture_palette = new GLESFakePalette5551Texture();
 	_mouse_texture = _mouse_texture_palette;
 
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
index 1ea67f3290..7c3cfe8ea3 100644
--- a/backends/graphics3d/android/android-graphics3d.h
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -163,7 +163,7 @@ private:
 	int _cursorX, _cursorY;
 
 	// Overlay layer
-	GLES4444Texture *_overlay_texture;
+	GLES5551Texture *_overlay_texture;
 	bool _show_overlay;
 
 	// Mouse layer


Commit: 73522075554992fe205bfcc18d96a944ab9b578b
    https://github.com/scummvm/scummvm/commit/73522075554992fe205bfcc18d96a944ab9b578b
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Free frame buffer when it's unused

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 0b49800847..67a94a8796 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -81,6 +81,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
 AndroidGraphics3dManager::~AndroidGraphics3dManager() {
 	deinitSurface();
 
+	delete _frame_buffer;
 	delete _game_texture;
 	delete _overlay_texture;
 	delete _mouse_texture_palette;
@@ -472,6 +473,7 @@ void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
 	_game_texture->allocBuffer(width, height);
 #endif
 #ifdef USE_GLES2
+	delete _frame_buffer;
 	_frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight());
 	_frame_buffer->attach();
 #endif


Commit: 2a444f981e21db6068fdbc30bdb7147fa7ea708a
    https://github.com/scummvm/scummvm/commit/2a444f981e21db6068fdbc30bdb7147fa7ea708a
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Fix indentation

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 67a94a8796..4e3e962cb8 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -177,48 +177,48 @@ void AndroidGraphics3dManager::updateScreen() {
 	if (!JNI::haveSurface())
 		return;
 
-		if (_game_pbuf) {
-			int pitch = _game_texture->width() * _game_texture->getPixelFormat().bytesPerPixel;
-			_game_texture->updateBuffer(0, 0, _game_texture->width(), _game_texture->height(),
-					_game_pbuf.getRawBuffer(), pitch);
-		}
+	if (_game_pbuf) {
+		int pitch = _game_texture->width() * _game_texture->getPixelFormat().bytesPerPixel;
+		_game_texture->updateBuffer(0, 0, _game_texture->width(), _game_texture->height(),
+				_game_pbuf.getRawBuffer(), pitch);
+	}
 
-		if (!_force_redraw &&
-				!_game_texture->dirty() &&
-				!_overlay_texture->dirty() &&
-				!_mouse_texture->dirty())
-			return;
+	if (!_force_redraw &&
+			!_game_texture->dirty() &&
+			!_overlay_texture->dirty() &&
+			!_mouse_texture->dirty())
+		return;
 
-		_force_redraw = false;
+	_force_redraw = false;
 
-		if (_frame_buffer) {
-			_frame_buffer->detach();
-			glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
-		}
+	if (_frame_buffer) {
+		_frame_buffer->detach();
+		glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
+	}
+
+	// clear pointer leftovers in dead areas
+	clearScreen(kClear);
 
-		// clear pointer leftovers in dead areas
-		clearScreen(kClear);
+	_game_texture->drawTextureRect();
+	if (!_show_overlay) {
+		glEnable(GL_BLEND);
+		_touchControls.draw();
+	}
 
-		_game_texture->drawTextureRect();
-		if (!_show_overlay) {
-			glEnable(GL_BLEND);
-			_touchControls.draw();
-		}
+	int cs = _mouse_targetscale;
 
-		int cs = _mouse_targetscale;
+	if (_show_overlay) {
+		// ugly, but the modern theme sets a wacko factor, only god knows why
+		cs = 1;
 
-		if (_show_overlay) {
-			// ugly, but the modern theme sets a wacko factor, only god knows why
-			cs = 1;
+		GLCALL(_overlay_texture->drawTextureRect());
+	}
 
-			GLCALL(_overlay_texture->drawTextureRect());
+	if (_show_mouse && !_mouse_texture->isEmpty()) {
+		const Common::Point &mouse = g_system->getEventManager()->getMousePos();
+		if (_show_overlay) {
+			_mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height());
 		}
-
-		if (_show_mouse && !_mouse_texture->isEmpty()) {
-			const Common::Point &mouse = g_system->getEventManager()->getMousePos();
-			if (_show_overlay) {
-				_mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height());
-			}
 	}
 
 	if (!JNI::swapBuffers())


Commit: 881f48b24d1b3cc22cda558078c07b6a2bc46b7a
    https://github.com/scummvm/scummvm/commit/881f48b24d1b3cc22cda558078c07b6a2bc46b7a
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Set up scissor box when resizing

We enable the scissor test when the overlay is hidden so the box must be
correctly defined

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 4e3e962cb8..52524c9dac 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -729,6 +729,9 @@ Common::List<Graphics::PixelFormat> AndroidGraphics3dManager::getSupportedFormat
 void AndroidGraphics3dManager::updateScreenRect() {
 	Common::Rect rect(0, 0, JNI::egl_surface_width, JNI::egl_surface_height);
 
+	// setup the scissor to the full screen as we enable it when overlay is hidden
+	glScissor(0, 0, JNI::egl_surface_width, JNI::egl_surface_height);
+
 	_overlay_texture->setDrawRect(rect);
 
 	uint16 w = _game_texture->width();


Commit: 9ce3b692c638c8adabe26058c6a4c3297609c9aa
    https://github.com/scummvm/scummvm/commit/9ce3b692c638c8adabe26058c6a4c3297609c9aa
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Reinitialize some state before stopping 3D manager

This avoids breaking the 2D graphics manager

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 52524c9dac..ed8bc1a9d6 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -79,6 +79,13 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
 }
 
 AndroidGraphics3dManager::~AndroidGraphics3dManager() {
+	// Reinitialize OpenGL for other manager
+	glBindBuffer(GL_ARRAY_BUFFER, 0);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+	glBindRenderbuffer(GL_RENDERBUFFER, 0);
+	glUseProgram(0);
+
 	deinitSurface();
 
 	delete _frame_buffer;


Commit: 0988f3d6d899e46dffd507a012c444a6570b8954
    https://github.com/scummvm/scummvm/commit/0988f3d6d899e46dffd507a012c444a6570b8954
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Fix OpenGL debug in 3D backend

Changed paths:
    backends/platform/android/android.h


diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 6b0f6998f1..0759918fb3 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -41,6 +41,8 @@
 
 // toggles start
 //#define ANDROID_DEBUG_ENTER
+//#define ANDROID_DEBUG_GL
+//#define ANDROID_DEBUG_GL_CALLS
 // toggles end
 
 extern const char *android_log_tag;
@@ -82,7 +84,7 @@ extern void checkGlError(const char *expr, const char *file, int line);
 
 #define GLTHREADCHECK \
 	do { \
-		assert(pthread_self() == _main_thread); \
+		assert(dynamic_cast<OSystem_Android *>(g_system)->isRunningInMainThread()); \
 	} while (false)
 
 #else
@@ -184,6 +186,9 @@ public:
 	int getGraphicsMode() const override;
 
 	void updateEventScale(uint32 w, uint32 h);
+#ifdef ANDROID_DEBUG_GL_CALLS
+	bool isRunningInMainThread() { return pthread_self() == _main_thread; }
+#endif
 };
 
 #endif


Commit: f0aef09021376a31bb72acfbe44b6184b4e87a1e
    https://github.com/scummvm/scummvm/commit/f0aef09021376a31bb72acfbe44b6184b4e87a1e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Make sure glDrawArrays succeeds

Changed paths:
    backends/graphics3d/android/texture.cpp


diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
index 3faa689409..43a8e291d0 100644
--- a/backends/graphics3d/android/texture.cpp
+++ b/backends/graphics3d/android/texture.cpp
@@ -191,7 +191,7 @@ void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, co
 	g_box_shader->setUniform("clip", clipV);
 	g_box_shader->setUniform("flipY", !_is_game_texture);
 
-	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+	GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
 
 	clearDirty();
 }


Commit: ebeb731ad73391e2d18cd39c8f176009903f1696
    https://github.com/scummvm/scummvm/commit/ebeb731ad73391e2d18cd39c8f176009903f1696
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Disable depth test as we don't use it in final rendering

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index ed8bc1a9d6..5e6014e933 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -203,6 +203,9 @@ void AndroidGraphics3dManager::updateScreen() {
 		glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
 	}
 
+	// We don't use depth stencil to draw on screen
+	glDisable(GL_DEPTH_TEST);
+
 	// clear pointer leftovers in dead areas
 	clearScreen(kClear);
 


Commit: e4390abd86a5e6f141801a8730f4aadb2ee3a4e1
    https://github.com/scummvm/scummvm/commit/e4390abd86a5e6f141801a8730f4aadb2ee3a4e1
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Introduce back the touch controls for 3D

Changed paths:
  A backends/platform/android/touchcontrols.cpp
  A backends/platform/android/touchcontrols.h
  R backends/graphics3d/android/touchcontrols.cpp
  R backends/graphics3d/android/touchcontrols.h
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/android/android-graphics3d.h
    backends/module.mk
    backends/platform/android/android.h
    backends/platform/android/jni-android.cpp
    backends/platform/android/jni-android.h
    backends/platform/android/module.mk
    backends/platform/android/org/scummvm/scummvm/ScummVM.java
    backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
    backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 5e6014e933..3f83cc6c24 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -76,6 +76,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
 	_mouse_texture = _mouse_texture_palette;
 
 	initSurface();
+	JNI::setTouch3DMode(true);
 }
 
 AndroidGraphics3dManager::~AndroidGraphics3dManager() {
@@ -94,6 +95,7 @@ AndroidGraphics3dManager::~AndroidGraphics3dManager() {
 	delete _mouse_texture_palette;
 	delete _mouse_texture_rgb;
 
+	JNI::setTouch3DMode(false);
 }
 
 static void logExtensions() {
@@ -150,7 +152,7 @@ void AndroidGraphics3dManager::initSurface() {
 	clearScreen(kClearUpdate, 2);
 	updateEventScale();
 
-	_touchControls.init(JNI::egl_surface_width, JNI::egl_surface_height);
+	dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(JNI::egl_surface_width, JNI::egl_surface_height);
 }
 
 void AndroidGraphics3dManager::deinitSurface() {
@@ -212,7 +214,7 @@ void AndroidGraphics3dManager::updateScreen() {
 	_game_texture->drawTextureRect();
 	if (!_show_overlay) {
 		glEnable(GL_BLEND);
-		_touchControls.draw();
+		dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().draw();
 	}
 
 	int cs = _mouse_targetscale;
@@ -316,6 +318,8 @@ bool AndroidGraphics3dManager::getFeatureState(OSystem::Feature f) const {
 void AndroidGraphics3dManager::showOverlay() {
 	ENTER();
 
+	JNI::setTouch3DMode(false);
+
 	_show_overlay = true;
 	_force_redraw = true;
 
@@ -331,6 +335,8 @@ void AndroidGraphics3dManager::hideOverlay() {
 
 	_show_overlay = false;
 
+	JNI::setTouch3DMode(true);
+
 	updateEventScale();
 
 	warpMouse(_game_texture->width() / 2, _game_texture->height() / 2);
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
index 7c3cfe8ea3..07231aa2d9 100644
--- a/backends/graphics3d/android/android-graphics3d.h
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -29,7 +29,6 @@
 #include "backends/graphics/graphics.h"
 #include "backends/graphics/android/android-graphics.h"
 #include "backends/graphics3d/android/texture.h"
-#include "backends/graphics3d/android/touchcontrols.h"
 
 class AndroidGraphics3dManager : public GraphicsManager, public AndroidCommonGraphics {
 public:
@@ -175,8 +174,6 @@ private:
 	int _mouse_targetscale;
 	bool _show_mouse;
 	bool _use_mouse_palette;
-
-	TouchControls _touchControls;
 };
 
 #endif
diff --git a/backends/graphics3d/android/touchcontrols.cpp b/backends/graphics3d/android/touchcontrols.cpp
deleted file mode 100644
index fd53e39052..0000000000
--- a/backends/graphics3d/android/touchcontrols.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/* ResidualVM - A 3D game interpreter
- *
- * ResidualVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#if defined(__ANDROID__)
-
-// Allow use of stuff in <time.h>
-#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
-
-//
-// Disable printf override in common/forbidden.h to avoid
-// clashes with log.h from the Android SDK.
-// That header file uses
-//   __attribute__ ((format(printf, 3, 4)))
-// which gets messed up by our override mechanism; this could
-// be avoided by either changing the Android SDK to use the equally
-// legal and valid
-//   __attribute__ ((format(printf, 3, 4)))
-// or by refining our printf override to use a varadic macro
-// (which then wouldn't be portable, though).
-// Anyway, for now we just disable the printf override globally
-// for the Android port
-#define FORBIDDEN_SYMBOL_EXCEPTION_printf
-
-#include "common/fs.h"
-#include "common/stream.h"
-#include "common/archive.h"
-#include "image/tga.h"
-
-#include "backends/graphics3d/android/texture.h"
-#include "backends/graphics3d/android/touchcontrols.h"
-#include "backends/platform/android/android.h"
-
-// action type
-enum {
-	JACTION_DOWN = 0,
-	JACTION_UP = 1,
-	JACTION_MULTIPLE = 2,
-	JACTION_POINTER_DOWN = 5,
-	JACTION_POINTER_UP = 6
-};
-
-static Common::Rect clipFor(const Common::KeyCode &cs) {
-	switch (cs) {
-	case Common::KEYCODE_UP:
-	case Common::KEYCODE_PAGEUP:
-		return Common::Rect(0, 0, 128, 128);
-	case Common::KEYCODE_RIGHT:
-		return Common::Rect(128, 0, 256, 128);
-	case Common::KEYCODE_DOWN:
-	case Common::KEYCODE_PAGEDOWN:
-		return Common::Rect(256, 0, 384, 128);
-	case Common::KEYCODE_LEFT:
-		return Common::Rect(384, 0, 512, 128);
-	case Common::KEYCODE_i:
-		return Common::Rect(0, 128, 128, 256);
-	case Common::KEYCODE_p:
-		return Common::Rect(128, 128, 256, 256);
-	case Common::KEYCODE_u:
-		return Common::Rect(256, 128, 384, 256);
-	case Common::KEYCODE_e:
-	case Common::KEYCODE_l:
-		return Common::Rect(384, 128, 512, 256);
-	default: // unreachable
-		return Common::Rect(0, 0, 1, 1);
-	}
-}
-
-TouchControls::TouchControls() :
-	_arrows_texture(NULL),
-	_joystickPressing(Common::KEYCODE_INVALID),
-	_centerPressing(Common::KEYCODE_INVALID),
-	_rightPressing(Common::KEYCODE_INVALID),
-	_screen_width(0),
-	_screen_height(0) {
-
-	for (int p = 0; p < kNumPointers; ++p) {
-		Pointer &pp = _pointers[p];
-		pp.currentX = pp.currentY = pp.startX = pp.startY = 0;
-		pp.active = false;
-		pp.function = kTouchAreaNone;
-	}
-
-	for (int i = 0; i < 4; ++i)
-		_activePointers[i] = -1;
-}
-
-TouchControls::~TouchControls() {
-	if (_arrows_texture) {
-		delete _arrows_texture;
-		_arrows_texture = 0;
-	}
-}
-
-uint16 TouchControls::getTouchArea(int x, int y) {
-	float xPercent = float(x) / _screen_width;
-
-	if (xPercent < 0.3)
-		return kTouchAreaJoystick;
-	else if (xPercent < 0.8)
-		return kTouchAreaCenter;
-	else
-		return kTouchAreaRight;
-}
-
-static Common::KeyCode determineKey(int dX, int dY, Common::KeyCode def = Common::KEYCODE_INVALID) {
-	if (dX * dX + dY * dY < 50 * 50)
-		return def;
-
-	if (dY > abs(dX))
-		return Common::KEYCODE_DOWN;
-	if (dX > abs(dY))
-		return Common::KEYCODE_RIGHT;
-	if (-dY > abs(dX))
-		return Common::KEYCODE_UP;
-	if (-dX > abs(dY))
-		return Common::KEYCODE_LEFT;
-
-	return Common::KEYCODE_INVALID;
-}
-
-static GLES8888Texture *loadBuiltinTexture(const char *filename) {
-	Common::ArchiveMemberPtr member = SearchMan.getMember(filename);
-	Common::SeekableReadStream *str = member->createReadStream();
-	Image::TGADecoder dec;
-	dec.loadStream(*str);
-	const void *pixels = dec.getSurface()->getPixels();
-
-	GLES8888Texture *ret = new GLES8888Texture();
-	uint16 w = dec.getSurface()->w;
-	uint16 h = dec.getSurface()->h;
-	uint16 pitch = dec.getSurface()->pitch;
-	ret->allocBuffer(w, h);
-	ret->updateBuffer(0, 0, w, h, pixels, pitch);
-
-	delete str;
-	return ret;
-}
-
-void TouchControls::init(int width, int height) {
-	_arrows_texture = loadBuiltinTexture("arrows.tga");
-	_screen_width = width;
-	_screen_height = height;
-}
-
-const uint _numRightKeycodes = 4;
-const Common::KeyCode _rightKeycodes[] = { Common::KEYCODE_i, Common::KEYCODE_p, Common::KEYCODE_u, Common::KEYCODE_e };
-
-void TouchControls::draw() {
-	if (_joystickPressing != Common::KEYCODE_INVALID) {
-		Common::Rect clip = clipFor(_joystickPressing);
-		_arrows_texture->drawTexture(2 * _screen_width / 10, _screen_height / 2, 64, 64, clip);
-	}
-
-	if (_centerPressing != Common::KEYCODE_INVALID) {
-		Common::Rect clip = clipFor(_centerPressing);
-		_arrows_texture->drawTexture(_screen_width / 2, _screen_height / 2, 64, 64, clip);
-	}
-
-	if (_rightPressing != Common::KEYCODE_INVALID) {
-		Common::Rect clip = clipFor(_rightPressing);
-		_arrows_texture->drawTexture( 8 * _screen_width / 10, _screen_height / 2, 64, 64, clip);
-	}
-}
-
-void TouchControls::update(int ptr, int action, int x, int y) {
-	if (ptr > kNumPointers)
-		return;
-
-	TouchArea touchArea = (TouchArea) getTouchArea(x, y);
-
-	switch (action) {
-	case JACTION_POINTER_DOWN:
-	case JACTION_DOWN:
-		if (touchArea > kTouchAreaNone && -1 == pointerFor(touchArea)) {
-			pointerFor(touchArea) = ptr;
-			_pointers[ptr].active = true;
-			_pointers[ptr].function = touchArea;
-			_pointers[ptr].startX = _pointers[ptr].currentX = x;
-			_pointers[ptr].startY = _pointers[ptr].currentY = y;
-			// fall through to move case to initialize _{joy,center,right}Pressing
-		} else {
-			return;
-		}
-
-	case JACTION_MULTIPLE: {
-		_pointers[ptr].currentX = x;
-		_pointers[ptr].currentY = y;
-		int dX = x - _pointers[ptr].startX;
-		int dY = y - _pointers[ptr].startY;
-
-		switch (_pointers[ptr].function) {
-		case kTouchAreaJoystick: {
-			Common::KeyCode newPressing = determineKey(dX, dY);
-			if (newPressing != _joystickPressing) {
-				keyUp(_joystickPressing);
-				keyDown(newPressing);
-				_joystickPressing = newPressing;
-			} else if(abs(dY) > 150) {
-			   keyDown(Common::KEYCODE_LSHIFT);
-			} else if(abs(dY) <= 150){
-			   keyUp(Common::KEYCODE_LSHIFT);
-			}
-			return;
-		}
-
-		case kTouchAreaCenter:
-			_centerPressing = determineKey(dX, dY, Common::KEYCODE_RETURN);
-			return;
-
-		case kTouchAreaRight:
-			_rightPressing = determineKey(dX, dY, Common::KEYCODE_i);
-			switch (_rightPressing) {
-			case Common::KEYCODE_LEFT:
-			case Common::KEYCODE_RIGHT:
-				_rightPressing = _rightKeycodes[abs(dX / 100) % _numRightKeycodes];
-				break;
-
-			case Common::KEYCODE_UP:
-				_rightPressing = Common::KEYCODE_PAGEUP;
-				break;
-
-			case Common::KEYCODE_DOWN:
-				_rightPressing = Common::KEYCODE_PAGEDOWN;
-				break;
-
-			default:
-				break;
-			}
-
-		default:
-			return;
-		}
-		return;
-	}
-
-	case JACTION_UP:
-	case JACTION_POINTER_UP: {
-		switch (_pointers[ptr].function) {
-		case kTouchAreaJoystick:
-			pointerFor(kTouchAreaJoystick) = -1;
-			if (_joystickPressing != Common::KEYCODE_INVALID) {
-				keyUp(_joystickPressing);
-				_joystickPressing = Common::KEYCODE_INVALID;
-				keyUp(Common::KEYCODE_LSHIFT);
-			}
-			break;
-
-		case kTouchAreaCenter:
-			pointerFor(kTouchAreaCenter) = -1;
-			keyPress(_centerPressing);
-			_centerPressing = Common::KEYCODE_INVALID;
-			break;
-
-		case kTouchAreaRight:
-			pointerFor(kTouchAreaRight) = -1;
-			keyPress(_rightPressing);
-			_rightPressing = Common::KEYCODE_INVALID;
-			break;
-
-		case kTouchAreaNone:
-		default:
-			break;
-		}
-		_pointers[ptr].active = false;
-		_pointers[ptr].function = kTouchAreaNone;
-		return;
-	}
-	}
-}
-
-int &TouchControls::pointerFor(TouchArea ta) {
-	return _activePointers[ta - kTouchAreaNone];
-}
-
-void TouchControls::keyDown(Common::KeyCode kc) {
-	Common::Event ev;
-	ev.type = Common::EVENT_KEYDOWN;
-	ev.kbd.keycode = kc;
-	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
-}
-
-void TouchControls::keyUp(Common::KeyCode kc) {
-	Common::Event ev;
-	ev.type = Common::EVENT_KEYUP;
-	ev.kbd.keycode = kc;
-	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
-}
-
-void TouchControls::keyPress(Common::KeyCode kc) {
-	Common::Event ev;
-	ev.kbd.keycode = kc;
-	dynamic_cast<OSystem_Android *>(g_system)->pushKeyPressEvent(ev);
-}
-
-#endif
diff --git a/backends/module.mk b/backends/module.mk
index 6b99e37b33..78da0c6a0c 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -235,7 +235,6 @@ MODULE_OBJS += \
 	graphics/android/android-graphics.o \
 	graphics3d/android/android-graphics3d.o \
 	graphics3d/android/texture.o \
-	graphics3d/android/touchcontrols.o \
 	mutex/pthread/pthread-mutex.o
 endif
 
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 0759918fb3..59fd05a325 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -35,6 +35,8 @@
 #include "backends/plugins/posix/posix-provider.h"
 #include "backends/fs/posix/posix-fs-factory.h"
 
+#include "backends/platform/android/touchcontrols.h"
+
 #include <pthread.h>
 
 #include <android/log.h>
@@ -132,6 +134,8 @@ public:
 	void pushEvent(const Common::Event &event);
 	void pushKeyPressEvent(Common::Event &event);
 
+	TouchControls &getTouchControls() { return _touchControls; }
+
 private:
 	Common::Queue<Common::Event> _event_queue;
 	Common::Event _queuedEvent;
@@ -151,6 +155,8 @@ private:
 	int _secondPointerId;
 	int _thirdPointerId;
 
+	TouchControls _touchControls;
+
 public:
 	bool pollEvent(Common::Event &event) override;
 	Common::HardwareInputSet *getHardwareInputSet() override;
diff --git a/backends/platform/android/jni-android.cpp b/backends/platform/android/jni-android.cpp
index 33ae214ade..fa846cc0d2 100644
--- a/backends/platform/android/jni-android.cpp
+++ b/backends/platform/android/jni-android.cpp
@@ -84,6 +84,7 @@ jmethodID JNI::_MID_isConnectionLimited = 0;
 jmethodID JNI::_MID_setWindowCaption = 0;
 jmethodID JNI::_MID_showVirtualKeyboard = 0;
 jmethodID JNI::_MID_showKeyboardControl = 0;
+jmethodID JNI::_MID_setTouch3DMode = 0;
 jmethodID JNI::_MID_showSAFRevokePermsControl = 0;
 jmethodID JNI::_MID_getSysArchives = 0;
 jmethodID JNI::_MID_getAllStorageLocations = 0;
@@ -118,6 +119,8 @@ const JNINativeMethod JNI::_natives[] = {
 		(void *)JNI::main },
 	{ "pushEvent", "(IIIIIII)V",
 		(void *)JNI::pushEvent },
+	{ "updateTouch", "(IIII)V",
+		(void *)JNI::updateTouch },
 	{ "setPause", "(Z)V",
 		(void *)JNI::setPause },
 	{ "getNativeVersionInfo", "()Ljava/lang/String;",
@@ -386,6 +389,19 @@ void JNI::showKeyboardControl(bool enable) {
 	}
 }
 
+void JNI::setTouch3DMode(bool touch3DMode) {
+	JNIEnv *env = JNI::getEnv();
+
+	env->CallVoidMethod(_jobj, _MID_setTouch3DMode, touch3DMode);
+
+	if (env->ExceptionCheck()) {
+		LOGE("Error trying to show virtual keyboard control");
+
+		env->ExceptionDescribe();
+		env->ExceptionClear();
+	}
+}
+
 void JNI::showSAFRevokePermsControl(bool enable) {
 #ifndef BACKEND_ANDROID3D
 	JNIEnv *env = JNI::getEnv();
@@ -571,6 +587,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager,
 	FIND_METHOD(, isConnectionLimited, "()Z");
 	FIND_METHOD(, showVirtualKeyboard, "(Z)V");
 	FIND_METHOD(, showKeyboardControl, "(Z)V");
+	FIND_METHOD(, setTouch3DMode, "(Z)V");
 	FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;");
 	FIND_METHOD(, getAllStorageLocations, "()[Ljava/lang/String;");
 	FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;");
@@ -713,6 +730,18 @@ void JNI::pushEvent(JNIEnv *env, jobject self, int type, int arg1, int arg2,
 	_system->pushEvent(type, arg1, arg2, arg3, arg4, arg5, arg6);
 }
 
+void JNI::updateTouch(JNIEnv *env, jobject self, int action, int ptr, int x, int y) {
+	// drop events until we're ready and after we quit
+	if (!_ready_for_events) {
+		LOGW("dropping event");
+		return;
+	}
+
+	assert(_system);
+
+	_system->getTouchControls().update((TouchControls::Action) action, ptr, x, y);
+}
+
 void JNI::setPause(JNIEnv *env, jobject self, jboolean value) {
 	if (!_system)
 		return;
diff --git a/backends/platform/android/jni-android.h b/backends/platform/android/jni-android.h
index 81af274976..547af26cdc 100644
--- a/backends/platform/android/jni-android.h
+++ b/backends/platform/android/jni-android.h
@@ -68,6 +68,7 @@ public:
 	static bool isConnectionLimited();
 	static void showVirtualKeyboard(bool enable);
 	static void showKeyboardControl(bool enable);
+	static void setTouch3DMode(bool touch3DMode);
 	static void showSAFRevokePermsControl(bool enable);
 	static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority);
 
@@ -114,6 +115,7 @@ private:
 	static jmethodID _MID_setWindowCaption;
 	static jmethodID _MID_showVirtualKeyboard;
 	static jmethodID _MID_showKeyboardControl;
+	static jmethodID _MID_setTouch3DMode;
 	static jmethodID _MID_showSAFRevokePermsControl;
 	static jmethodID _MID_getSysArchives;
 	static jmethodID _MID_getAllStorageLocations;
@@ -149,6 +151,7 @@ private:
 
 	static void pushEvent(JNIEnv *env, jobject self, int type, int arg1,
 							int arg2, int arg3, int arg4, int arg5, int arg6);
+	static void updateTouch(JNIEnv *env, jobject self, int action, int ptr, int x, int y);
 	static void setPause(JNIEnv *env, jobject self, jboolean value);
 
 	static jstring getNativeVersionInfo(JNIEnv *env, jobject self);
diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk
index 3a6fe8f515..8da89718f7 100644
--- a/backends/platform/android/module.mk
+++ b/backends/platform/android/module.mk
@@ -6,7 +6,8 @@ MODULE_OBJS := \
 	android.o \
 	events.o \
 	options.o \
-	snprintf.o
+	snprintf.o \
+	touchcontrols.o
 
 # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
 MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
index 77cdc04da6..e875886abf 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java
@@ -54,6 +54,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
 	// Feed an event to ScummVM.  Safe to call from other threads.
 	final public native void pushEvent(int type, int arg1, int arg2, int arg3,
 										int arg4, int arg5, int arg6);
+	// Update the 3D touch controls
+	final public native void updateTouch(int action, int ptr, int x, int y);
 
 	final public native String getNativeVersionInfo();
 
@@ -68,6 +70,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
 	abstract protected void setWindowCaption(String caption);
 	abstract protected void showVirtualKeyboard(boolean enable);
 	abstract protected void showKeyboardControl(boolean enable);
+	abstract protected void setTouch3DMode(boolean touch3DMode);
 	abstract protected void showSAFRevokePermsControl(boolean enable);
 	abstract protected String[] getSysArchives();
 	abstract protected String[] getAllStorageLocations();
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index b472540ac8..9902dd5059 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -699,6 +699,15 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 			});
 		}
 
+		@Override
+		protected void setTouch3DMode(final boolean touch3DMode) {
+			runOnUiThread(new Runnable() {
+				public void run() {
+					_events.setTouch3DMode(touch3DMode);
+				}
+			});
+		}
+
 		@Override
 		protected void showSAFRevokePermsControl(final boolean enable) {
 			runOnUiThread(new Runnable() {
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java
index 455580a87a..76b3e8e2fb 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java
@@ -50,6 +50,11 @@ public class ScummVMEventsBase implements
 	public static final int JE_QUIT = 0x1000;
 	public static final int JE_MENU = 0x1001;
 
+	public static final int JACTION_DOWN = 0;
+	public static final int JACTION_MOVE = 1;
+	public static final int JACTION_UP = 2;
+	public static final int JACTION_CANCEL = 3;
+
 	final protected Context _context;
 	final protected ScummVM _scummvm;
 	final protected GestureDetector _gd;
@@ -57,6 +62,8 @@ public class ScummVMEventsBase implements
 	final protected MouseHelper _mouseHelper;
 	final protected MultitouchHelper _multitouchHelper;
 
+	protected boolean _touch3DMode;
+
 	// Custom handler code (to avoid mem leaks, see warning "This Handler Class Should Be Static Or Leaks Might Occur”) based on:
 	// https://stackoverflow.com/a/27826094
 	public static class ScummVMEventHandler extends Handler {
@@ -135,6 +142,13 @@ public class ScummVMEventsBase implements
 		}
 	}
 
+	final public void setTouch3DMode(boolean touch3DMode) {
+		if (_touch3DMode != touch3DMode && !touch3DMode) {
+			_scummvm.updateTouch(JACTION_CANCEL, 0, 0, 0);
+		}
+		_touch3DMode = touch3DMode;
+	}
+
 	public void clearEventHandler() {
 		_skeyHandler.clear();
 		_multitouchHelper.clearEventHandler();
@@ -459,30 +473,60 @@ public class ScummVMEventsBase implements
 			}
 		}
 
-		// Deal with LINT warning "ScummVMEvents#onTouch should call View#performClick when a click is detected"
-		switch (action) {
-			case MotionEvent.ACTION_UP:
-				v.performClick();
-				break;
-			case MotionEvent.ACTION_DOWN:
-				// fall through
-			default:
-				break;
-		}
+		if (_touch3DMode) {
+			switch (event.getActionMasked()) {
+				case MotionEvent.ACTION_DOWN:
+				case MotionEvent.ACTION_POINTER_DOWN: {
+					int idx = event.getActionIndex();
+					_scummvm.updateTouch(JACTION_DOWN, event.getPointerId(idx), (int)event.getX(idx), (int)event.getY(idx));
+					// fall through
+				}
+				case MotionEvent.ACTION_MOVE:
+					for(int idx = 0; idx < event.getPointerCount(); idx++) {
+						_scummvm.updateTouch(JACTION_MOVE, event.getPointerId(idx), (int)event.getX(idx), (int)event.getY(idx));
+					}
+					break;
+				case MotionEvent.ACTION_UP:
+				case MotionEvent.ACTION_POINTER_UP: {
+					int idx = event.getActionIndex();
+					_scummvm.updateTouch(JACTION_UP, event.getPointerId(idx), (int)event.getX(idx), (int)event.getY(idx));
+					break;
+				}
+				case MotionEvent.ACTION_CANCEL:
+					_scummvm.updateTouch(JACTION_CANCEL, 0, 0, 0);
+					break;
+			}
 
-		// check if the event can be handled as a multitouch event
-		if (_multitouchHelper.handleMotionEvent(event)) {
+			//return _gd.onTouchEvent(event);
 			return true;
-		}
+		} else {
+			// Deal with LINT warning "ScummVMEvents#onTouch should call View#performClick when a click is detected"
+			switch (action) {
+				case MotionEvent.ACTION_UP:
+					v.performClick();
+					break;
+				case MotionEvent.ACTION_DOWN:
+					// fall through
+				default:
+					break;
+			}
+
+			// check if the event can be handled as a multitouch event
+			if (_multitouchHelper.handleMotionEvent(event)) {
+				return true;
+			}
 
-		return _gd.onTouchEvent(event);
+			return _gd.onTouchEvent(event);
+		}
 	}
 
 	// OnGestureListener
 	@Override
 	final public boolean onDown(MotionEvent e) {
 //		Log.d(ScummVM.LOG_TAG, "SCUMMV-EVENTS-BASE - onDOWN MotionEvent");
-		_scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0, 0);
+		if (!_touch3DMode) {
+			_scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0, 0);
+		}
 		return true;
 	}
 
@@ -505,9 +549,10 @@ public class ScummVMEventsBase implements
 	final public boolean onScroll(MotionEvent e1, MotionEvent e2,
 									float distanceX, float distanceY) {
 //		Log.d(ScummVM.LOG_TAG, "onScroll");
-		_scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(),
+		if (!_touch3DMode) {
+			_scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(),
 							(int)e2.getX(), (int)e2.getY(), 0, 0);
-
+		}
 		return true;
 	}
 
@@ -518,9 +563,10 @@ public class ScummVMEventsBase implements
 	@Override
 	final public boolean onSingleTapUp(MotionEvent e) {
 //		Log.d(ScummVM.LOG_TAG, "onSingleTapUp");
-		_scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(),
+		if (!_touch3DMode) {
+			_scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(),
 							(int)(e.getEventTime() - e.getDownTime()), 0, 0, 0);
-
+		}
 		return true;
 	}
 
@@ -545,7 +591,9 @@ public class ScummVMEventsBase implements
 //		} else {
 //			Log.d(ScummVM.LOG_TAG, "onDoubleTapEvent UNKNOWN!!!!");
 //		}
-		_scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(), e.getAction(), 0, 0, 0);
+		if (!_touch3DMode) {
+			_scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(), e.getAction(), 0, 0, 0);
+		}
 		return true;
 	}
 
diff --git a/backends/platform/android/touchcontrols.cpp b/backends/platform/android/touchcontrols.cpp
new file mode 100644
index 0000000000..005679114d
--- /dev/null
+++ b/backends/platform/android/touchcontrols.cpp
@@ -0,0 +1,362 @@
+/* ResidualVM - A 3D game interpreter
+ *
+ * ResidualVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#if defined(__ANDROID__)
+
+// Allow use of stuff in <time.h>
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+
+//
+// Disable printf override in common/forbidden.h to avoid
+// clashes with log.h from the Android SDK.
+// That header file uses
+//   __attribute__ ((format(printf, 3, 4)))
+// which gets messed up by our override mechanism; this could
+// be avoided by either changing the Android SDK to use the equally
+// legal and valid
+//   __attribute__ ((format(printf, 3, 4)))
+// or by refining our printf override to use a varadic macro
+// (which then wouldn't be portable, though).
+// Anyway, for now we just disable the printf override globally
+// for the Android port
+#define FORBIDDEN_SYMBOL_EXCEPTION_printf
+
+#include "common/fs.h"
+#include "common/stream.h"
+#include "common/archive.h"
+#include "image/tga.h"
+
+#include "backends/graphics3d/android/texture.h"
+#include "backends/platform/android/android.h"
+#include "backends/platform/android/touchcontrols.h"
+
+TouchControls::TouchControls() :
+	_arrows_texture(NULL),
+	_screen_width(0),
+	_screen_height(0) {
+}
+
+TouchControls::~TouchControls() {
+	if (_arrows_texture) {
+		delete _arrows_texture;
+		_arrows_texture = 0;
+	}
+}
+
+TouchControls::Function TouchControls::getFunction(int x, int y) {
+	float xPercent = float(x) / _screen_width;
+
+	if (xPercent < 0.3)
+		return kFunctionJoystick;
+	else if (xPercent < 0.8)
+		return kFunctionCenter;
+	else
+		return kFunctionRight;
+}
+
+void TouchControls::touchToJoystickState(int dX, int dY, FunctionState &state) {
+	int sqNorm = dX * dX + dY * dY;
+	if (sqNorm < 50 * 50) {
+		return;
+	}
+
+	if (dY > abs(dX)) {
+		state.main = Common::KEYCODE_DOWN;
+		state.clip = Common::Rect(256, 0, 384, 128);
+	} else if (dX > abs(dY)) {
+		state.main = Common::KEYCODE_RIGHT;
+		state.clip = Common::Rect(128, 0, 256, 128);
+	} else if (-dY > abs(dX)) {
+		state.main = Common::KEYCODE_UP;
+		state.clip = Common::Rect(0, 0, 128, 128);
+	} else if (-dX > abs(dY)) {
+		state.main = Common::KEYCODE_LEFT;
+		state.clip = Common::Rect(384, 0, 512, 128);
+	} else {
+		return;
+	}
+
+	if (sqNorm > 20000) {
+		state.modifier = Common::KEYCODE_LSHIFT;
+	}
+
+}
+
+void TouchControls::touchToCenterState(int dX, int dY, FunctionState &state) {
+	int sqNorm = dX * dX + dY * dY;
+	if (sqNorm < 50 * 50) {
+		state.main = Common::KEYCODE_RETURN;
+	}
+}
+
+void TouchControls::touchToRightState(int dX, int dY, FunctionState &state) {
+	if (dX * dX + dY * dY < 100 * 100)
+		return;
+
+	if (dY > abs(dX)) {
+		// down
+		state.main = Common::KEYCODE_PAGEDOWN;
+		state.clip = Common::Rect(256, 0, 384, 128);
+		return;
+	} else if (-dY > abs(dX)) {
+		// up
+		state.main = Common::KEYCODE_PAGEUP;
+		state.clip = Common::Rect(0, 0, 128, 128);
+		return;
+	}
+
+	static Common::KeyCode keycodes[5] = {
+		Common::KEYCODE_i, Common::KEYCODE_p, // left zone
+		Common::KEYCODE_INVALID, // center
+		Common::KEYCODE_u, Common::KEYCODE_l // right zone
+	};
+
+	static int16 clips[5][4] = {
+		{   0, 128, 128, 256 }, // i
+		{ 128, 128, 256, 256 }, // p
+		{   0,   0,   0,   0 }, // center
+		{ 256, 128, 384, 256 }, // u
+		{ 384, 128, 512, 256 }  // l
+	};
+	static const unsigned int offset = (ARRAYSIZE(keycodes) - 1) / 2;
+
+	int idx = (dX / 100) + offset;
+	if (idx < 0) {
+		idx = 0;
+	}
+	if (idx >= ARRAYSIZE(keycodes)) {
+		idx = ARRAYSIZE(keycodes) - 1;
+	}
+	state.main = keycodes[idx];
+	state.clip = Common::Rect(clips[idx][0], clips[idx][1], clips[idx][2], clips[idx][3]);
+}
+
+TouchControls::FunctionBehavior TouchControls::functionBehaviors[TouchControls::kFunctionMax+1] = {
+	{ touchToJoystickState, false, .2f, .5f },
+	{ touchToCenterState,   true,  .5f, .5f },
+	{ touchToRightState,    true,  .8f, .5f }
+};
+
+static GLES8888Texture *loadBuiltinTexture(const char *filename) {
+	Common::ArchiveMemberPtr member = SearchMan.getMember(filename);
+	Common::SeekableReadStream *str = member->createReadStream();
+	Image::TGADecoder dec;
+	dec.loadStream(*str);
+	const void *pixels = dec.getSurface()->getPixels();
+
+	GLES8888Texture *ret = new GLES8888Texture();
+	uint16 w = dec.getSurface()->w;
+	uint16 h = dec.getSurface()->h;
+	uint16 pitch = dec.getSurface()->pitch;
+	ret->allocBuffer(w, h);
+	ret->updateBuffer(0, 0, w, h, pixels, pitch);
+
+	delete str;
+	return ret;
+}
+
+void TouchControls::init(int width, int height) {
+	_arrows_texture = loadBuiltinTexture("arrows.tga");
+	_screen_width = width;
+	_screen_height = height;
+}
+
+TouchControls::Pointer *TouchControls::getPointerFromId(int ptrId, bool createNotFound) {
+	unsigned int freeEntry = -1;
+	for (unsigned int i = 0; i < kNumPointers; i++) {
+		Pointer &ptr = _pointers[i];
+		if (ptr.active && (ptr.id == ptrId)) {
+			return &ptr;
+		}
+		if (createNotFound && (freeEntry == -1) && !ptr.active) {
+			freeEntry = i;
+		}
+	}
+	// Too much fingers or not found
+	if (freeEntry == -1) {
+		return nullptr;
+	}
+
+	Pointer &ptr = _pointers[freeEntry];
+	ptr.reset();
+	ptr.id = ptrId;
+
+	return &ptr;
+}
+
+TouchControls::Pointer *TouchControls::findPointerFromFunction(Function function) {
+	for (unsigned int i = 0; i < kNumPointers; i++) {
+		Pointer &ptr = _pointers[i];
+		if (ptr.active && (ptr.function == function)) {
+			return &ptr;
+		}
+	}
+	return nullptr;
+}
+
+void TouchControls::draw() {
+	for (unsigned int i = 0; i < kFunctionMax+1; i++) {
+		FunctionState &state = _functionStates[i];
+		FunctionBehavior behavior = functionBehaviors[i];
+
+		if (state.clip.isEmpty()) {
+			continue;
+		}
+		_arrows_texture->drawTexture(_screen_width * behavior.xRatio, _screen_height * behavior.yRatio, 64, 64, state.clip);
+
+	}
+}
+
+void TouchControls::update(Action action, int ptrId, int x, int y) {
+	if (action == JACTION_DOWN) {
+		Pointer *ptr = getPointerFromId(ptrId, true);
+		if (!ptr) {
+			return;
+		}
+
+		TouchControls::Function function = getFunction(x, y);
+		// ptrId is active no matter what
+		ptr->active = true;
+
+		if (findPointerFromFunction(function)) {
+			// Some finger is already using this function: don't do anything
+			return;
+		}
+
+		ptr->startX = ptr->currentX = x;
+		ptr->startY = ptr->currentY = y;
+		ptr->function = function;
+	} else if (action == JACTION_MOVE) {
+		Pointer *ptr = getPointerFromId(ptrId, false);
+		if (!ptr || ptr->function == kFunctionNone) {
+			return;
+		}
+
+		FunctionBehavior &behavior = functionBehaviors[ptr->function];
+
+		ptr->currentX = x;
+		ptr->currentY = y;
+
+		int dX = x - ptr->startX;
+		int dY = y - ptr->startY;
+
+		FunctionState newState;
+		functionBehaviors[ptr->function].touchToState(dX, dY, newState);
+
+		FunctionState &oldState = _functionStates[ptr->function];
+
+		if (!behavior.keyPressOnRelease) {
+			// send key presses continuously
+			// first old remove main key, then update modifier, then press new main key
+			if (oldState.main != newState.main) {
+				keyUp(oldState.main);
+			}
+			if (oldState.modifier != newState.modifier) {
+				keyUp(oldState.modifier);
+				keyDown(newState.modifier);
+			}
+			if (oldState.main != newState.main) {
+				keyDown(newState.main);
+			}
+		}
+		oldState = newState;
+	} else if (action == JACTION_UP) {
+		Pointer *ptr = getPointerFromId(ptrId, false);
+		if (!ptr || ptr->function == kFunctionNone) {
+			return;
+		}
+
+		FunctionBehavior &behavior = functionBehaviors[ptr->function];
+		FunctionState &functionState = _functionStates[ptr->function];
+
+		if (!behavior.keyPressOnRelease) {
+			// We sent key down continously: keyUp everything
+			keyUp(functionState.main);
+			keyUp(functionState.modifier);
+		} else {
+			int dX = x - ptr->startX;
+			int dY = y - ptr->startY;
+
+			FunctionState newState;
+			functionBehaviors[ptr->function].touchToState(dX, dY, newState);
+
+			keyDown(newState.modifier);
+			keyPress(newState.main);
+			keyUp(newState.modifier);
+		}
+
+		functionState.reset();
+		ptr->active = false;
+	} else if (action == JACTION_CANCEL) {
+		for (unsigned int i = 0; i < kNumPointers; i++) {
+			Pointer &ptr = _pointers[i];
+			ptr.reset();
+		}
+
+		for (unsigned int i = 0; i < kFunctionMax+1; i++) {
+			FunctionBehavior &behavior = functionBehaviors[i];
+			FunctionState &functionState = _functionStates[i];
+
+			if (!behavior.keyPressOnRelease) {
+				// We sent key down continously: keyUp everything
+				keyUp(functionState.main);
+				keyUp(functionState.modifier);
+			}
+
+			functionState.reset();
+		}
+	}
+}
+
+void TouchControls::keyDown(Common::KeyCode kc) {
+	if (kc == Common::KEYCODE_INVALID) {
+		return;
+	}
+
+	Common::Event ev;
+	ev.type = Common::EVENT_KEYDOWN;
+	ev.kbd.keycode = kc;
+	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
+}
+
+void TouchControls::keyUp(Common::KeyCode kc) {
+	if (kc == Common::KEYCODE_INVALID) {
+		return;
+	}
+
+	Common::Event ev;
+	ev.type = Common::EVENT_KEYUP;
+	ev.kbd.keycode = kc;
+	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
+}
+
+void TouchControls::keyPress(Common::KeyCode kc) {
+	if (kc == Common::KEYCODE_INVALID) {
+		return;
+	}
+
+	Common::Event ev;
+	ev.kbd.keycode = kc;
+	dynamic_cast<OSystem_Android *>(g_system)->pushKeyPressEvent(ev);
+}
+
+#endif
diff --git a/backends/graphics3d/android/touchcontrols.h b/backends/platform/android/touchcontrols.h
similarity index 50%
rename from backends/graphics3d/android/touchcontrols.h
rename to backends/platform/android/touchcontrols.h
index 83716488ed..980ff0a1d4 100644
--- a/backends/graphics3d/android/touchcontrols.h
+++ b/backends/platform/android/touchcontrols.h
@@ -31,41 +31,80 @@
 
 class TouchControls {
 public:
+	// action type
+	enum Action {
+		JACTION_DOWN = 0,
+		JACTION_MOVE = 1,
+		JACTION_UP = 2,
+		JACTION_CANCEL = 3
+	};
+
 	TouchControls();
 	~TouchControls();
 
 	void init(int width, int height);
 	void draw();
-	void update(int ptr, int action, int x, int y);
+	void update(Action action, int ptr, int x, int y);
 
 private:
 	int _screen_width, _screen_height;
 
-	enum TouchArea{
-		kTouchAreaJoystick = 0xffff,
-		kTouchAreaCenter = 0xfffe,
-		kTouchAreaRight = 0xfffd,
-		kTouchAreaNone = 0xfffc,
+	enum Function {
+		kFunctionNone = -1,
+		kFunctionJoystick = 0,
+		kFunctionCenter = 1,
+		kFunctionRight = 2,
+		kFunctionMax = 2
 	};
-
-	uint16 getTouchArea(int x, int y);
+	Function getFunction(int x, int y);
 
 	struct Pointer {
+		Pointer() : id(-1), startX(-1), startY(-1), currentX(-1), currentY(-1), function(kFunctionNone), active(false) {}
+		void reset() { id = -1; startX = startY = currentX = currentY = -1; function = kFunctionNone; active = false; }
+
+		int id;
 		uint16 startX, startY;
 		uint16 currentX, currentY;
-		TouchArea function;
+		Function function;
 		bool active;
 	};
 
 	enum { kNumPointers = 5 };
 	Pointer _pointers[kNumPointers];
-	int _activePointers[4];
-	Common::KeyCode _joystickPressing, _centerPressing, _rightPressing;
-	int &pointerFor(TouchArea ta);
+
+	Pointer *getPointerFromId(int ptr, bool createNotFound);
+	Pointer *findPointerFromFunction(Function function);
+
+	struct FunctionState {
+		FunctionState() : main(Common::KEYCODE_INVALID), modifier(Common::KEYCODE_INVALID) { }
+		void reset() { main = Common::KEYCODE_INVALID; modifier = Common::KEYCODE_INVALID; clip = Common::Rect(); }
+
+		Common::KeyCode main;
+		Common::KeyCode modifier;
+		Common::Rect clip;
+	};
+
+	FunctionState _functionStates[kFunctionMax + 1];
+
 	GLESTexture *_arrows_texture;
 	void keyDown(Common::KeyCode kc);
 	void keyUp(Common::KeyCode kc);
 	void keyPress(Common::KeyCode kc);
+
+	/* Functions implementations */
+	struct FunctionBehavior {
+		void (*touchToState)(int, int, TouchControls::FunctionState &);
+		bool keyPressOnRelease;
+		float xRatio;
+		float yRatio;
+	};
+	static FunctionBehavior functionBehaviors[TouchControls::kFunctionMax+1];
+
+	static void touchToJoystickState(int dX, int dY, FunctionState &state);
+	static void touchToCenterState(int dX, int dY, FunctionState &state);
+	static void touchToRightState(int dX, int dY, FunctionState &state);
+
+
 };
 
 #endif


Commit: faa8986fc8018d773c8e4bcdbd5dc4526a9ef018
    https://github.com/scummvm/scummvm/commit/faa8986fc8018d773c8e4bcdbd5dc4526a9ef018
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Display the game below the overlay menu

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/android/android-graphics3d.h


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 3f83cc6c24..4a92bc3cc6 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -61,6 +61,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
 	_cursorX(0),
 	_cursorY(0),
 	_overlay_texture(0),
+	_overlay_background(nullptr),
 	_show_overlay(false),
 	_mouse_texture(0),
 	_mouse_texture_palette(0),
@@ -72,6 +73,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
 {
 	_game_texture = new GLESFakePalette565Texture();
 	_overlay_texture = new GLES5551Texture();
+	_overlay_background = new GLES5551Texture();
 	_mouse_texture_palette = new GLESFakePalette5551Texture();
 	_mouse_texture = _mouse_texture_palette;
 
@@ -92,6 +94,7 @@ AndroidGraphics3dManager::~AndroidGraphics3dManager() {
 	delete _frame_buffer;
 	delete _game_texture;
 	delete _overlay_texture;
+	delete _overlay_background;
 	delete _mouse_texture_palette;
 	delete _mouse_texture_rgb;
 
@@ -138,6 +141,11 @@ void AndroidGraphics3dManager::initSurface() {
 	if (_game_texture)
 		_game_texture->reinit();
 
+	// We don't have any content to display: just make sure surface is clean
+	if (_overlay_background) {
+		_overlay_background->release();
+	}
+
 	if (_overlay_texture) {
 		_overlay_texture->reinit();
 		initOverlay();
@@ -170,6 +178,9 @@ void AndroidGraphics3dManager::deinitSurface() {
 	if (_overlay_texture)
 		_overlay_texture->release();
 
+	if (_overlay_background)
+		_overlay_background->release();
+
 	if (_mouse_texture)
 		_mouse_texture->release();
 
@@ -223,6 +234,9 @@ void AndroidGraphics3dManager::updateScreen() {
 		// ugly, but the modern theme sets a wacko factor, only god knows why
 		cs = 1;
 
+		if (_overlay_background && _overlay_background->getTextureName() != 0) {
+			GLCALL(_overlay_background->drawTextureRect());
+		}
 		GLCALL(_overlay_texture->drawTextureRect());
 	}
 
@@ -318,11 +332,34 @@ bool AndroidGraphics3dManager::getFeatureState(OSystem::Feature f) const {
 void AndroidGraphics3dManager::showOverlay() {
 	ENTER();
 
+	if (_show_overlay) {
+		return;
+	}
+
 	JNI::setTouch3DMode(false);
 
 	_show_overlay = true;
 	_force_redraw = true;
 
+	// If there is a game running capture the screen, so that it can be shown "below" the overlay.
+	if (_overlay_background) {
+		_overlay_background->release();
+
+		if (g_engine) {
+			if (_frame_buffer) {
+				_frame_buffer->detach();
+				glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
+			}
+			_overlay_background->allocBuffer(_overlay_texture->width(), _overlay_texture->height());
+			_overlay_background->setDrawRect(0, 0,
+				JNI::egl_surface_width, JNI::egl_surface_height);
+			Graphics::Surface *background = _overlay_background->surface();
+			glReadPixels(0, 0, background->w, background->h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, background->getPixels());
+			if (_frame_buffer)
+				_frame_buffer->attach();
+		}
+	}
+
 	updateEventScale();
 
 	warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2);
@@ -333,8 +370,14 @@ void AndroidGraphics3dManager::showOverlay() {
 void AndroidGraphics3dManager::hideOverlay() {
 	ENTER();
 
+	if (!_show_overlay) {
+		return;
+	}
+
 	_show_overlay = false;
 
+	_overlay_background->release();
+
 	JNI::setTouch3DMode(true);
 
 	updateEventScale();
@@ -750,6 +793,9 @@ void AndroidGraphics3dManager::updateScreenRect() {
 
 	_overlay_texture->setDrawRect(rect);
 
+	// Clear the overlay background so it is not displayed distorted while resizing
+	_overlay_background->release();
+
 	uint16 w = _game_texture->width();
 	uint16 h = _game_texture->height();
 
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
index 07231aa2d9..ab02b6db08 100644
--- a/backends/graphics3d/android/android-graphics3d.h
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -162,6 +162,7 @@ private:
 	int _cursorX, _cursorY;
 
 	// Overlay layer
+	GLES5551Texture *_overlay_background;
 	GLES5551Texture *_overlay_texture;
 	bool _show_overlay;
 


Commit: d4e9c0eca413be9c642ebb98650466534634c229
    https://github.com/scummvm/scummvm/commit/d4e9c0eca413be9c642ebb98650466534634c229
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Always enable blending when drawing all the layers

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 4a92bc3cc6..d754d5680e 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -218,13 +218,14 @@ void AndroidGraphics3dManager::updateScreen() {
 
 	// We don't use depth stencil to draw on screen
 	glDisable(GL_DEPTH_TEST);
+	// We do blend though
+	glEnable(GL_BLEND);
 
 	// clear pointer leftovers in dead areas
 	clearScreen(kClear);
 
 	_game_texture->drawTextureRect();
 	if (!_show_overlay) {
-		glEnable(GL_BLEND);
 		dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().draw();
 	}
 


Commit: 20df3369b494ff7beeaa034f564ea4a4d5cb8f4c
    https://github.com/scummvm/scummvm/commit/20df3369b494ff7beeaa034f564ea4a4d5cb8f4c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Rework 3D screen setup

All the setupScreen functions were useless as there is only one place
where it's called.
_opengl was always true.
_game_pbuf was never initialized.

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/android/android-graphics3d.h


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index d754d5680e..02cd3bef1b 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -51,12 +51,10 @@
 AndroidGraphics3dManager::AndroidGraphics3dManager() :
 	_screenChangeID(0),
 	_graphicsMode(0),
-	_opengl(false),
 	_fullscreen(true),
 	_ar_correction(true),
 	_force_redraw(false),
 	_game_texture(0),
-	_game_pbuf(),
 	_frame_buffer(0),
 	_cursorX(0),
 	_cursorY(0),
@@ -197,12 +195,6 @@ void AndroidGraphics3dManager::updateScreen() {
 	if (!JNI::haveSurface())
 		return;
 
-	if (_game_pbuf) {
-		int pitch = _game_texture->width() * _game_texture->getPixelFormat().bytesPerPixel;
-		_game_texture->updateBuffer(0, 0, _game_texture->width(), _game_texture->height(),
-				_game_pbuf.getRawBuffer(), pitch);
-	}
-
 	if (!_force_redraw &&
 			!_game_texture->dirty() &&
 			!_overlay_texture->dirty() &&
@@ -517,8 +509,13 @@ void AndroidGraphics3dManager::copyRectToScreen(const void *buf, int pitch,
 }
 
 void AndroidGraphics3dManager::initSize(uint width, uint height,
-								const Graphics::PixelFormat *format) {
-	setupScreen(width, height, true, true);
+					const Graphics::PixelFormat *format) {
+	initViewport();
+
+	// resize game texture
+	initSizeIntern(width, height, 0);
+
+	_game_texture->setGameTexture();
 }
 
 void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
@@ -737,32 +734,6 @@ bool AndroidGraphics3dManager::lockMouse(bool lock) {
 	return true;
 }
 
-void AndroidGraphics3dManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) {
-	setupScreen(screenW, screenH, fullscreen, accel3d, true);
-}
-
-void AndroidGraphics3dManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame) {
-	_opengl = accel3d;
-	initViewport();
-
-	if (_opengl) {
-		// resize game texture
-		initSizeIntern(screenW, screenH, 0);
-		if (isGame)
-			_game_texture->setGameTexture();
-		// format is not used by the gfx_opengl driver, use fake format
-		_game_pbuf.set(Graphics::PixelFormat(), 0);
-
-	} else {
-		Graphics::PixelFormat format = GLES565Texture::pixelFormat();
-		initSizeIntern(screenW, screenH, &format);
-		// as there is no support for the texture surface's lock/unlock mechanism in gfx_tinygl/...
-		// do not use _game_texture->surface()->pixels directly
-		_game_pbuf.create(_game_texture->getPixelFormat(),
-				_game_texture->width() * _game_texture->height(), DisposeAfterUse::YES);
-	}
-}
-
 void AndroidGraphics3dManager::clipMouse(Common::Point &p) const {
 	const GLESBaseTexture *tex = getActiveTexture();
 
@@ -892,11 +863,7 @@ void AndroidGraphics3dManager::clearScreen(FixupType type, byte count) {
 	for (byte i = 0; i < count; ++i) {
 		// clear screen
 		GLCALL(glClearColor(0, 0, 0, 1 << 16));
-		if (_opengl) {
-			GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
-		} else {
-			GLCALL(glClear(GL_COLOR_BUFFER_BIT));
-		}
+		GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
 
 		switch (type) {
 		case kClear:
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
index ab02b6db08..23196964cf 100644
--- a/backends/graphics3d/android/android-graphics3d.h
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -102,19 +102,16 @@ public:
 	virtual void setCursorPalette(const byte *colors, uint start, uint num) override;
 
 
-	void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d);
-
-	void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame);
-	void updateScreenRect();
-	const GLESBaseTexture *getActiveTexture() const;
-	void clipMouse(Common::Point &p) const;
-
 #ifdef USE_RGB_COLOR
 	virtual Graphics::PixelFormat getScreenFormat() const override;
 	virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
 #endif
 
 protected:
+	void updateScreenRect();
+	const GLESBaseTexture *getActiveTexture() const;
+	void clipMouse(Common::Point &p) const;
+
 	void setSystemMousePosition(int x, int y) {}
 
 	bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format);
@@ -146,14 +143,12 @@ private:
 private:
 	int _screenChangeID;
 	int _graphicsMode;
-	bool _opengl;
 	bool _fullscreen;
 	bool _ar_correction;
 	bool _force_redraw;
 
 	// Game layer
 	GLESBaseTexture *_game_texture;
-	Graphics::PixelBuffer _game_pbuf;
 	OpenGL::FrameBuffer *_frame_buffer;
 
 	/**


Commit: 7145b3c2f2e7fb5cf5b12fd62e3be3735e18fcd7
    https://github.com/scummvm/scummvm/commit/7145b3c2f2e7fb5cf5b12fd62e3be3735e18fcd7
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Add support for kSupportsArbitraryResolutions in 3D

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 02cd3bef1b..72429bbc3e 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -522,6 +522,12 @@ void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
 								const Graphics::PixelFormat *format) {
 	ENTER("%d, %d, %p", width, height, format);
 
+	bool engineSupportsArbitraryResolutions = !g_engine || g_engine->hasFeature(Engine::kSupportsArbitraryResolutions);
+	if (engineSupportsArbitraryResolutions) {
+		width = JNI::egl_surface_width;
+		height = JNI::egl_surface_height;
+	}
+
 	GLTHREADCHECK;
 
 #ifdef USE_RGB_COLOR


Commit: 2792b474e19d2af8b5b4ee49cb2004aa78118269
    https://github.com/scummvm/scummvm/commit/2792b474e19d2af8b5b4ee49cb2004aa78118269
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Remove superfluous ifdefs

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/android/texture.cpp
    backends/graphics3d/android/texture.h
    backends/platform/android/touchcontrols.cpp
    backends/platform/android/touchcontrols.h


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 72429bbc3e..169e8f6b08 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-#if defined(__ANDROID__)
-
 // Allow use of stuff in <time.h>
 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h
 
@@ -535,11 +533,9 @@ void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
 #else
 	_game_texture->allocBuffer(width, height);
 #endif
-#ifdef USE_GLES2
 	delete _frame_buffer;
 	_frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight());
 	_frame_buffer->attach();
-#endif
 
 	updateScreenRect();
 	updateEventScale();
@@ -969,5 +965,3 @@ bool AndroidGraphics3dManager::setState(const AndroidCommonGraphics::State &stat
 
 		return true;
 }
-
-#endif
diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
index 43a8e291d0..d2b7dcaebe 100644
--- a/backends/graphics3d/android/texture.cpp
+++ b/backends/graphics3d/android/texture.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-#if defined(__ANDROID__)
-
 // Allow use of stuff in <time.h>
 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h
 
@@ -465,5 +463,3 @@ GLESFakePalette5551Texture::GLESFakePalette5551Texture() :
 
 GLESFakePalette5551Texture::~GLESFakePalette5551Texture() {
 }
-
-#endif
diff --git a/backends/graphics3d/android/texture.h b/backends/graphics3d/android/texture.h
index b05711c6b1..e513938337 100644
--- a/backends/graphics3d/android/texture.h
+++ b/backends/graphics3d/android/texture.h
@@ -23,8 +23,6 @@
 #ifndef BACKENDS_GRAPHICS3D_ANDROID_TEXTURE_H
 #define BACKENDS_GRAPHICS3D_ANDROID_TEXTURE_H
 
-#if defined(__ANDROID__)
-
 #define GL_GLEXT_PROTOTYPES
 #include <GLES/gl.h>
 
@@ -309,4 +307,3 @@ public:
 };
 
 #endif
-#endif
diff --git a/backends/platform/android/touchcontrols.cpp b/backends/platform/android/touchcontrols.cpp
index 005679114d..b59e7737d2 100644
--- a/backends/platform/android/touchcontrols.cpp
+++ b/backends/platform/android/touchcontrols.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-#if defined(__ANDROID__)
-
 // Allow use of stuff in <time.h>
 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h
 
@@ -358,5 +356,3 @@ void TouchControls::keyPress(Common::KeyCode kc) {
 	ev.kbd.keycode = kc;
 	dynamic_cast<OSystem_Android *>(g_system)->pushKeyPressEvent(ev);
 }
-
-#endif
diff --git a/backends/platform/android/touchcontrols.h b/backends/platform/android/touchcontrols.h
index 980ff0a1d4..990ecf187a 100644
--- a/backends/platform/android/touchcontrols.h
+++ b/backends/platform/android/touchcontrols.h
@@ -23,8 +23,6 @@
 #ifndef ANDROID_TOUCHCONTROLS_H_
 #define ANDROID_TOUCHCONTROLS_H_
 
-#if defined(__ANDROID__)
-
 #include "common/events.h"
 
 #include "backends/graphics3d/android/texture.h"
@@ -108,5 +106,3 @@ private:
 };
 
 #endif
-
-#endif


Commit: 8a6f74b5a1b6357f7eb55e3f4f3adbedc2238ae1
    https://github.com/scummvm/scummvm/commit/8a6f74b5a1b6357f7eb55e3f4f3adbedc2238ae1
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Remove global variables

Changed paths:
    backends/graphics3d/android/texture.cpp
    backends/graphics3d/android/texture.h


diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
index d2b7dcaebe..6df9aba59a 100644
--- a/backends/graphics3d/android/texture.cpp
+++ b/backends/graphics3d/android/texture.cpp
@@ -51,10 +51,9 @@
 #include "backends/graphics3d/android/texture.h"
 
 // Supported GL extensions
-static bool npot_supported = false;
-
-OpenGL::ShaderGL * g_box_shader;
-GLuint g_verticesVBO;
+bool GLESBaseTexture::_npot_supported = false;
+OpenGL::ShaderGL *GLESBaseTexture::_box_shader = nullptr;
+GLuint GLESBaseTexture::_verticesVBO = 0;
 
 template<class T>
 static T nextHigher2(T k) {
@@ -68,7 +67,7 @@ static T nextHigher2(T k) {
 	return k + 1;
 }
 
-const GLfloat vertices[] = {
+static const GLfloat vertices[] = {
 	0.0, 0.0,
 	1.0, 0.0,
 	0.0, 1.0,
@@ -76,13 +75,16 @@ const GLfloat vertices[] = {
 };
 
 void GLESBaseTexture::initGL() {
-	npot_supported = OpenGLContext.NPOTSupported;
+	_npot_supported = OpenGLContext.NPOTSupported;
 
-	const char* attributes[] = { "position", "texcoord", NULL };
-	g_box_shader = OpenGL::ShaderGL::fromStrings("control", OpenGL::BuiltinShaders::controlVertex, OpenGL::BuiltinShaders::controlFragment, attributes);
-	g_verticesVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
-	g_box_shader->enableVertexAttribute("position", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
-	g_box_shader->enableVertexAttribute("texcoord", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
+	const char *attributes[] = { "position", "texcoord", NULL };
+	_box_shader = OpenGL::ShaderGL::fromStrings("control", OpenGL::BuiltinShaders::controlVertex,
+	              OpenGL::BuiltinShaders::controlFragment, attributes);
+	_verticesVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
+	_box_shader->enableVertexAttribute("position", _verticesVBO, 2, GL_FLOAT, GL_TRUE,
+	                                   2 * sizeof(float), 0);
+	_box_shader->enableVertexAttribute("texcoord", _verticesVBO, 2, GL_FLOAT, GL_TRUE,
+	                                   2 * sizeof(float), 0);
 }
 
 GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
@@ -157,7 +159,7 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
 	if (w == _texture_width && h == _texture_height)
 		return;
 
-	if (npot_supported) {
+	if (_npot_supported) {
 		_texture_width = _surface.w;
 		_texture_height = _surface.h;
 	} else {
@@ -171,8 +173,8 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
 void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
 //	LOGD("*** Texture %p: Drawing %dx%d rect to (%d,%d)", this, w, h, x, y);
 
-	assert(g_box_shader);
-	g_box_shader->use();
+	assert(_box_shader);
+	_box_shader->use();
 
 	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
 	const GLfloat offsetX    = float(x) / float(JNI::egl_surface_width);
@@ -184,10 +186,10 @@ void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, co
 	clipV.z() /= _texture_width; clipV.w() /= _texture_height;
 //	LOGD("*** Drawing at (%f,%f) , size %f x %f", float(x) / float(_surface.w), float(y) / float(_surface.h),  tex_width, tex_height);
 
-	g_box_shader->setUniform("offsetXY", Math::Vector2d(offsetX, offsetY));
-	g_box_shader->setUniform("sizeWH", Math::Vector2d(sizeW, sizeH));
-	g_box_shader->setUniform("clip", clipV);
-	g_box_shader->setUniform("flipY", !_is_game_texture);
+	_box_shader->setUniform("offsetXY", Math::Vector2d(offsetX, offsetY));
+	_box_shader->setUniform("sizeWH", Math::Vector2d(sizeW, sizeH));
+	_box_shader->setUniform("clip", clipV);
+	_box_shader->setUniform("flipY", !_is_game_texture);
 
 	GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
 
diff --git a/backends/graphics3d/android/texture.h b/backends/graphics3d/android/texture.h
index e513938337..d009abc891 100644
--- a/backends/graphics3d/android/texture.h
+++ b/backends/graphics3d/android/texture.h
@@ -32,6 +32,10 @@
 #include "common/rect.h"
 #include "common/array.h"
 
+namespace OpenGL {
+class ShaderGL;
+}
+
 class GLESBaseTexture {
 public:
 	static void initGL();
@@ -189,6 +193,11 @@ protected:
 	Graphics::PixelFormat _palettePixelFormat;
 
 	bool _is_game_texture;
+
+	static bool _npot_supported;
+	static OpenGL::ShaderGL *_box_shader;
+	static GLuint _verticesVBO;
+
 };
 
 class GLESTexture : public GLESBaseTexture {


Commit: 83210561078aa4e29891bbfd5e410b73ea441d7d
    https://github.com/scummvm/scummvm/commit/83210561078aa4e29891bbfd5e410b73ea441d7d
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Remove superfluous asserts

new never returns nullptr, it throws exception or aborts

Changed paths:
    backends/graphics3d/android/texture.cpp


diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
index 6df9aba59a..d05e20cc45 100644
--- a/backends/graphics3d/android/texture.cpp
+++ b/backends/graphics3d/android/texture.cpp
@@ -229,14 +229,12 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {
 	delete[] _pixels;
 
 	_pixels = new byte[w * h * _surface.format.bytesPerPixel];
-	assert(_pixels);
 
 	_surface.setPixels(_pixels);
 
 	fillBuffer(0);
 
 	_buf = new byte[w * h * _surface.format.bytesPerPixel];
-	assert(_buf);
 }
 
 void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
@@ -350,7 +348,6 @@ GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
 	_fake_format = Graphics::PixelFormat::createFormatCLUT8();
 
 	_palette = new uint16[256];
-	assert(_palette);
 
 	memset(_palette, 0, 256 * 2);
 }
@@ -379,7 +376,6 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
 	delete[] _pixels;
 
 	_pixels = new byte[w * h];
-	assert(_pixels);
 
 	// fixup surface, for the outside this is a CLUT8 surface
 	_surface.setPixels(_pixels);
@@ -387,7 +383,6 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
 	fillBuffer(0);
 
 	_buf = new uint16[w * h];
-	assert(_buf);
 }
 
 void GLESFakePaletteTexture::fillBuffer(uint32 color) {


Commit: 40a036ac0be5c853d09493d0527f94ea73eba508
    https://github.com/scummvm/scummvm/commit/40a036ac0be5c853d09493d0527f94ea73eba508
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Use nullptr where appropriate

Changed paths:
    backends/graphics3d/android/texture.cpp
    backends/platform/android/touchcontrols.cpp


diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
index d05e20cc45..613b815b75 100644
--- a/backends/graphics3d/android/texture.cpp
+++ b/backends/graphics3d/android/texture.cpp
@@ -203,8 +203,8 @@ const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const {
 GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
 							Graphics::PixelFormat pixelFormat) :
 	GLESBaseTexture(glFormat, glType, pixelFormat),
-	_pixels(0),
-	_buf(0) {
+	_pixels(nullptr),
+	_buf(nullptr) {
 }
 
 GLESTexture::~GLESTexture() {
@@ -340,10 +340,9 @@ GLES565Texture::~GLES565Texture() {
 GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
 									Graphics::PixelFormat pixelFormat) :
 	GLESBaseTexture(glFormat, glType, pixelFormat),
-	_palette(0),
-	_pixels(0),
-	_buf(0)
-{
+	_palette(nullptr),
+	_pixels(nullptr),
+	_buf(nullptr) {
 	_palettePixelFormat = pixelFormat;
 	_fake_format = Graphics::PixelFormat::createFormatCLUT8();
 
diff --git a/backends/platform/android/touchcontrols.cpp b/backends/platform/android/touchcontrols.cpp
index b59e7737d2..f6d9ea046c 100644
--- a/backends/platform/android/touchcontrols.cpp
+++ b/backends/platform/android/touchcontrols.cpp
@@ -48,7 +48,7 @@
 #include "backends/platform/android/touchcontrols.h"
 
 TouchControls::TouchControls() :
-	_arrows_texture(NULL),
+	_arrows_texture(nullptr),
 	_screen_width(0),
 	_screen_height(0) {
 }


Commit: afcb0c54e74e6ed6b6a8c823843dcec802520a6b
    https://github.com/scummvm/scummvm/commit/afcb0c54e74e6ed6b6a8c823843dcec802520a6b
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Use real size instead of magical constant

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 169e8f6b08..dbb16b197d 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -448,10 +448,13 @@ void AndroidGraphics3dManager::setPalette(const byte *colors, uint start, uint n
 		setCursorPaletteInternal(colors, start, num);
 
 	const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
-	byte *p = _game_texture->palette() + start * 2;
+	// _game_texture is a GLESFakePalette565Texture so it's 16bits colors
+	assert(pf.bpp() == sizeof(uint16) * 8);
+	byte *p = _game_texture->palette() + start * sizeof(uint16);
 
-	for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+	for (uint i = 0; i < num; ++i, colors += 3, p += sizeof(uint16)) {
 		WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
+	}
 }
 
 void AndroidGraphics3dManager::grabPalette(byte *colors, uint start, uint num) const {
@@ -464,10 +467,13 @@ void AndroidGraphics3dManager::grabPalette(byte *colors, uint start, uint num) c
 	GLTHREADCHECK;
 
 	const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
-	const byte *p = _game_texture->palette_const() + start * 2;
+	// _game_texture is a GLESFakePalette565Texture so it's 16bits colors
+	assert(pf.bpp() == sizeof(uint16) * 8);
+	const byte *p = _game_texture->palette_const() + start * sizeof(uint16);
 
-	for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+	for (uint i = 0; i < num; ++i, colors += 3, p += sizeof(uint16)) {
 		pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]);
+	}
 }
 
 Graphics::Surface *AndroidGraphics3dManager::lockScreen() {
@@ -613,12 +619,15 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
 	if (_mouse_texture == _mouse_texture_palette) {
 		assert(keycolor < 256);
 
-		byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+		const Graphics::PixelFormat &pf = _mouse_texture_palette->getPalettePixelFormat();
+		// _mouse_texture_palette is a GLESFakePalette565Texture so it's 16bits colors
+		assert(pf.bpp() == sizeof(uint16) * 8);
+		byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * sizeof(uint16);
 		WRITE_UINT16(p, READ_UINT16(p) | 1);
 
 		_mouse_keycolor = keycolor;
 
-		p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+		p = _mouse_texture_palette->palette() + _mouse_keycolor * sizeof(uint16);
 		WRITE_UINT16(p, READ_UINT16(p) & ~1);
 	}
 
@@ -677,14 +686,17 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
 
 void AndroidGraphics3dManager::setCursorPaletteInternal(const byte *colors,
 												uint start, uint num) {
+	// _mouse_texture_palette is a GLESFakePalette565Texture so it's 16bits colors
 	const Graphics::PixelFormat &pf =
 		_mouse_texture_palette->getPalettePixelFormat();
-	byte *p = _mouse_texture_palette->palette() + start * 2;
+	assert(pf.bpp() == sizeof(uint16) * 8);
+	byte *p = _mouse_texture_palette->palette() + start * sizeof(uint16);
 
-	for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+	for (uint i = 0; i < num; ++i, colors += 3, p += sizeof(uint16)) {
 		WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
+	}
 
-	p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+	p = _mouse_texture_palette->palette() + _mouse_keycolor * sizeof(uint16);
 	WRITE_UINT16(p, READ_UINT16(p) & ~1);
 }
 
@@ -711,22 +723,25 @@ void AndroidGraphics3dManager::disableCursorPalette() {
 	// when disabling the cursor palette, and we're running a clut8 game,
 	// it expects the game palette to be used for the cursor
 	if (_game_texture->hasPalette()) {
-		const byte *src = _game_texture->palette_const();
-		byte *dst = _mouse_texture_palette->palette();
-
+		// _game_texture and _mouse_texture_palette are GLESFakePalette565Texture so it's 16bits colors
 		const Graphics::PixelFormat &pf_src =
 			_game_texture->getPalettePixelFormat();
 		const Graphics::PixelFormat &pf_dst =
 			_mouse_texture_palette->getPalettePixelFormat();
+		assert(pf_src.bpp() == sizeof(uint16) * 8);
+		assert(pf_dst.bpp() == sizeof(uint16) * 8);
+
+		const byte *src = _game_texture->palette_const();
+		byte *dst = _mouse_texture_palette->palette();
 
 		uint8 r, g, b;
 
-		for (uint i = 0; i < 256; ++i, src += 2, dst += 2) {
+		for (uint i = 0; i < 256; ++i, src += sizeof(uint16), dst += sizeof(uint16)) {
 			pf_src.colorToRGB(READ_UINT16(src), r, g, b);
 			WRITE_UINT16(dst, pf_dst.RGBToColor(r, g, b));
 		}
 
-		byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+		byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * sizeof(uint16);
 		WRITE_UINT16(p, READ_UINT16(p) & ~1);
 	}
 }


Commit: 3cb81ff31cbba6bc011a8375a2577154394f31b1
    https://github.com/scummvm/scummvm/commit/3cb81ff31cbba6bc011a8375a2577154394f31b1
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Don't use unsigned int

Changed paths:
    backends/platform/android/touchcontrols.cpp


diff --git a/backends/platform/android/touchcontrols.cpp b/backends/platform/android/touchcontrols.cpp
index f6d9ea046c..4c184a2727 100644
--- a/backends/platform/android/touchcontrols.cpp
+++ b/backends/platform/android/touchcontrols.cpp
@@ -135,7 +135,7 @@ void TouchControls::touchToRightState(int dX, int dY, FunctionState &state) {
 		{ 256, 128, 384, 256 }, // u
 		{ 384, 128, 512, 256 }  // l
 	};
-	static const unsigned int offset = (ARRAYSIZE(keycodes) - 1) / 2;
+	static const uint offset = (ARRAYSIZE(keycodes) - 1) / 2;
 
 	int idx = (dX / 100) + offset;
 	if (idx < 0) {
@@ -179,8 +179,8 @@ void TouchControls::init(int width, int height) {
 }
 
 TouchControls::Pointer *TouchControls::getPointerFromId(int ptrId, bool createNotFound) {
-	unsigned int freeEntry = -1;
-	for (unsigned int i = 0; i < kNumPointers; i++) {
+	uint freeEntry = -1;
+	for (uint i = 0; i < kNumPointers; i++) {
 		Pointer &ptr = _pointers[i];
 		if (ptr.active && (ptr.id == ptrId)) {
 			return &ptr;
@@ -202,7 +202,7 @@ TouchControls::Pointer *TouchControls::getPointerFromId(int ptrId, bool createNo
 }
 
 TouchControls::Pointer *TouchControls::findPointerFromFunction(Function function) {
-	for (unsigned int i = 0; i < kNumPointers; i++) {
+	for (uint i = 0; i < kNumPointers; i++) {
 		Pointer &ptr = _pointers[i];
 		if (ptr.active && (ptr.function == function)) {
 			return &ptr;
@@ -212,7 +212,7 @@ TouchControls::Pointer *TouchControls::findPointerFromFunction(Function function
 }
 
 void TouchControls::draw() {
-	for (unsigned int i = 0; i < kFunctionMax+1; i++) {
+	for (uint i = 0; i < kFunctionMax + 1; i++) {
 		FunctionState &state = _functionStates[i];
 		FunctionBehavior behavior = functionBehaviors[i];
 
@@ -305,12 +305,12 @@ void TouchControls::update(Action action, int ptrId, int x, int y) {
 		functionState.reset();
 		ptr->active = false;
 	} else if (action == JACTION_CANCEL) {
-		for (unsigned int i = 0; i < kNumPointers; i++) {
+		for (uint i = 0; i < kNumPointers; i++) {
 			Pointer &ptr = _pointers[i];
 			ptr.reset();
 		}
 
-		for (unsigned int i = 0; i < kFunctionMax+1; i++) {
+		for (uint i = 0; i < kFunctionMax + 1; i++) {
 			FunctionBehavior &behavior = functionBehaviors[i];
 			FunctionState &functionState = _functionStates[i];
 


Commit: 2bb9d5f3dfb6e205e1b02640aafae64acf33f70c
    https://github.com/scummvm/scummvm/commit/2bb9d5f3dfb6e205e1b02640aafae64acf33f70c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Remove outdated piece of code

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index dbb16b197d..b68d4ac064 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -829,17 +829,6 @@ void AndroidGraphics3dManager::initOverlay() {
 	int overlay_width = MAX(JNI::egl_surface_width, 320);
 	int overlay_height = MAX(JNI::egl_surface_height, 200);
 
-	// the 'normal' theme layout uses a max height of 400 pixels. if the
-	// surface is too big we use only a quarter of the size so that the widgets
-	// don't get too small. if the surface height has less than 800 pixels, this
-	// enforces the 'lowres' layout, which will be scaled back up by factor 2x,
-	// but this looks way better than the 'normal' layout scaled by some
-	// calculated factors
-//	while (overlay_height > 480) {
-//		overlay_width /= 2;
-//		overlay_height /= 2;
-//	}
-
 	LOGI("overlay size is %ux%u", overlay_width, overlay_height);
 
 	_overlay_texture->allocBuffer(overlay_width, overlay_height);


Commit: 5b62141b8f377e393b1def7b3ee9a8addb366a43
    https://github.com/scummvm/scummvm/commit/5b62141b8f377e393b1def7b3ee9a8addb366a43
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Fix code style

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/android/android-graphics3d.h
    backends/graphics3d/android/texture.cpp
    backends/graphics3d/android/texture.h
    backends/platform/android/touchcontrols.cpp
    backends/platform/android/touchcontrols.h


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index b68d4ac064..75a288f8e7 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -65,8 +65,7 @@ AndroidGraphics3dManager::AndroidGraphics3dManager() :
 	_mouse_hotspot(),
 	_mouse_keycolor(0),
 	_show_mouse(false),
-	_use_mouse_palette(false)
-{
+	_use_mouse_palette(false) {
 	_game_texture = new GLESFakePalette565Texture();
 	_overlay_texture = new GLES5551Texture();
 	_overlay_background = new GLES5551Texture();
@@ -99,7 +98,7 @@ AndroidGraphics3dManager::~AndroidGraphics3dManager() {
 
 static void logExtensions() {
 	const char *ext_string =
-		reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
+	    reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
 
 	LOGI("Extensions:");
 
@@ -115,8 +114,9 @@ static void logExtensions() {
 		}
 	}
 
-	if (exts.size() > 0)
+	if (exts.size() > 0) {
 		LOGI("\t%s", exts.c_str());
+	}
 }
 
 
@@ -134,8 +134,9 @@ void AndroidGraphics3dManager::initSurface() {
 	logExtensions();
 	GLESTexture::initGL();
 
-	if (_game_texture)
+	if (_game_texture) {
 		_game_texture->reinit();
+	}
 
 	// We don't have any content to display: just make sure surface is clean
 	if (_overlay_background) {
@@ -147,8 +148,9 @@ void AndroidGraphics3dManager::initSurface() {
 		initOverlay();
 	}
 
-	if (_mouse_texture)
+	if (_mouse_texture) {
 		_mouse_texture->reinit();
+	}
 
 	initViewport();
 	updateScreenRect();
@@ -156,29 +158,35 @@ void AndroidGraphics3dManager::initSurface() {
 	clearScreen(kClearUpdate, 2);
 	updateEventScale();
 
-	dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(JNI::egl_surface_width, JNI::egl_surface_height);
+	dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
+	    JNI::egl_surface_width, JNI::egl_surface_height);
 }
 
 void AndroidGraphics3dManager::deinitSurface() {
-	if (!JNI::haveSurface())
+	if (!JNI::haveSurface()) {
 		return;
+	}
 
 	LOGD("deinitializing 3D surface");
 
 	_screenChangeID = JNI::surface_changeid;
 
 	// release texture resources
-	if (_game_texture)
+	if (_game_texture) {
 		_game_texture->release();
+	}
 
-	if (_overlay_texture)
+	if (_overlay_texture) {
 		_overlay_texture->release();
+	}
 
-	if (_overlay_background)
+	if (_overlay_background) {
 		_overlay_background->release();
+	}
 
-	if (_mouse_texture)
+	if (_mouse_texture) {
 		_mouse_texture->release();
+	}
 
 	OpenGL::ContextGL::destroy();
 
@@ -190,20 +198,22 @@ void AndroidGraphics3dManager::updateScreen() {
 
 	GLTHREADCHECK;
 
-	if (!JNI::haveSurface())
+	if (!JNI::haveSurface()) {
 		return;
+	}
 
 	if (!_force_redraw &&
-			!_game_texture->dirty() &&
-			!_overlay_texture->dirty() &&
-			!_mouse_texture->dirty())
+	        !_game_texture->dirty() &&
+	        !_overlay_texture->dirty() &&
+	        !_mouse_texture->dirty()) {
 		return;
+	}
 
 	_force_redraw = false;
 
 	if (_frame_buffer) {
 		_frame_buffer->detach();
-		glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
+		glViewport(0, 0, JNI::egl_surface_width, JNI::egl_surface_height);
 	}
 
 	// We don't use depth stencil to draw on screen
@@ -234,15 +244,18 @@ void AndroidGraphics3dManager::updateScreen() {
 	if (_show_mouse && !_mouse_texture->isEmpty()) {
 		const Common::Point &mouse = g_system->getEventManager()->getMousePos();
 		if (_show_overlay) {
-			_mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height());
+			_mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs,
+			                            _mouse_texture->width(), _mouse_texture->height());
 		}
 	}
 
-	if (!JNI::swapBuffers())
+	if (!JNI::swapBuffers()) {
 		LOGW("swapBuffers failed: 0x%x", glGetError());
+	}
 
-	if (_frame_buffer)
+	if (_frame_buffer) {
 		_frame_buffer->attach();
+	}
 }
 
 void AndroidGraphics3dManager::displayMessageOnOSD(const Common::U32String &msg) {
@@ -280,8 +293,8 @@ int AndroidGraphics3dManager::getGraphicsMode() const {
 
 bool AndroidGraphics3dManager::hasFeature(OSystem::Feature f) const {
 	if (f == OSystem::kFeatureCursorPalette ||
-			f == OSystem::kFeatureOpenGLForGame ||
-			f == OSystem::kFeatureAspectRatioCorrection) {
+	        f == OSystem::kFeatureOpenGLForGame ||
+	        f == OSystem::kFeatureAspectRatioCorrection) {
 		return true;
 	}
 	return false;
@@ -291,8 +304,9 @@ void AndroidGraphics3dManager::setFeatureState(OSystem::Feature f, bool enable)
 	switch (f) {
 	case OSystem::kFeatureCursorPalette:
 		_use_mouse_palette = enable;
-		if (!enable)
+		if (!enable) {
 			disableCursorPalette();
+		}
 		break;
 	case OSystem::kFeatureFullscreenMode:
 		_fullscreen = enable;
@@ -339,15 +353,17 @@ void AndroidGraphics3dManager::showOverlay() {
 		if (g_engine) {
 			if (_frame_buffer) {
 				_frame_buffer->detach();
-				glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
+				glViewport(0, 0, JNI::egl_surface_width, JNI::egl_surface_height);
 			}
 			_overlay_background->allocBuffer(_overlay_texture->width(), _overlay_texture->height());
 			_overlay_background->setDrawRect(0, 0,
-				JNI::egl_surface_width, JNI::egl_surface_height);
+			                                 JNI::egl_surface_width, JNI::egl_surface_height);
 			Graphics::Surface *background = _overlay_background->surface();
-			glReadPixels(0, 0, background->w, background->h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, background->getPixels());
-			if (_frame_buffer)
+			glReadPixels(0, 0, background->w, background->h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
+			             background->getPixels());
+			if (_frame_buffer) {
 				_frame_buffer->attach();
+			}
 		}
 	}
 
@@ -403,11 +419,12 @@ void AndroidGraphics3dManager::grabOverlay(Graphics::Surface &surface) const {
 
 	const byte *src = (const byte *)overlaySurface->getPixels();
 	byte *dst = (byte *)surface.getPixels();
-	Graphics::copyBlit(dst, src, surface.pitch, overlaySurface->pitch, overlaySurface->w, overlaySurface->h, sizeof(uint16));
+	Graphics::copyBlit(dst, src, surface.pitch, overlaySurface->pitch,
+	                   overlaySurface->w, overlaySurface->h, sizeof(uint16));
 }
 
 void AndroidGraphics3dManager::copyRectToOverlay(const void *buf, int pitch,
-										int x, int y, int w, int h) {
+        int x, int y, int w, int h) {
 	ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
 
 	GLTHREADCHECK;
@@ -444,8 +461,9 @@ void AndroidGraphics3dManager::setPalette(const byte *colors, uint start, uint n
 
 	GLTHREADCHECK;
 
-	if (!_use_mouse_palette)
+	if (!_use_mouse_palette) {
 		setCursorPaletteInternal(colors, start, num);
+	}
 
 	const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
 	// _game_texture is a GLESFakePalette565Texture so it's 16bits colors
@@ -504,7 +522,7 @@ void AndroidGraphics3dManager::fillScreen(uint32 col) {
 }
 
 void AndroidGraphics3dManager::copyRectToScreen(const void *buf, int pitch,
-										int x, int y, int w, int h) {
+        int x, int y, int w, int h) {
 	ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
 
 	GLTHREADCHECK;
@@ -513,7 +531,7 @@ void AndroidGraphics3dManager::copyRectToScreen(const void *buf, int pitch,
 }
 
 void AndroidGraphics3dManager::initSize(uint width, uint height,
-					const Graphics::PixelFormat *format) {
+                                        const Graphics::PixelFormat *format) {
 	initViewport();
 
 	// resize game texture
@@ -523,10 +541,11 @@ void AndroidGraphics3dManager::initSize(uint width, uint height,
 }
 
 void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
-								const Graphics::PixelFormat *format) {
+        const Graphics::PixelFormat *format) {
 	ENTER("%d, %d, %p", width, height, format);
 
-	bool engineSupportsArbitraryResolutions = !g_engine || g_engine->hasFeature(Engine::kSupportsArbitraryResolutions);
+	bool engineSupportsArbitraryResolutions = !g_engine ||
+	        g_engine->hasFeature(Engine::kSupportsArbitraryResolutions);
 	if (engineSupportsArbitraryResolutions) {
 		width = JNI::egl_surface_width;
 		height = JNI::egl_surface_height;
@@ -540,7 +559,9 @@ void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
 	_game_texture->allocBuffer(width, height);
 #endif
 	delete _frame_buffer;
-	_frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight());
+	_frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(),
+	                                        _game_texture->width(), _game_texture->height(),
+	                                        _game_texture->texWidth(), _game_texture->texHeight());
 	_frame_buffer->attach();
 
 	updateScreenRect();
@@ -584,11 +605,11 @@ void AndroidGraphics3dManager::warpMouse(int x, int y) {
 }
 
 void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
-										int hotspotX, int hotspotY,
-										uint32 keycolor, bool dontScale,
-										const Graphics::PixelFormat *format) {
+        int hotspotX, int hotspotY,
+        uint32 keycolor, bool dontScale,
+        const Graphics::PixelFormat *format) {
 	ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
-			keycolor, dontScale, format);
+	      keycolor, dontScale, format);
 
 	GLTHREADCHECK;
 
@@ -604,8 +625,9 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
 
 		_mouse_texture = _mouse_texture_rgb;
 	} else {
-		if (_mouse_texture != _mouse_texture_palette)
+		if (_mouse_texture != _mouse_texture_palette) {
 			LOGD("switching to paletted mouse cursor");
+		}
 
 		_mouse_texture = _mouse_texture_palette;
 
@@ -631,8 +653,9 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
 		WRITE_UINT16(p, READ_UINT16(p) & ~1);
 	}
 
-	if (w == 0 || h == 0)
+	if (w == 0 || h == 0) {
 		return;
+	}
 
 	if (_mouse_texture == _mouse_texture_palette) {
 		_mouse_texture->updateBuffer(0, 0, w, h, buf, w);
@@ -643,8 +666,8 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
 
 		// meh, a n-bit cursor without alpha bits... this is so silly
 		if (!crossBlit(tmp, (const byte *)buf, pitch, w * format->bytesPerPixel, w, h,
-						_mouse_texture->getPixelFormat(),
-						*format)) {
+		               _mouse_texture->getPixelFormat(),
+		               *format)) {
 			LOGE("crossblit failed");
 
 			delete[] tmp;
@@ -659,18 +682,18 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
 			uint16 *d = (uint16 *)tmp;
 			for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
 				for (uint16 x = 0; x < w; ++x, d++)
-					if (*s++ == (keycolor & 0xffff))
+					if (*s++ == (keycolor & 0xffff)) {
 						*d = 0;
-		}
-		else if (format->bytesPerPixel == 4) {
+					}
+		} else if (format->bytesPerPixel == 4) {
 			const uint32 *s = (const uint32 *)buf;
 			uint16 *d = (uint16 *)tmp;
 			for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
 				for (uint16 x = 0; x < w; ++x, d++)
-					if (*s++ == (keycolor & 0xffff))
+					if (*s++ == (keycolor & 0xffff)) {
 						*d = 0;
-		}
-		else {
+					}
+		} else {
 			error("AndroidGraphics3dManager::setMouseCursor: invalid bytesPerPixel %d", format->bytesPerPixel);
 		}
 
@@ -685,7 +708,7 @@ void AndroidGraphics3dManager::setMouseCursor(const void *buf, uint w, uint h,
 }
 
 void AndroidGraphics3dManager::setCursorPaletteInternal(const byte *colors,
-												uint start, uint num) {
+        uint start, uint num) {
 	// _mouse_texture_palette is a GLESFakePalette565Texture so it's 16bits colors
 	const Graphics::PixelFormat &pf =
 		_mouse_texture_palette->getPalettePixelFormat();
@@ -701,7 +724,7 @@ void AndroidGraphics3dManager::setCursorPaletteInternal(const byte *colors,
 }
 
 void AndroidGraphics3dManager::setCursorPalette(const byte *colors,
-										uint start, uint num) {
+        uint start, uint num) {
 	ENTER("%p, %u, %u", colors, start, num);
 
 	GLTHREADCHECK;
@@ -725,9 +748,9 @@ void AndroidGraphics3dManager::disableCursorPalette() {
 	if (_game_texture->hasPalette()) {
 		// _game_texture and _mouse_texture_palette are GLESFakePalette565Texture so it's 16bits colors
 		const Graphics::PixelFormat &pf_src =
-			_game_texture->getPalettePixelFormat();
+		    _game_texture->getPalettePixelFormat();
 		const Graphics::PixelFormat &pf_dst =
-			_mouse_texture_palette->getPalettePixelFormat();
+		    _mouse_texture_palette->getPalettePixelFormat();
 		assert(pf_src.bpp() == sizeof(uint16) * 8);
 		assert(pf_dst.bpp() == sizeof(uint16) * 8);
 
@@ -797,7 +820,7 @@ void AndroidGraphics3dManager::updateScreenRect() {
 		if (dpi[0] != 0.0 && dpi[1] != 0.0) {
 			// horizontal orientation
 			screen_ar = (dpi[1] * JNI::egl_surface_width) /
-						(dpi[0] * JNI::egl_surface_height);
+			            (dpi[0] * JNI::egl_surface_height);
 		} else {
 			screen_ar = float(JNI::egl_surface_width) / float(JNI::egl_surface_height);
 		}
@@ -817,10 +840,11 @@ void AndroidGraphics3dManager::updateScreenRect() {
 }
 
 const GLESBaseTexture *AndroidGraphics3dManager::getActiveTexture() const {
-	if (_show_overlay)
+	if (_show_overlay) {
 		return _overlay_texture;
-	else
+	} else {
 		return _game_texture;
+	}
 }
 
 void AndroidGraphics3dManager::initOverlay() {
@@ -833,7 +857,7 @@ void AndroidGraphics3dManager::initOverlay() {
 
 	_overlay_texture->allocBuffer(overlay_width, overlay_height);
 	_overlay_texture->setDrawRect(0, 0,
-									JNI::egl_surface_width, JNI::egl_surface_height);
+	                              JNI::egl_surface_width, JNI::egl_surface_height);
 }
 
 void AndroidGraphics3dManager::initViewport() {
@@ -886,8 +910,9 @@ void AndroidGraphics3dManager::clearScreen(FixupType type, byte count) {
 		}
 	}
 
-	if (!_show_overlay)
+	if (!_show_overlay) {
 		GLCALL(glEnable(GL_SCISSOR_TEST));
+	}
 
 	_show_mouse = sm;
 	_force_redraw = true;
@@ -895,48 +920,50 @@ void AndroidGraphics3dManager::clearScreen(FixupType type, byte count) {
 
 #ifdef USE_RGB_COLOR
 void AndroidGraphics3dManager::initTexture(GLESBaseTexture **texture,
-									uint width, uint height,
-									const Graphics::PixelFormat *format) {
+        uint width, uint height,
+        const Graphics::PixelFormat *format) {
 	assert(texture);
 	Graphics::PixelFormat format_clut8 =
-		Graphics::PixelFormat::createFormatCLUT8();
+	    Graphics::PixelFormat::createFormatCLUT8();
 	Graphics::PixelFormat format_current;
 	Graphics::PixelFormat format_new;
 
-	if (*texture)
+	if (*texture) {
 		format_current = (*texture)->getPixelFormat();
-	else
+	} else {
 		format_current = Graphics::PixelFormat();
+	}
 
-	if (format)
+	if (format) {
 		format_new = *format;
-	else
+	} else {
 		format_new = format_clut8;
+	}
 
 	if (format_current != format_new) {
 		if (*texture)
 			LOGD("switching pixel format from: %s",
-					(*texture)->getPixelFormat().toString().c_str());
+			     (*texture)->getPixelFormat().toString().c_str());
 
 		delete *texture;
 
-		if (format_new == GLES565Texture::pixelFormat())
+		if (format_new == GLES565Texture::pixelFormat()) {
 			*texture = new GLES565Texture();
-		else if (format_new == GLES5551Texture::pixelFormat())
+		} else if (format_new == GLES5551Texture::pixelFormat()) {
 			*texture = new GLES5551Texture();
-		else if (format_new == GLES4444Texture::pixelFormat())
+		} else if (format_new == GLES4444Texture::pixelFormat()) {
 			*texture = new GLES4444Texture();
-		else {
+		} else {
 			// TODO what now?
 			if (format_new != format_clut8)
 				LOGE("unsupported pixel format: %s",
-					format_new.toString().c_str());
+				     format_new.toString().c_str());
 
 			*texture = new GLESFakePalette565Texture;
 		}
 
 		LOGD("new pixel format: %s",
-				(*texture)->getPixelFormat().toString().c_str());
+		     (*texture)->getPixelFormat().toString().c_str());
 	}
 
 	(*texture)->allocBuffer(width, height);
@@ -959,13 +986,13 @@ AndroidCommonGraphics::State AndroidGraphics3dManager::getState() const {
 
 bool AndroidGraphics3dManager::setState(const AndroidCommonGraphics::State &state) {
 #ifdef USE_RGB_COLOR
-		initSize(state.screenWidth, state.screenHeight, &state.pixelFormat);
+	initSize(state.screenWidth, state.screenHeight, &state.pixelFormat);
 #else
-		initSize(state.screenWidth, state.screenHeight, nullptr);
+	initSize(state.screenWidth, state.screenHeight, nullptr);
 #endif
-		setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio);
-		setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen);
-		setFeatureState(OSystem::kFeatureCursorPalette, state.cursorPalette);
+	setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio);
+	setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen);
+	setFeatureState(OSystem::kFeatureCursorPalette, state.cursorPalette);
 
-		return true;
+	return true;
 }
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
index 23196964cf..4e41f0c1d3 100644
--- a/backends/graphics3d/android/android-graphics3d.h
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -46,11 +46,18 @@ public:
 	void displayMessageOnOSD(const Common::U32String &msg);
 
 	virtual bool notifyMousePosition(Common::Point &mouse) override;
-	virtual Common::Point getMousePosition() override { return Common::Point(_cursorX, _cursorY); }
-	void setMousePosition(int x, int y) { _cursorX = x; _cursorY = y; }
+	virtual Common::Point getMousePosition() override {
+		return Common::Point(_cursorX, _cursorY);
+	}
+	void setMousePosition(int x, int y) {
+		_cursorX = x;
+		_cursorY = y;
+	}
 
 	virtual void beginGFXTransaction() {}
-	virtual OSystem::TransactionError endGFXTransaction() { return OSystem::kTransactionSuccess; }
+	virtual OSystem::TransactionError endGFXTransaction() {
+		return OSystem::kTransactionSuccess;
+	}
 
 	virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
 	virtual int getDefaultGraphicsMode() const override;
@@ -66,11 +73,13 @@ public:
 	virtual void clearOverlay() override;
 	virtual void grabOverlay(Graphics::Surface &surface) const override;
 	virtual void copyRectToOverlay(const void *buf, int pitch,
-									int x, int y, int w, int h) override;
+	                               int x, int y, int w, int h) override;
 	virtual int16 getOverlayHeight() const override;
 	virtual int16 getOverlayWidth() const override;
 	virtual Graphics::PixelFormat getOverlayFormat() const override;
-	virtual bool isOverlayVisible() const override { return _show_overlay; }
+	virtual bool isOverlayVisible() const override {
+		return _show_overlay;
+	}
 
 	virtual int16 getHeight() const override;
 	virtual int16 getWidth() const override;
@@ -79,26 +88,26 @@ public:
 	virtual void setPalette(const byte *colors, uint start, uint num) override;
 	virtual void grabPalette(byte *colors, uint start, uint num) const override;
 	virtual void copyRectToScreen(const void *buf, int pitch, int x, int y,
-									int w, int h) override;
+	                              int w, int h) override;
 	virtual Graphics::Surface *lockScreen() override;
 	virtual void unlockScreen() override;
 	virtual void fillScreen(uint32 col);
 
 	virtual void setShakePos(int shakeXOffset, int shakeYOffset) {};
-	virtual void setFocusRectangle(const Common::Rect& rect) {}
+	virtual void setFocusRectangle(const Common::Rect &rect) {}
 	virtual void clearFocusRectangle() {}
 
 	virtual void initSize(uint width, uint height,
-							const Graphics::PixelFormat *format) override;
+	                      const Graphics::PixelFormat *format) override;
 	virtual int getScreenChangeID() const override;
 
 	virtual bool showMouse(bool visible) override;
 	virtual void warpMouse(int x, int y) override;
 	virtual bool lockMouse(bool lock) override;
 	virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
-								int hotspotY, uint32 keycolor,
-								bool dontScale,
-								const Graphics::PixelFormat *format) override;
+	                            int hotspotY, uint32 keycolor,
+	                            bool dontScale,
+	                            const Graphics::PixelFormat *format) override;
 	virtual void setCursorPalette(const byte *colors, uint start, uint num) override;
 
 
@@ -129,15 +138,15 @@ private:
 	void initSizeIntern(uint width, uint height, const Graphics::PixelFormat *format);
 
 	enum FixupType {
-		kClear = 0,		// glClear
-		kClearSwap,		// glClear + swapBuffers
-		kClearUpdate	// glClear + updateScreen
+		kClear = 0,     // glClear
+		kClearSwap,     // glClear + swapBuffers
+		kClearUpdate    // glClear + updateScreen
 	};
 
 	void clearScreen(FixupType type, byte count = 1);
 #ifdef USE_RGB_COLOR
 	void initTexture(GLESBaseTexture **texture, uint width, uint height,
-						const Graphics::PixelFormat *format);
+	                 const Graphics::PixelFormat *format);
 #endif
 
 private:
diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
index 613b815b75..808e509f30 100644
--- a/backends/graphics3d/android/texture.cpp
+++ b/backends/graphics3d/android/texture.cpp
@@ -57,12 +57,14 @@ GLuint GLESBaseTexture::_verticesVBO = 0;
 
 template<class T>
 static T nextHigher2(T k) {
-	if (k == 0)
+	if (k == 0) {
 		return 1;
+	}
 	--k;
 
-	for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)
+	for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) {
 		k = k | k >> i;
+	}
 
 	return k + 1;
 }
@@ -88,7 +90,7 @@ void GLESBaseTexture::initGL() {
 }
 
 GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
-									Graphics::PixelFormat pixelFormat) :
+                                 Graphics::PixelFormat pixelFormat) :
 	_glFormat(glFormat),
 	_glType(glType),
 	_glFilter(GL_NEAREST),
@@ -101,8 +103,7 @@ GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
 	_dirty_rect(),
 	_pixelFormat(pixelFormat),
 	_palettePixelFormat(),
-	_is_game_texture(false)
-{
+	_is_game_texture(false) {
 	GLCALL(glGenTextures(1, &_texture_name));
 }
 
@@ -135,15 +136,16 @@ void GLESBaseTexture::initSize() {
 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
 	GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glFormat,
-						_texture_width, _texture_height,
-						0, _glFormat, _glType, 0));
+	                    _texture_width, _texture_height,
+	                    0, _glFormat, _glType, 0));
 }
 
 void GLESBaseTexture::setLinearFilter(bool value) {
-	if (value)
+	if (value) {
 		_glFilter = GL_LINEAR;
-	else
+	} else {
 		_glFilter = GL_NEAREST;
+	}
 
 	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
 
@@ -156,8 +158,9 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
 	_surface.h = h;
 	_surface.format = _pixelFormat;
 
-	if (w == _texture_width && h == _texture_height)
+	if (w == _texture_width && h == _texture_height) {
 		return;
+	}
 
 	if (_npot_supported) {
 		_texture_width = _surface.w;
@@ -170,7 +173,8 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
 	initSize();
 }
 
-void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
+void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h,
+                                  const Common::Rect &clip) {
 //	LOGD("*** Texture %p: Drawing %dx%d rect to (%d,%d)", this, w, h, x, y);
 
 	assert(_box_shader);
@@ -182,8 +186,10 @@ void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, co
 	const GLfloat sizeW      = float(w) / float(JNI::egl_surface_width);
 	const GLfloat sizeH      = float(h) / float(JNI::egl_surface_height);
 	Math::Vector4d clipV = Math::Vector4d(clip.left, clip.top, clip.right, clip.bottom);
-	clipV.x() /= _texture_width; clipV.y() /= _texture_height;
-	clipV.z() /= _texture_width; clipV.w() /= _texture_height;
+	clipV.x() /= _texture_width;
+	clipV.y() /= _texture_height;
+	clipV.z() /= _texture_width;
+	clipV.w() /= _texture_height;
 //	LOGD("*** Drawing at (%f,%f) , size %f x %f", float(x) / float(_surface.w), float(y) / float(_surface.h),  tex_width, tex_height);
 
 	_box_shader->setUniform("offsetXY", Math::Vector2d(offsetX, offsetY));
@@ -201,7 +207,7 @@ const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const {
 }
 
 GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
-							Graphics::PixelFormat pixelFormat) :
+                         Graphics::PixelFormat pixelFormat) :
 	GLESBaseTexture(glFormat, glType, pixelFormat),
 	_pixels(nullptr),
 	_buf(nullptr) {
@@ -238,7 +244,7 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {
 }
 
 void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
-								const void *buf, int pitch_buf) {
+                               const void *buf, int pitch_buf) {
 	setDirtyRect(Common::Rect(x, y, x + w, y + h));
 
 	const byte *src = (const byte *)buf;
@@ -255,16 +261,18 @@ void GLESTexture::fillBuffer(uint32 color) {
 	assert(_surface.getPixels());
 
 	if (_pixelFormat.bytesPerPixel == 1 ||
-			((color & 0xff) == ((color >> 8) & 0xff)))
+	        ((color & 0xff) == ((color >> 8) & 0xff))) {
 		memset(_pixels, color & 0xff, _surface.pitch * _surface.h);
-	else
+	} else {
 		Common::fill(_pixels, _pixels + _surface.pitch * _surface.h,
-						(uint16)color);
+		             (uint16)color);
+	}
 
 	setDirty();
 }
 
-void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
+void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h,
+                              const Common::Rect &clip) {
 	if (_all_dirty) {
 		_dirty_rect.top = 0;
 		_dirty_rect.left = 0;
@@ -286,7 +294,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const
 			_tex = _buf;
 
 			byte *src = _pixels + _dirty_rect.top * _surface.pitch +
-						_dirty_rect.left * _surface.format.bytesPerPixel;
+			            _dirty_rect.left * _surface.format.bytesPerPixel;
 			byte *dst = _buf;
 
 			uint16 l = dwidth * _surface.format.bytesPerPixel;
@@ -302,8 +310,8 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const
 		GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
 
 		GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
-								_dirty_rect.left, _dirty_rect.top,
-								dwidth, dheight, _glFormat, _glType, _tex));
+		                       _dirty_rect.left, _dirty_rect.top,
+		                       dwidth, dheight, _glFormat, _glType, _tex));
 	}
 
 	GLESBaseTexture::drawTexture(x, y, w, h, clip);
@@ -338,7 +346,7 @@ GLES565Texture::~GLES565Texture() {
 }
 
 GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
-									Graphics::PixelFormat pixelFormat) :
+        Graphics::PixelFormat pixelFormat) :
 	GLESBaseTexture(glFormat, glType, pixelFormat),
 	_palette(nullptr),
 	_pixels(nullptr),
@@ -390,9 +398,8 @@ void GLESFakePaletteTexture::fillBuffer(uint32 color) {
 	setDirty();
 }
 
-void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w,
-											GLuint h, const void *buf,
-											int pitch_buf) {
+void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y,
+        GLuint w, GLuint h, const void *buf, int pitch_buf) {
 	setDirtyRect(Common::Rect(x, y, x + w, y + h));
 
 	const byte *src = (const byte *)buf;
@@ -405,7 +412,8 @@ void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w,
 	} while (--h);
 }
 
-void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
+void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h,
+        const Common::Rect &clip) {
 	if (_all_dirty) {
 		_dirty_rect.top = 0;
 		_dirty_rect.left = 0;
@@ -420,21 +428,22 @@ void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshor
 		int16 dheight = _dirty_rect.height();
 
 		byte *src = _pixels + _dirty_rect.top * _surface.pitch +
-					_dirty_rect.left;
+		            _dirty_rect.left;
 		uint16 *dst = _buf;
 		uint pitch_delta = _surface.pitch - dwidth;
 
 		for (uint16 j = 0; j < dheight; ++j) {
-			for (uint16 i = 0; i < dwidth; ++i)
+			for (uint16 i = 0; i < dwidth; ++i) {
 				*dst++ = _palette[*src++];
+			}
 			src += pitch_delta;
 		}
 
 		GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
 
 		GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
-								_dirty_rect.left, _dirty_rect.top,
-								dwidth, dheight, _glFormat, _glType, _buf));
+		                       _dirty_rect.left, _dirty_rect.top,
+		                       dwidth, dheight, _glFormat, _glType, _buf));
 	}
 
 	GLESBaseTexture::drawTexture(x, y, w, h, clip);
@@ -446,7 +455,7 @@ const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const {
 
 GLESFakePalette565Texture::GLESFakePalette565Texture() :
 	GLESFakePaletteTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
-							GLES565Texture::pixelFormat()) {
+	                       GLES565Texture::pixelFormat()) {
 }
 
 GLESFakePalette565Texture::~GLESFakePalette565Texture() {
@@ -454,7 +463,7 @@ GLESFakePalette565Texture::~GLESFakePalette565Texture() {
 
 GLESFakePalette5551Texture::GLESFakePalette5551Texture() :
 	GLESFakePaletteTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
-							GLES5551Texture::pixelFormat()) {
+	                       GLES5551Texture::pixelFormat()) {
 }
 
 GLESFakePalette5551Texture::~GLESFakePalette5551Texture() {
diff --git a/backends/graphics3d/android/texture.h b/backends/graphics3d/android/texture.h
index d009abc891..1680d97f85 100644
--- a/backends/graphics3d/android/texture.h
+++ b/backends/graphics3d/android/texture.h
@@ -42,7 +42,7 @@ public:
 
 protected:
 	GLESBaseTexture(GLenum glFormat, GLenum glType,
-					Graphics::PixelFormat pixelFormat);
+	                Graphics::PixelFormat pixelFormat);
 
 public:
 	virtual ~GLESBaseTexture();
@@ -56,7 +56,7 @@ public:
 	virtual void allocBuffer(GLuint w, GLuint h);
 
 	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
-								const void *buf, int pitch_buf) = 0;
+	                          const void *buf, int pitch_buf) = 0;
 	virtual void fillBuffer(uint32 color) = 0;
 
 	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
@@ -83,11 +83,11 @@ public:
 
 	inline void drawTextureRect() {
 		drawTexture(_draw_rect.left, _draw_rect.top,
-					_draw_rect.width(), _draw_rect.height());
+		            _draw_rect.width(), _draw_rect.height());
 	}
 
 	inline void drawTextureOrigin() {
-			drawTexture(0, 0, _surface.w, _surface.h);
+		drawTexture(0, 0, _surface.w, _surface.h);
 	}
 
 	inline GLuint width() const {
@@ -166,12 +166,13 @@ protected:
 		_dirty_rect.right = 0;
 	}
 
-	inline void setDirtyRect(const Common::Rect& r) {
+	inline void setDirtyRect(const Common::Rect &r) {
 		if (!_all_dirty) {
-			if (_dirty_rect.isEmpty())
+			if (_dirty_rect.isEmpty()) {
 				_dirty_rect = r;
-			else
+			} else {
 				_dirty_rect.extend(r);
+			}
 		}
 	}
 
@@ -203,7 +204,7 @@ protected:
 class GLESTexture : public GLESBaseTexture {
 protected:
 	GLESTexture(GLenum glFormat, GLenum glType,
-				Graphics::PixelFormat pixelFormat);
+	            Graphics::PixelFormat pixelFormat);
 
 public:
 	virtual ~GLESTexture();
@@ -211,7 +212,7 @@ public:
 	virtual void allocBuffer(GLuint w, GLuint h);
 
 	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
-								const void *buf, int pitch_buf);
+	                          const void *buf, int pitch_buf);
 	virtual void fillBuffer(uint32 color);
 
 	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
@@ -270,14 +271,14 @@ public:
 class GLESFakePaletteTexture : public GLESBaseTexture {
 protected:
 	GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
-							Graphics::PixelFormat pixelFormat);
+	                       Graphics::PixelFormat pixelFormat);
 
 public:
 	virtual ~GLESFakePaletteTexture();
 
 	virtual void allocBuffer(GLuint w, GLuint h);
 	virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
-								const void *buf, int pitch_buf);
+	                          const void *buf, int pitch_buf);
 	virtual void fillBuffer(uint32 color);
 
 	virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
diff --git a/backends/platform/android/touchcontrols.cpp b/backends/platform/android/touchcontrols.cpp
index 4c184a2727..f2baf2d9ac 100644
--- a/backends/platform/android/touchcontrols.cpp
+++ b/backends/platform/android/touchcontrols.cpp
@@ -63,12 +63,13 @@ TouchControls::~TouchControls() {
 TouchControls::Function TouchControls::getFunction(int x, int y) {
 	float xPercent = float(x) / _screen_width;
 
-	if (xPercent < 0.3)
+	if (xPercent < 0.3) {
 		return kFunctionJoystick;
-	else if (xPercent < 0.8)
+	} else if (xPercent < 0.8) {
 		return kFunctionCenter;
-	else
+	} else {
 		return kFunctionRight;
+	}
 }
 
 void TouchControls::touchToJoystickState(int dX, int dY, FunctionState &state) {
@@ -107,8 +108,9 @@ void TouchControls::touchToCenterState(int dX, int dY, FunctionState &state) {
 }
 
 void TouchControls::touchToRightState(int dX, int dY, FunctionState &state) {
-	if (dX * dX + dY * dY < 100 * 100)
+	if (dX * dX + dY * dY < 100 * 100) {
 		return;
+	}
 
 	if (dY > abs(dX)) {
 		// down
@@ -148,7 +150,8 @@ void TouchControls::touchToRightState(int dX, int dY, FunctionState &state) {
 	state.clip = Common::Rect(clips[idx][0], clips[idx][1], clips[idx][2], clips[idx][3]);
 }
 
-TouchControls::FunctionBehavior TouchControls::functionBehaviors[TouchControls::kFunctionMax+1] = {
+TouchControls::FunctionBehavior TouchControls::functionBehaviors[TouchControls::kFunctionMax + 1] =
+{
 	{ touchToJoystickState, false, .2f, .5f },
 	{ touchToCenterState,   true,  .5f, .5f },
 	{ touchToRightState,    true,  .8f, .5f }
@@ -219,7 +222,8 @@ void TouchControls::draw() {
 		if (state.clip.isEmpty()) {
 			continue;
 		}
-		_arrows_texture->drawTexture(_screen_width * behavior.xRatio, _screen_height * behavior.yRatio, 64, 64, state.clip);
+		_arrows_texture->drawTexture(_screen_width * behavior.xRatio, _screen_height * behavior.yRatio,
+		                             64, 64, state.clip);
 
 	}
 }
diff --git a/backends/platform/android/touchcontrols.h b/backends/platform/android/touchcontrols.h
index 990ecf187a..c5f1cd9bfc 100644
--- a/backends/platform/android/touchcontrols.h
+++ b/backends/platform/android/touchcontrols.h
@@ -57,8 +57,15 @@ private:
 	Function getFunction(int x, int y);
 
 	struct Pointer {
-		Pointer() : id(-1), startX(-1), startY(-1), currentX(-1), currentY(-1), function(kFunctionNone), active(false) {}
-		void reset() { id = -1; startX = startY = currentX = currentY = -1; function = kFunctionNone; active = false; }
+		Pointer() : id(-1), startX(-1), startY(-1),
+			currentX(-1), currentY(-1),
+			function(kFunctionNone), active(false) {}
+		void reset() {
+			id = -1;
+			startX = startY = currentX = currentY = -1;
+			function = kFunctionNone;
+			active = false;
+		}
 
 		int id;
 		uint16 startX, startY;
@@ -74,8 +81,13 @@ private:
 	Pointer *findPointerFromFunction(Function function);
 
 	struct FunctionState {
-		FunctionState() : main(Common::KEYCODE_INVALID), modifier(Common::KEYCODE_INVALID) { }
-		void reset() { main = Common::KEYCODE_INVALID; modifier = Common::KEYCODE_INVALID; clip = Common::Rect(); }
+		FunctionState() : main(Common::KEYCODE_INVALID),
+			modifier(Common::KEYCODE_INVALID) {}
+		void reset() {
+			main = Common::KEYCODE_INVALID;
+			modifier = Common::KEYCODE_INVALID;
+			clip = Common::Rect();
+		}
 
 		Common::KeyCode main;
 		Common::KeyCode modifier;
@@ -96,7 +108,7 @@ private:
 		float xRatio;
 		float yRatio;
 	};
-	static FunctionBehavior functionBehaviors[TouchControls::kFunctionMax+1];
+	static FunctionBehavior functionBehaviors[TouchControls::kFunctionMax + 1];
 
 	static void touchToJoystickState(int dX, int dY, FunctionState &state);
 	static void touchToCenterState(int dX, int dY, FunctionState &state);


Commit: d6f37a161b7dcf63bcfd59827dbb33ad6f712318
    https://github.com/scummvm/scummvm/commit/d6f37a161b7dcf63bcfd59827dbb33ad6f712318
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: Remove again updateEventScale

It was removed in android in #1695 but not in android3d in ResidualVM.

Changed paths:
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/android/android-graphics3d.h
    backends/platform/android/android.h
    backends/platform/android/events.cpp


diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 75a288f8e7..80c2dfae50 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -156,7 +156,6 @@ void AndroidGraphics3dManager::initSurface() {
 	updateScreenRect();
 	// double buffered, flip twice
 	clearScreen(kClearUpdate, 2);
-	updateEventScale();
 
 	dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().init(
 	    JNI::egl_surface_width, JNI::egl_surface_height);
@@ -367,8 +366,6 @@ void AndroidGraphics3dManager::showOverlay() {
 		}
 	}
 
-	updateEventScale();
-
 	warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2);
 
 	GLCALL(glDisable(GL_SCISSOR_TEST));
@@ -387,8 +384,6 @@ void AndroidGraphics3dManager::hideOverlay() {
 
 	JNI::setTouch3DMode(true);
 
-	updateEventScale();
-
 	warpMouse(_game_texture->width() / 2, _game_texture->height() / 2);
 
 	// double buffered, flip twice
@@ -565,7 +560,6 @@ void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
 	_frame_buffer->attach();
 
 	updateScreenRect();
-	updateEventScale();
 
 	// Don't know mouse size yet - it gets reallocated in
 	// setMouseCursor.  We need the palette allocated before
@@ -875,13 +869,6 @@ void AndroidGraphics3dManager::initViewport() {
 	LOGD("viewport size: %dx%d", JNI::egl_surface_width, JNI::egl_surface_height);
 }
 
-void AndroidGraphics3dManager::updateEventScale() {
-	const GLESBaseTexture *texture = getActiveTexture();
-	if (texture) {
-		dynamic_cast<OSystem_Android *>(g_system)->updateEventScale(texture->width(), texture->height());
-	}
-}
-
 void AndroidGraphics3dManager::clearScreen(FixupType type, byte count) {
 	assert(count > 0);
 
diff --git a/backends/graphics3d/android/android-graphics3d.h b/backends/graphics3d/android/android-graphics3d.h
index 4e41f0c1d3..4e234fdaf1 100644
--- a/backends/graphics3d/android/android-graphics3d.h
+++ b/backends/graphics3d/android/android-graphics3d.h
@@ -134,7 +134,6 @@ private:
 	void disableCursorPalette();
 	void initOverlay();
 	void initViewport();
-	void updateEventScale();
 	void initSizeIntern(uint width, uint height, const Graphics::PixelFormat *format);
 
 	enum FixupType {
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 59fd05a325..b1b2427129 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -191,7 +191,6 @@ public:
 	bool setGraphicsMode(int mode, uint flags) override;
 	int getGraphicsMode() const override;
 
-	void updateEventScale(uint32 w, uint32 h);
 #ifdef ANDROID_DEBUG_GL_CALLS
 	bool isRunningInMainThread() { return pthread_self() == _main_thread; }
 #endif
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
index 54924807a8..7f38e8e330 100644
--- a/backends/platform/android/events.cpp
+++ b/backends/platform/android/events.cpp
@@ -373,13 +373,6 @@ static const Common::KeyCode jkeymap[] = {
 	Common::KEYCODE_PASTE // AKEYCODE_PASTE
 };
 
-void OSystem_Android::updateEventScale(uint32 w, uint32 h) {
-	if ((h != 0) && (w != 0)) {
-	    _eventScaleY = 100 * 480 / h;
-	    _eventScaleX = 100 * 640 / w;
-	}
-}
-
 void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 								int arg4, int arg5, int arg6) {
 	Common::Event e;


Commit: ba136b6f29140dc019ed2738e737f45d5cf53620
    https://github.com/scummvm/scummvm/commit/ba136b6f29140dc019ed2738e737f45d5cf53620
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
COMMON: Add JOYSTICK_BUTTON_INVALID to be used when no button is pressed

Changed paths:
    common/events.h


diff --git a/common/events.h b/common/events.h
index 69413e80e7..aab6799f78 100644
--- a/common/events.h
+++ b/common/events.h
@@ -144,6 +144,7 @@ struct JoystickState {
  *  The list of named buttons available from a joystick.
  */
 enum JoystickButton {
+	JOYSTICK_BUTTON_INVALID,
 	JOYSTICK_BUTTON_A,
 	JOYSTICK_BUTTON_B,
 	JOYSTICK_BUTTON_X,


Commit: e7b6cff4dd01542ec593e9e2ecb1fe0909b15019
    https://github.com/scummvm/scummvm/commit/e7b6cff4dd01542ec593e9e2ecb1fe0909b15019
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-11-29T00:04:45+01:00

Commit Message:
ANDROID: The virtual controls now generate fake joystick events

This allows to use the keymapper and not have hardcoded keyboard events

Changed paths:
    backends/platform/android/android.h
    backends/platform/android/events.cpp
    backends/platform/android/touchcontrols.cpp
    backends/platform/android/touchcontrols.h
    dists/android/assets/arrows.tga


diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index b1b2427129..649d6055bc 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -132,7 +132,7 @@ public:
 public:
 	void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6);
 	void pushEvent(const Common::Event &event);
-	void pushKeyPressEvent(Common::Event &event);
+	void pushEvent(const Common::Event &event1, const Common::Event &event2);
 
 	TouchControls &getTouchControls() { return _touchControls; }
 
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
index 7f38e8e330..65ace99532 100644
--- a/backends/platform/android/events.cpp
+++ b/backends/platform/android/events.cpp
@@ -1299,12 +1299,10 @@ void OSystem_Android::pushEvent(const Common::Event &event) {
 	_event_queue_lock->unlock();
 }
 
-void OSystem_Android::pushKeyPressEvent(Common::Event &event) {
+void OSystem_Android::pushEvent(const Common::Event &event1, const Common::Event &event2) {
 	_event_queue_lock->lock();
-	event.type = Common::EVENT_KEYDOWN;
-	_event_queue.push(event);
-	event.type = Common::EVENT_KEYUP;
-	_event_queue.push(event);
+	_event_queue.push(event1);
+	_event_queue.push(event2);
 	_event_queue_lock->unlock();
 }
 
diff --git a/backends/platform/android/touchcontrols.cpp b/backends/platform/android/touchcontrols.cpp
index f2baf2d9ac..b274e5b010 100644
--- a/backends/platform/android/touchcontrols.cpp
+++ b/backends/platform/android/touchcontrols.cpp
@@ -79,23 +79,23 @@ void TouchControls::touchToJoystickState(int dX, int dY, FunctionState &state) {
 	}
 
 	if (dY > abs(dX)) {
-		state.main = Common::KEYCODE_DOWN;
+		state.main = Common::JOYSTICK_BUTTON_DPAD_DOWN;
 		state.clip = Common::Rect(256, 0, 384, 128);
 	} else if (dX > abs(dY)) {
-		state.main = Common::KEYCODE_RIGHT;
+		state.main = Common::JOYSTICK_BUTTON_DPAD_RIGHT;
 		state.clip = Common::Rect(128, 0, 256, 128);
 	} else if (-dY > abs(dX)) {
-		state.main = Common::KEYCODE_UP;
+		state.main = Common::JOYSTICK_BUTTON_DPAD_UP;
 		state.clip = Common::Rect(0, 0, 128, 128);
 	} else if (-dX > abs(dY)) {
-		state.main = Common::KEYCODE_LEFT;
+		state.main = Common::JOYSTICK_BUTTON_DPAD_LEFT;
 		state.clip = Common::Rect(384, 0, 512, 128);
 	} else {
 		return;
 	}
 
 	if (sqNorm > 20000) {
-		state.modifier = Common::KEYCODE_LSHIFT;
+		state.modifier = Common::JOYSTICK_BUTTON_RIGHT_SHOULDER;
 	}
 
 }
@@ -103,7 +103,7 @@ void TouchControls::touchToJoystickState(int dX, int dY, FunctionState &state) {
 void TouchControls::touchToCenterState(int dX, int dY, FunctionState &state) {
 	int sqNorm = dX * dX + dY * dY;
 	if (sqNorm < 50 * 50) {
-		state.main = Common::KEYCODE_RETURN;
+		state.main = Common::JOYSTICK_BUTTON_GUIDE;
 	}
 }
 
@@ -112,41 +112,41 @@ void TouchControls::touchToRightState(int dX, int dY, FunctionState &state) {
 		return;
 	}
 
-	if (dY > abs(dX)) {
-		// down
-		state.main = Common::KEYCODE_PAGEDOWN;
-		state.clip = Common::Rect(256, 0, 384, 128);
+	if (dX > abs(dY)) {
+		// right
+		state.main = Common::JOYSTICK_BUTTON_RIGHT_STICK;
+		state.clip = Common::Rect(512, 128, 640, 256);
 		return;
-	} else if (-dY > abs(dX)) {
-		// up
-		state.main = Common::KEYCODE_PAGEUP;
-		state.clip = Common::Rect(0, 0, 128, 128);
+	} else if (-dX > abs(dY)) {
+		// left
+		state.main = Common::JOYSTICK_BUTTON_LEFT_STICK;
+		state.clip = Common::Rect(512, 0, 640, 128);
 		return;
 	}
 
-	static Common::KeyCode keycodes[5] = {
-		Common::KEYCODE_i, Common::KEYCODE_p, // left zone
-		Common::KEYCODE_INVALID, // center
-		Common::KEYCODE_u, Common::KEYCODE_l // right zone
+	static Common::JoystickButton buttons[5] = {
+		Common::JOYSTICK_BUTTON_Y, Common::JOYSTICK_BUTTON_B, // top zone
+		Common::JOYSTICK_BUTTON_INVALID, // center
+		Common::JOYSTICK_BUTTON_A, Common::JOYSTICK_BUTTON_X // bottom zone
 	};
 
 	static int16 clips[5][4] = {
-		{   0, 128, 128, 256 }, // i
-		{ 128, 128, 256, 256 }, // p
+		{   0, 128, 128, 256 }, // y
+		{ 128, 128, 256, 256 }, // b
 		{   0,   0,   0,   0 }, // center
-		{ 256, 128, 384, 256 }, // u
-		{ 384, 128, 512, 256 }  // l
+		{ 256, 128, 384, 256 }, // a
+		{ 384, 128, 512, 256 }  // x
 	};
-	static const uint offset = (ARRAYSIZE(keycodes) - 1) / 2;
+	static const uint offset = (ARRAYSIZE(buttons) - 1) / 2;
 
-	int idx = (dX / 100) + offset;
+	int idx = (dY / 100) + offset;
 	if (idx < 0) {
 		idx = 0;
 	}
-	if (idx >= ARRAYSIZE(keycodes)) {
-		idx = ARRAYSIZE(keycodes) - 1;
+	if (idx >= ARRAYSIZE(buttons)) {
+		idx = ARRAYSIZE(buttons) - 1;
 	}
-	state.main = keycodes[idx];
+	state.main = buttons[idx];
 	state.clip = Common::Rect(clips[idx][0], clips[idx][1], clips[idx][2], clips[idx][3]);
 }
 
@@ -266,18 +266,18 @@ void TouchControls::update(Action action, int ptrId, int x, int y) {
 
 		FunctionState &oldState = _functionStates[ptr->function];
 
-		if (!behavior.keyPressOnRelease) {
+		if (!behavior.pressOnRelease) {
 			// send key presses continuously
 			// first old remove main key, then update modifier, then press new main key
 			if (oldState.main != newState.main) {
-				keyUp(oldState.main);
+				buttonUp(oldState.main);
 			}
 			if (oldState.modifier != newState.modifier) {
-				keyUp(oldState.modifier);
-				keyDown(newState.modifier);
+				buttonUp(oldState.modifier);
+				buttonDown(newState.modifier);
 			}
 			if (oldState.main != newState.main) {
-				keyDown(newState.main);
+				buttonDown(newState.main);
 			}
 		}
 		oldState = newState;
@@ -290,10 +290,10 @@ void TouchControls::update(Action action, int ptrId, int x, int y) {
 		FunctionBehavior &behavior = functionBehaviors[ptr->function];
 		FunctionState &functionState = _functionStates[ptr->function];
 
-		if (!behavior.keyPressOnRelease) {
-			// We sent key down continously: keyUp everything
-			keyUp(functionState.main);
-			keyUp(functionState.modifier);
+		if (!behavior.pressOnRelease) {
+			// We sent key down continously: buttonUp everything
+			buttonUp(functionState.main);
+			buttonUp(functionState.modifier);
 		} else {
 			int dX = x - ptr->startX;
 			int dY = y - ptr->startY;
@@ -301,9 +301,9 @@ void TouchControls::update(Action action, int ptrId, int x, int y) {
 			FunctionState newState;
 			functionBehaviors[ptr->function].touchToState(dX, dY, newState);
 
-			keyDown(newState.modifier);
-			keyPress(newState.main);
-			keyUp(newState.modifier);
+			buttonDown(newState.modifier);
+			buttonPress(newState.main);
+			buttonUp(newState.modifier);
 		}
 
 		functionState.reset();
@@ -318,10 +318,10 @@ void TouchControls::update(Action action, int ptrId, int x, int y) {
 			FunctionBehavior &behavior = functionBehaviors[i];
 			FunctionState &functionState = _functionStates[i];
 
-			if (!behavior.keyPressOnRelease) {
-				// We sent key down continously: keyUp everything
-				keyUp(functionState.main);
-				keyUp(functionState.modifier);
+			if (!behavior.pressOnRelease) {
+				// We sent key down continously: buttonUp everything
+				buttonUp(functionState.main);
+				buttonUp(functionState.modifier);
 			}
 
 			functionState.reset();
@@ -329,34 +329,37 @@ void TouchControls::update(Action action, int ptrId, int x, int y) {
 	}
 }
 
-void TouchControls::keyDown(Common::KeyCode kc) {
-	if (kc == Common::KEYCODE_INVALID) {
+void TouchControls::buttonDown(Common::JoystickButton jb) {
+	if (jb == Common::JOYSTICK_BUTTON_INVALID) {
 		return;
 	}
 
 	Common::Event ev;
-	ev.type = Common::EVENT_KEYDOWN;
-	ev.kbd.keycode = kc;
+	ev.type = Common::EVENT_JOYBUTTON_DOWN;
+	ev.joystick.button = jb;
 	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
 }
 
-void TouchControls::keyUp(Common::KeyCode kc) {
-	if (kc == Common::KEYCODE_INVALID) {
+void TouchControls::buttonUp(Common::JoystickButton jb) {
+	if (jb == Common::JOYSTICK_BUTTON_INVALID) {
 		return;
 	}
 
 	Common::Event ev;
-	ev.type = Common::EVENT_KEYUP;
-	ev.kbd.keycode = kc;
+	ev.type = Common::EVENT_JOYBUTTON_UP;
+	ev.joystick.button = jb;
 	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev);
 }
 
-void TouchControls::keyPress(Common::KeyCode kc) {
-	if (kc == Common::KEYCODE_INVALID) {
+void TouchControls::buttonPress(Common::JoystickButton jb) {
+	if (jb == Common::JOYSTICK_BUTTON_INVALID) {
 		return;
 	}
 
-	Common::Event ev;
-	ev.kbd.keycode = kc;
-	dynamic_cast<OSystem_Android *>(g_system)->pushKeyPressEvent(ev);
+	Common::Event ev1, ev2;
+	ev1.type = Common::EVENT_JOYBUTTON_DOWN;
+	ev1.joystick.button = jb;
+	ev2.type = Common::EVENT_JOYBUTTON_UP;
+	ev2.joystick.button = jb;
+	dynamic_cast<OSystem_Android *>(g_system)->pushEvent(ev1, ev2);
 }
diff --git a/backends/platform/android/touchcontrols.h b/backends/platform/android/touchcontrols.h
index c5f1cd9bfc..7f2ee494fb 100644
--- a/backends/platform/android/touchcontrols.h
+++ b/backends/platform/android/touchcontrols.h
@@ -81,30 +81,30 @@ private:
 	Pointer *findPointerFromFunction(Function function);
 
 	struct FunctionState {
-		FunctionState() : main(Common::KEYCODE_INVALID),
-			modifier(Common::KEYCODE_INVALID) {}
+		FunctionState() : main(Common::JOYSTICK_BUTTON_INVALID),
+			modifier(Common::JOYSTICK_BUTTON_INVALID) {}
 		void reset() {
-			main = Common::KEYCODE_INVALID;
-			modifier = Common::KEYCODE_INVALID;
+			main = Common::JOYSTICK_BUTTON_INVALID;
+			modifier = Common::JOYSTICK_BUTTON_INVALID;
 			clip = Common::Rect();
 		}
 
-		Common::KeyCode main;
-		Common::KeyCode modifier;
+		Common::JoystickButton main;
+		Common::JoystickButton modifier;
 		Common::Rect clip;
 	};
 
 	FunctionState _functionStates[kFunctionMax + 1];
 
 	GLESTexture *_arrows_texture;
-	void keyDown(Common::KeyCode kc);
-	void keyUp(Common::KeyCode kc);
-	void keyPress(Common::KeyCode kc);
+	void buttonDown(Common::JoystickButton jb);
+	void buttonUp(Common::JoystickButton jb);
+	void buttonPress(Common::JoystickButton jb);
 
 	/* Functions implementations */
 	struct FunctionBehavior {
 		void (*touchToState)(int, int, TouchControls::FunctionState &);
-		bool keyPressOnRelease;
+		bool pressOnRelease;
 		float xRatio;
 		float yRatio;
 	};
diff --git a/dists/android/assets/arrows.tga b/dists/android/assets/arrows.tga
index 1e168d31ec..64a504fe4a 100644
Binary files a/dists/android/assets/arrows.tga and b/dists/android/assets/arrows.tga differ




More information about the Scummvm-git-logs mailing list