[Scummvm-git-logs] scummvm android-3d -> 8614368ee52c30a6646c39d957a0f63fcc8f4f30
lephilousophe
lephilousophe at users.noreply.github.com
Tue Oct 26 11:25:55 UTC 2021
This automated email contains information about 18 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
11da2eed7f OPENGL: Fix compilation with USE_BUILTIN_OPENGL
72b83e416a ANDROID: Switch to GLES2
d42dcfd023 ANDROID: Merge 3D graphics backend
5110b3bcaf ANDROID: Better debug of which graphic backend is used
0afef37200 ANDROID: Implement modes completely to allow switching between 3D and 2D
251fecd70d ANDROID: Use 5551 format for overlay instead of 4444
a25e4c5436 ANDROID: Free frame buffer when it's unused
fa5338a0c7 ANDROID: Fix indentation
18fe55bbb0 ANDROID: Set up scissor box when resizing
3b1fe7a281 ANDROID: Reinitialize some state before stopping 3D manager
b419ffd19f ANDROID: Fix OpenGL debug in 3D backend
c7870682ae ANDROID: Make sure glDrawArrays succeeds
820ce55f36 ANDROID: Disable depth test as we don't use it in final rendering
74d7a3f6ef ANDROID: Introduce back the touch controls for 3D
38e91272c5 ANDROID: Display the game below the overlay menu
ee762d7844 ANDROID: Always enable blending when drawing all the layers
6f41f285c1 ANDROID: Rework 3D screen setup
8614368ee5 ANDROID: Add support for kSupportsArbitraryResolutions in 3D
Commit: 11da2eed7f737ea93ad41d62d958a06e2b2fa2c4
https://github.com/scummvm/scummvm/commit/11da2eed7f737ea93ad41d62d958a06e2b2fa2c4
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: 72b83e416a8e08b6768453043be0f67ee574fd6a
https://github.com/scummvm/scummvm/commit/72b83e416a8e08b6768453043be0f67ee574fd6a
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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 e942c853c4..9a2f8221bb 100755
--- a/configure
+++ b/configure
@@ -5341,8 +5341,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
@@ -5467,7 +5468,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" || test "$_backend" = "raspberrypi"; then
+ if (test "$_backend" = "sdl" && test "$_opengl" = yes) || test "$_backend" = "android" || test "$_backend" = "android3d" \
+ || test "$_backend" = "switch" || test "$_backend" = "raspberrypi"; 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
@@ -6132,7 +6134,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: d42dcfd023303f8c1882d046ee8ea780d8055661
https://github.com/scummvm/scummvm/commit/d42dcfd023303f8c1882d046ee8ea780d8055661
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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 55%
rename from backends/platform/android/graphics.h
rename to backends/graphics/android/android-graphics.h
index 7d35e98766..112dbdd4c8 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;
virtual void updateScreen() override;
virtual 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); }
virtual 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 02082f30c7..152fecd90d 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -226,6 +226,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 499c418773..ce236d0978 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),
@@ -654,4 +687,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 a07f7b5507..0471edd5e9 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 ModularMutexBackend, 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:
virtual bool pollEvent(Common::Event &event) override;
virtual Common::HardwareInputSet *getHardwareInputSet() override;
@@ -144,6 +176,10 @@ public:
virtual bool setTextInClipboard(const Common::U32String &text) override;
virtual bool isConnectionLimited() override;
virtual Common::String getSystemLanguage() const override;
+
+ virtual 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: 5110b3bcaf7e7fb5f941b2b8612d949f02d307e8
https://github.com/scummvm/scummvm/commit/5110b3bcaf7e7fb5f941b2b8612d949f02d307e8
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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 ce236d0978..8a21c0a999 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -705,15 +705,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: 0afef3720006fdd302f96aa74858d721830eee22
https://github.com/scummvm/scummvm/commit/0afef3720006fdd302f96aa74858d721830eee22
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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 8a21c0a999..17cc5a0fb0 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -687,6 +687,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;
@@ -754,4 +769,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 0471edd5e9..e17b0a5382 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -177,7 +177,10 @@ public:
virtual bool isConnectionLimited() override;
virtual Common::String getSystemLanguage() const override;
+ virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
+ virtual int getDefaultGraphicsMode() const override;
virtual bool setGraphicsMode(int mode, uint flags) override;
+ virtual int getGraphicsMode() const override;
void updateEventScale(uint32 w, uint32 h);
};
Commit: 251fecd70d19c506f8008d432805a5dcecb483a0
https://github.com/scummvm/scummvm/commit/251fecd70d19c506f8008d432805a5dcecb483a0
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: a25e4c5436ea082230db1081fe3be8ce5074851c
https://github.com/scummvm/scummvm/commit/a25e4c5436ea082230db1081fe3be8ce5074851c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: fa5338a0c7e9d9bcfd2ef6f3efb9c287d82e0445
https://github.com/scummvm/scummvm/commit/fa5338a0c7e9d9bcfd2ef6f3efb9c287d82e0445
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: 18fe55bbb0febf2d2bdf9165534a36542ec62cb7
https://github.com/scummvm/scummvm/commit/18fe55bbb0febf2d2bdf9165534a36542ec62cb7
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: 3b1fe7a281032eb0742179cd19e10d21ec8b6425
https://github.com/scummvm/scummvm/commit/3b1fe7a281032eb0742179cd19e10d21ec8b6425
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: b419ffd19f04cae17b4a86b1871460808a08fded
https://github.com/scummvm/scummvm/commit/b419ffd19f04cae17b4a86b1871460808a08fded
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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 e17b0a5382..9c2a8dca2e 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
@@ -183,6 +185,9 @@ public:
virtual 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: c7870682ae3f2b8800c9a0c34c258ed338176953
https://github.com/scummvm/scummvm/commit/c7870682ae3f2b8800c9a0c34c258ed338176953
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: 820ce55f36f15f2a022507f592273aba2a363929
https://github.com/scummvm/scummvm/commit/820ce55f36f15f2a022507f592273aba2a363929
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: 74d7a3f6efd21035bc2d0926a6b2a5323f421eab
https://github.com/scummvm/scummvm/commit/74d7a3f6efd21035bc2d0926a6b2a5323f421eab
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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 152fecd90d..dc25b2a896 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -229,7 +229,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 9c2a8dca2e..79da063e9f 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:
virtual bool pollEvent(Common::Event &event) override;
virtual 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: 38e91272c53311c94857b601c176035d93ffe5b0
https://github.com/scummvm/scummvm/commit/38e91272c53311c94857b601c176035d93ffe5b0
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: ee762d7844cb512c133da8f218a4bd297d8066f6
https://github.com/scummvm/scummvm/commit/ee762d7844cb512c133da8f218a4bd297d8066f6
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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: 6f41f285c1783221a09ac83a071ddb1f1dcf7089
https://github.com/scummvm/scummvm/commit/6f41f285c1783221a09ac83a071ddb1f1dcf7089
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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.
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..f044692046 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -51,7 +51,6 @@
AndroidGraphics3dManager::AndroidGraphics3dManager() :
_screenChangeID(0),
_graphicsMode(0),
- _opengl(false),
_fullscreen(true),
_ar_correction(true),
_force_redraw(false),
@@ -517,8 +516,15 @@ 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();
+ // format is not used by the gfx_opengl driver, use fake format
+ _game_pbuf.set(Graphics::PixelFormat(), 0);
}
void AndroidGraphics3dManager::initSizeIntern(uint width, uint height,
@@ -737,32 +743,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 +872,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..d383df08f7 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,7 +143,6 @@ private:
private:
int _screenChangeID;
int _graphicsMode;
- bool _opengl;
bool _fullscreen;
bool _ar_correction;
bool _force_redraw;
Commit: 8614368ee52c30a6646c39d957a0f63fcc8f4f30
https://github.com/scummvm/scummvm/commit/8614368ee52c30a6646c39d957a0f63fcc8f4f30
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2021-10-24T20:29:23+02: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 f044692046..22f9d53548 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -531,6 +531,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
More information about the Scummvm-git-logs
mailing list