aboutsummaryrefslogtreecommitdiff
path: root/backends/platform
diff options
context:
space:
mode:
authordhewg2011-02-20 17:01:46 +0100
committerdhewg2011-02-24 23:18:31 +0100
commit257913676d5a21c6192a6146e662c21f299c9b09 (patch)
tree69799ee15f8b0dfd20c84a0f19f6fe89d3f0cce3 /backends/platform
parentf3ea868cf6b3603e88e0899fef6e71bcc800e481 (diff)
downloadscummvm-rg350-257913676d5a21c6192a6146e662c21f299c9b09.tar.gz
scummvm-rg350-257913676d5a21c6192a6146e662c21f299c9b09.tar.bz2
scummvm-rg350-257913676d5a21c6192a6146e662c21f299c9b09.zip
ANDROID: Split code into multiple files
And get rid of unnecessary JNI calls to get a pointer to g_system
Diffstat (limited to 'backends/platform')
-rw-r--r--backends/platform/android/android.cpp970
-rw-r--r--backends/platform/android/android.h200
-rw-r--r--backends/platform/android/gfx.cpp459
-rw-r--r--backends/platform/android/jni.cpp387
-rw-r--r--backends/platform/android/module.mk6
-rw-r--r--backends/platform/android/texture.cpp (renamed from backends/platform/android/video.cpp)2
-rw-r--r--backends/platform/android/texture.h (renamed from backends/platform/android/video.h)5
7 files changed, 1062 insertions, 967 deletions
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index c49745f8bd..a0a53474e8 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -25,22 +25,10 @@
#if defined(__ANDROID__)
-#include "backends/base-backend.h"
-#include "base/main.h"
-#include "graphics/surface.h"
-
-#include "backends/platform/android/android.h"
-#include "backends/platform/android/video.h"
-
-#include <jni.h>
-
-#include <string.h>
-#include <unistd.h>
-#include <pthread.h>
#include <sys/time.h>
#include <time.h>
+#include <unistd.h>
-#include "common/archive.h"
#include "common/util.h"
#include "common/rect.h"
#include "common/queue.h"
@@ -48,13 +36,11 @@
#include "common/events.h"
#include "common/config-manager.h"
-#include "backends/fs/posix/posix-fs-factory.h"
#include "backends/keymapper/keymapper.h"
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
-#include "backends/plugins/posix/posix-provider.h"
-#include "audio/mixer_intern.h"
+#include "backends/platform/android/android.h"
#include "backends/platform/android/asset-archive.h"
const char *android_log_tag = "ScummVM";
@@ -106,226 +92,13 @@ void checkGlError(const char *expr, const char *file, int line) {
}
#endif
-static JavaVM *cached_jvm;
-static jfieldID FID_Event_type;
-static jfieldID FID_Event_synthetic;
-static jfieldID FID_Event_kbd_keycode;
-static jfieldID FID_Event_kbd_ascii;
-static jfieldID FID_Event_kbd_flags;
-static jfieldID FID_Event_mouse_x;
-static jfieldID FID_Event_mouse_y;
-static jfieldID FID_Event_mouse_relative;
-static jfieldID FID_ScummVM_nativeScummVM;
-static jmethodID MID_Object_wait;
-
-JNIEnv *JNU_GetEnv() {
- JNIEnv *env = 0;
-
- jint res = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2);
-
- if (res != JNI_OK) {
- LOGE("GetEnv() failed: %d", res);
- abort();
- }
-
- return env;
-}
-
-static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) {
- jclass cls = env->FindClass(name);
-
- // if cls is 0, an exception has already been thrown
- if (cls != 0)
- env->ThrowNew(cls, msg);
-
- env->DeleteLocalRef(cls);
-}
-
// floating point. use sparingly
template <class T>
static inline T scalef(T in, float numerator, float denominator) {
return static_cast<float>(in) * numerator / denominator;
}
-static inline GLfixed xdiv(int numerator, int denominator) {
- assert(numerator < (1 << 16));
- return (numerator << 16) / denominator;
-}
-
-#ifdef DYNAMIC_MODULES
-class AndroidPluginProvider : public POSIXPluginProvider {
-protected:
- virtual void addCustomDirectories(Common::FSList &dirs) const;
-};
-#endif
-
-class OSystem_Android : public BaseBackend, public PaletteManager {
-private:
- // back pointer to (java) peer instance
- jobject _back_ptr;
-
- jmethodID MID_displayMessageOnOSD;
- jmethodID MID_setWindowCaption;
- jmethodID MID_initBackend;
- jmethodID MID_audioSampleRate;
- jmethodID MID_showVirtualKeyboard;
- jmethodID MID_getSysArchives;
- jmethodID MID_getPluginDirectories;
- jmethodID MID_setupScummVMSurface;
- jmethodID MID_destroyScummVMSurface;
- jmethodID MID_swapBuffers;
-
- int _screen_changeid;
- int _egl_surface_width;
- int _egl_surface_height;
-
- bool _force_redraw;
-
- // Game layer
- GLESPaletteTexture *_game_texture;
- int _shake_offset;
- Common::Rect _focus_rect;
-
- // Overlay layer
- GLES4444Texture *_overlay_texture;
- bool _show_overlay;
-
- // Mouse layer
- GLESPaletteATexture *_mouse_texture;
- Common::Point _mouse_hotspot;
- int _mouse_targetscale;
- bool _show_mouse;
- bool _use_mouse_palette;
-
- Common::Queue<Common::Event> _event_queue;
- MutexRef _event_queue_lock;
-
- bool _timer_thread_exit;
- pthread_t _timer_thread;
- static void *timerThreadFunc(void *arg);
-
- bool _enable_zoning;
- bool _virtkeybd_on;
-
- Common::SaveFileManager *_savefile;
- Audio::MixerImpl *_mixer;
- Common::TimerManager *_timer;
- FilesystemFactory *_fsFactory;
- Common::Archive *_asset_archive;
- timeval _startTime;
-
- void setupScummVMSurface();
- void destroyScummVMSurface();
- void setupKeymapper();
- void _setCursorPalette(const byte *colors, uint start, uint num);
-
-public:
- OSystem_Android(jobject am);
- virtual ~OSystem_Android();
- bool initJavaHooks(JNIEnv *env, jobject self);
-
- static OSystem_Android *fromJavaObject(JNIEnv *env, jobject obj);
- virtual void initBackend();
- void addPluginDirectories(Common::FSList &dirs) const;
- void enableZoning(bool enable) { _enable_zoning = enable; }
- void setSurfaceSize(int width, int height) {
- _egl_surface_width = width;
- _egl_surface_height = height;
- }
-
- virtual bool hasFeature(Feature f);
- virtual void setFeatureState(Feature f, bool enable);
- virtual bool getFeatureState(Feature f);
- virtual const GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- bool setGraphicsMode(const char *name);
- virtual bool setGraphicsMode(int mode);
- virtual int getGraphicsMode() const;
- virtual void initSize(uint width, uint height,
- const Graphics::PixelFormat *format);
-
- virtual int getScreenChangeID() const {
- return _screen_changeid;
- }
-
- virtual int16 getHeight();
- virtual int16 getWidth();
-
- virtual PaletteManager *getPaletteManager() {
- return this;
- }
-
-protected:
- // PaletteManager API
- virtual void setPalette(const byte *colors, uint start, uint num);
- virtual void grabPalette(byte *colors, uint start, uint num);
-
-public:
- virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
- virtual void updateScreen();
- virtual Graphics::Surface *lockScreen();
- virtual void unlockScreen();
- virtual void setShakePos(int shakeOffset);
- virtual void fillScreen(uint32 col);
- virtual void setFocusRectangle(const Common::Rect& rect);
- virtual void clearFocusRectangle();
-
- virtual void showOverlay();
- virtual void hideOverlay();
- virtual void clearOverlay();
- virtual void grabOverlay(OverlayColor *buf, int pitch);
- virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
- virtual int16 getOverlayHeight();
- virtual int16 getOverlayWidth();
-
- // RGBA 4444
- virtual Graphics::PixelFormat getOverlayFormat() const {
- Graphics::PixelFormat format;
-
- format.bytesPerPixel = 2;
- format.rLoss = 8 - 4;
- format.gLoss = 8 - 4;
- format.bLoss = 8 - 4;
- format.aLoss = 8 - 4;
- format.rShift = 3 * 4;
- format.gShift = 2 * 4;
- format.bShift = 1 * 4;
- format.aShift = 0 * 4;
-
- return format;
- }
-
- virtual bool showMouse(bool visible);
-
- virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format);
- virtual void setCursorPalette(const byte *colors, uint start, uint num);
- virtual void disableCursorPalette(bool disable);
-
- virtual bool pollEvent(Common::Event &event);
- void pushEvent(const Common::Event& event);
- virtual uint32 getMillis();
- virtual void delayMillis(uint msecs);
-
- virtual MutexRef createMutex(void);
- virtual void lockMutex(MutexRef mutex);
- virtual void unlockMutex(MutexRef mutex);
- virtual void deleteMutex(MutexRef mutex);
-
- virtual void quit();
-
- virtual void setWindowCaption(const char *caption);
- virtual void displayMessageOnOSD(const char *msg);
- virtual void showVirtualKeyboard(bool enable);
-
- virtual Common::SaveFileManager *getSavefileManager();
- virtual Audio::Mixer *getMixer();
- virtual void getTimeAndDate(TimeDate &t) const;
- virtual Common::TimerManager *getTimerManager();
- virtual FilesystemFactory *getFilesystemFactory();
- virtual void logMessage(LogMessageType::Type type, const char *message);
- virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
-};
+OSystem_Android *g_sys = 0;
OSystem_Android::OSystem_Android(jobject am) :
_back_ptr(0),
@@ -357,6 +130,7 @@ OSystem_Android::~OSystem_Android() {
destroyScummVMSurface();
JNIEnv *env = JNU_GetEnv();
+ // see below
//env->DeleteWeakGlobalRef(_back_ptr);
env->DeleteGlobalRef(_back_ptr);
@@ -369,14 +143,9 @@ OSystem_Android::~OSystem_Android() {
deleteMutex(_event_queue_lock);
}
-OSystem_Android *OSystem_Android::fromJavaObject(JNIEnv *env, jobject obj) {
- jlong peer = env->GetLongField(obj, FID_ScummVM_nativeScummVM);
- return (OSystem_Android *)peer;
-}
-
bool OSystem_Android::initJavaHooks(JNIEnv *env, jobject self) {
// weak global ref to allow class to be unloaded
- // ... except dalvik doesn't implement NewWeakGlobalRef (yet)
+ // ... except dalvik implements NewWeakGlobalRef only on froyo
//_back_ptr = env->NewWeakGlobalRef(self);
_back_ptr = env->NewGlobalRef(self);
@@ -404,91 +173,11 @@ bool OSystem_Android::initJavaHooks(JNIEnv *env, jobject self) {
return true;
}
-static void ScummVM_create(JNIEnv *env, jobject self, jobject am) {
- OSystem_Android *cpp_obj = new OSystem_Android(am);
-
- // Exception already thrown by initJavaHooks?
- if (!cpp_obj->initJavaHooks(env, self))
- return;
-
- env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)cpp_obj);
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new AndroidPluginProvider());
-#endif
-}
-
-static void ScummVM_nativeDestroy(JNIEnv *env, jobject self) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- delete cpp_obj;
-}
-
-static void ScummVM_audioMixCallback(JNIEnv *env, jobject self,
- jbyteArray jbuf) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- jsize len = env->GetArrayLength(jbuf);
- jbyte *buf = env->GetByteArrayElements(jbuf, 0);
-
- if (buf == 0) {
- warning("Unable to get Java audio byte array. Skipping");
- return;
- }
-
- Audio::MixerImpl *mixer =
- static_cast<Audio::MixerImpl *>(cpp_obj->getMixer());
- assert(mixer);
- mixer->mixCallback(reinterpret_cast<byte *>(buf), len);
-
- env->ReleaseByteArrayElements(jbuf, buf, 0);
-}
-
-static void ScummVM_setConfManInt(JNIEnv *env, jclass cls,
- jstring key_obj, jint value) {
- ENTER("%p, %d", key_obj, (int)value);
-
- const char *key = env->GetStringUTFChars(key_obj, 0);
-
- if (key == 0)
- return;
-
- ConfMan.setInt(key, value);
-
- env->ReleaseStringUTFChars(key_obj, key);
-}
-
-static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj,
- jstring value_obj) {
- ENTER("%p, %p", key_obj, value_obj);
-
- const char *key = env->GetStringUTFChars(key_obj, 0);
-
- if (key == 0)
- return;
-
- const char *value = env->GetStringUTFChars(value_obj, 0);
-
- if (value == 0) {
- env->ReleaseStringUTFChars(key_obj, key);
- return;
- }
-
- ConfMan.set(key, value);
-
- env->ReleaseStringUTFChars(value_obj, value);
- env->ReleaseStringUTFChars(key_obj, key);
-}
-
void *OSystem_Android::timerThreadFunc(void *arg) {
OSystem_Android *system = (OSystem_Android *)arg;
DefaultTimerManager *timer = (DefaultTimerManager *)(system->_timer);
- JNIEnv *env = 0;
- jint res = cached_jvm->AttachCurrentThread(&env, 0);
-
- if (res != JNI_OK) {
- LOGE("AttachCurrentThread() failed: %d", res);
- abort();
- }
+ JNU_AttachThread();
struct timespec tv;
tv.tv_sec = 0;
@@ -499,12 +188,7 @@ void *OSystem_Android::timerThreadFunc(void *arg) {
nanosleep(&tv, 0);
}
- res = cached_jvm->DetachCurrentThread();
-
- if (res != JNI_OK) {
- LOGE("DetachCurrentThread() failed: %d", res);
- abort();
- }
+ JNU_DetachThread();
return 0;
}
@@ -627,430 +311,6 @@ bool OSystem_Android::getFeatureState(Feature f) {
}
}
-const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const {
- static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
- { "default", "Default", 1 },
- { 0, 0, 0 },
- };
-
- return s_supportedGraphicsModes;
-}
-
-
-int OSystem_Android::getDefaultGraphicsMode() const {
- return 1;
-}
-
-bool OSystem_Android::setGraphicsMode(const char *mode) {
- ENTER("%s", mode);
- return true;
-}
-
-bool OSystem_Android::setGraphicsMode(int mode) {
- ENTER("%d", mode);
- return true;
-}
-
-int OSystem_Android::getGraphicsMode() const {
- return 1;
-}
-
-void OSystem_Android::setupScummVMSurface() {
- ENTER();
-
- JNIEnv *env = JNU_GetEnv();
- env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface);
-
- if (env->ExceptionCheck())
- return;
-
- // EGL set up with a new surface. Initialise OpenGLES context.
- GLESTexture::initGLExtensions();
-
- // Turn off anything that looks like 3D ;)
- GLCALL(glDisable(GL_CULL_FACE));
- GLCALL(glDisable(GL_DEPTH_TEST));
- GLCALL(glDisable(GL_LIGHTING));
- GLCALL(glDisable(GL_FOG));
- GLCALL(glDisable(GL_DITHER));
-
- GLCALL(glShadeModel(GL_FLAT));
- GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
-
- GLCALL(glEnable(GL_BLEND));
- GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
-
- GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
- GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
-
- GLCALL(glEnable(GL_TEXTURE_2D));
-
- if (!_game_texture)
- _game_texture = new GLESPaletteTexture();
- else
- _game_texture->reinitGL();
-
- if (!_overlay_texture)
- _overlay_texture = new GLES4444Texture();
- else
- _overlay_texture->reinitGL();
-
- if (!_mouse_texture)
- _mouse_texture = new GLESPaletteATexture();
- else
- _mouse_texture->reinitGL();
-
- GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height));
-
- GLCALL(glMatrixMode(GL_PROJECTION));
- GLCALL(glLoadIdentity());
- GLCALL(glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1));
- GLCALL(glMatrixMode(GL_MODELVIEW));
- GLCALL(glLoadIdentity());
-
- clearFocusRectangle();
-}
-
-void OSystem_Android::destroyScummVMSurface() {
- JNIEnv *env = JNU_GetEnv();
- env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface);
- // Can't use OpenGLES functions after this
-}
-
-void OSystem_Android::initSize(uint width, uint height,
- const Graphics::PixelFormat *format) {
- ENTER("%d, %d, %p", width, height, format);
-
- _game_texture->allocBuffer(width, height);
-
- // Cap at 320x200 or the ScummVM themes abort :/
- GLuint overlay_width = MIN(_egl_surface_width, 320);
- GLuint overlay_height = MIN(_egl_surface_height, 200);
- _overlay_texture->allocBuffer(overlay_width, overlay_height);
-
- // 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->allocBuffer(20, 20);
-}
-
-int16 OSystem_Android::getHeight() {
- return _game_texture->height();
-}
-
-int16 OSystem_Android::getWidth() {
- return _game_texture->width();
-}
-
-void OSystem_Android::setPalette(const byte *colors, uint start, uint num) {
- ENTER("%p, %u, %u", colors, start, num);
-
- if (!_use_mouse_palette)
- _setCursorPalette(colors, start, num);
-
- memcpy(_game_texture->palette() + start * 3, colors, num * 3);
-}
-
-void OSystem_Android::grabPalette(byte *colors, uint start, uint num) {
- ENTER("%p, %u, %u", colors, start, num);
- memcpy(colors, _game_texture->palette_const() + start * 3, num * 3);
-}
-
-void OSystem_Android::copyRectToScreen(const byte *buf, int pitch,
- int x, int y, int w, int h) {
- ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
-
- _game_texture->updateBuffer(x, y, w, h, buf, pitch);
-}
-
-void OSystem_Android::updateScreen() {
- //ENTER();
-
- if (!_force_redraw &&
- !_game_texture->dirty() &&
- !_overlay_texture->dirty() &&
- !_mouse_texture->dirty())
- return;
-
- _force_redraw = false;
-
- GLCALL(glPushMatrix());
-
- if (_shake_offset != 0 ||
- (!_focus_rect.isEmpty() &&
- !Common::Rect(_game_texture->width(),
- _game_texture->height()).contains(_focus_rect))) {
- // These are the only cases where _game_texture doesn't
- // cover the entire screen.
- GLCALL(glClearColorx(0, 0, 0, 1 << 16));
- GLCALL(glClear(GL_COLOR_BUFFER_BIT));
-
- // Move everything up by _shake_offset (game) pixels
- GLCALL(glTranslatex(0, -_shake_offset << 16, 0));
- }
-
- if (_focus_rect.isEmpty()) {
- _game_texture->drawTexture(0, 0,
- _egl_surface_width, _egl_surface_height);
- } else {
- GLCALL(glPushMatrix());
- GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()),
- xdiv(_egl_surface_height, _focus_rect.height()),
- 1 << 16));
- GLCALL(glTranslatex(-_focus_rect.left << 16,
- -_focus_rect.top << 16, 0));
- GLCALL(glScalex(xdiv(_game_texture->width(), _egl_surface_width),
- xdiv(_game_texture->height(), _egl_surface_height),
- 1 << 16));
-
- _game_texture->drawTexture(0, 0,
- _egl_surface_width, _egl_surface_height);
- GLCALL(glPopMatrix());
- }
-
- 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->drawTexture(0, 0,
- _egl_surface_width,
- _egl_surface_height));
- }
-
- if (_show_mouse) {
- GLCALL(glPushMatrix());
-
- // Scale up ScummVM -> OpenGL (pixel) coordinates
- int texwidth, texheight;
-
- if (_show_overlay) {
- texwidth = getOverlayWidth();
- texheight = getOverlayHeight();
- } else {
- texwidth = getWidth();
- texheight = getHeight();
- }
-
- GLCALL(glScalex(xdiv(_egl_surface_width, texwidth),
- xdiv(_egl_surface_height, texheight),
- 1 << 16));
-
- GLCALL(glTranslatex((-_mouse_hotspot.x * cs) << 16,
- (-_mouse_hotspot.y * cs) << 16,
- 0));
-
- // Note the extra half texel to position the mouse in
- // the middle of the x,y square:
- const Common::Point& mouse = getEventManager()->getMousePos();
- GLCALL(glTranslatex((mouse.x << 16) | 1 << 15,
- (mouse.y << 16) | 1 << 15, 0));
-
- GLCALL(glScalex(cs << 16, cs << 16, 1 << 16));
-
- _mouse_texture->drawTexture();
-
- GLCALL(glPopMatrix());
- }
-
- GLCALL(glPopMatrix());
-
- JNIEnv *env = JNU_GetEnv();
- if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) {
- // Context lost -> need to reinit GL
- destroyScummVMSurface();
- setupScummVMSurface();
- }
-}
-
-Graphics::Surface *OSystem_Android::lockScreen() {
- ENTER();
-
- Graphics::Surface *surface = _game_texture->surface();
- assert(surface->pixels);
-
- return surface;
-}
-
-void OSystem_Android::unlockScreen() {
- ENTER();
-
- assert(_game_texture->dirty());
-}
-
-void OSystem_Android::setShakePos(int shake_offset) {
- ENTER("%d", shake_offset);
-
- if (_shake_offset != shake_offset) {
- _shake_offset = shake_offset;
- _force_redraw = true;
- }
-}
-
-void OSystem_Android::fillScreen(uint32 col) {
- ENTER("%u", col);
-
- assert(col < 256);
- _game_texture->fillBuffer(col);
-}
-
-void OSystem_Android::setFocusRectangle(const Common::Rect& rect) {
- ENTER("%d, %d, %d, %d", rect.left, rect.top, rect.right, rect.bottom);
-
- if (_enable_zoning) {
- _focus_rect = rect;
- _force_redraw = true;
- }
-}
-
-void OSystem_Android::clearFocusRectangle() {
- ENTER();
-
- if (_enable_zoning) {
- _focus_rect = Common::Rect();
- _force_redraw = true;
- }
-}
-
-void OSystem_Android::showOverlay() {
- ENTER();
-
- _show_overlay = true;
- _force_redraw = true;
-}
-
-void OSystem_Android::hideOverlay() {
- ENTER();
-
- _show_overlay = false;
- _force_redraw = true;
-}
-
-void OSystem_Android::clearOverlay() {
- ENTER();
-
- _overlay_texture->fillBuffer(0);
-
- // Shouldn't need this, but works around a 'blank screen' bug on Nexus1
- updateScreen();
-}
-
-void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) {
- ENTER("%p, %d", buf, pitch);
-
- // We support overlay alpha blending, so the pixel data here
- // shouldn't actually be used. Let's fill it with zeros, I'm sure
- // it will be fine...
- const Graphics::Surface *surface = _overlay_texture->surface_const();
- assert(surface->bytesPerPixel == sizeof(buf[0]));
-
- int h = surface->h;
-
- do {
- memset(buf, 0, surface->w * sizeof(buf[0]));
-
- // This 'pitch' is pixels not bytes
- buf += pitch;
- } while (--h);
-}
-
-void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch,
- int x, int y, int w, int h) {
- ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
-
- const Graphics::Surface *surface = _overlay_texture->surface_const();
- assert(surface->bytesPerPixel == sizeof(buf[0]));
-
- // This 'pitch' is pixels not bytes
- _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0]));
-
- // Shouldn't need this, but works around a 'blank screen' bug on Nexus1?
- updateScreen();
-}
-
-int16 OSystem_Android::getOverlayHeight() {
- return _overlay_texture->height();
-}
-
-int16 OSystem_Android::getOverlayWidth() {
- return _overlay_texture->width();
-}
-
-bool OSystem_Android::showMouse(bool visible) {
- ENTER("%d", visible);
-
- _show_mouse = visible;
-
- return true;
-}
-
-void OSystem_Android::warpMouse(int x, int y) {
- ENTER("%d, %d", x, y);
-
- // We use only the eventmanager's idea of the current mouse
- // position, so there is nothing extra to do here.
-}
-
-void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,
- int hotspotX, int hotspotY,
- uint32 keycolor, int cursorTargetScale,
- const Graphics::PixelFormat *format) {
- ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
- keycolor, cursorTargetScale, format);
-
- assert(keycolor < 256);
-
- _mouse_texture->allocBuffer(w, h);
-
- // Update palette alpha based on keycolor
- byte *palette = _mouse_texture->palette();
- int i = 256;
-
- do {
- palette[3] = 0xff;
- palette += 4;
- } while (--i);
-
- palette = _mouse_texture->palette();
- palette[keycolor * 4 + 3] = 0x00;
-
- _mouse_texture->updateBuffer(0, 0, w, h, buf, w);
-
- _mouse_hotspot = Common::Point(hotspotX, hotspotY);
- _mouse_targetscale = cursorTargetScale;
-}
-
-void OSystem_Android::_setCursorPalette(const byte *colors,
- uint start, uint num) {
- byte *palette = _mouse_texture->palette() + start * 4;
-
- do {
- for (int i = 0; i < 3; ++i)
- palette[i] = colors[i];
-
- // Leave alpha untouched to preserve keycolor
-
- palette += 4;
- colors += 3;
- } while (--num);
-}
-
-void OSystem_Android::setCursorPalette(const byte *colors,
- uint start, uint num) {
- ENTER("%p, %u, %u", colors, start, num);
-
- _setCursorPalette(colors, start, num);
- _use_mouse_palette = true;
-}
-
-void OSystem_Android::disableCursorPalette(bool disable) {
- ENTER("%d", disable);
-
- _use_mouse_palette = !disable;
-}
-
void OSystem_Android::setupKeymapper() {
#ifdef ENABLE_KEYMAPPER
using namespace Common;
@@ -1168,52 +428,6 @@ void OSystem_Android::pushEvent(const Common::Event& event) {
unlockMutex(_event_queue_lock);
}
-static void ScummVM_pushEvent(JNIEnv *env, jobject self, jobject java_event) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
-
- Common::Event event;
- event.type = (Common::EventType)env->GetIntField(java_event,
- FID_Event_type);
-
- event.synthetic =
- env->GetBooleanField(java_event, FID_Event_synthetic);
-
- switch (event.type) {
- case Common::EVENT_KEYDOWN:
- case Common::EVENT_KEYUP:
- event.kbd.keycode = (Common::KeyCode)env->GetIntField(
- java_event, FID_Event_kbd_keycode);
- event.kbd.ascii = static_cast<int>(env->GetIntField(
- java_event, FID_Event_kbd_ascii));
- event.kbd.flags = static_cast<int>(env->GetIntField(
- java_event, FID_Event_kbd_flags));
- break;
- case Common::EVENT_MOUSEMOVE:
- case Common::EVENT_LBUTTONDOWN:
- case Common::EVENT_LBUTTONUP:
- case Common::EVENT_RBUTTONDOWN:
- case Common::EVENT_RBUTTONUP:
- case Common::EVENT_WHEELUP:
- case Common::EVENT_WHEELDOWN:
- case Common::EVENT_MBUTTONDOWN:
- case Common::EVENT_MBUTTONUP:
- event.mouse.x =
- env->GetIntField(java_event, FID_Event_mouse_x);
- event.mouse.y =
- env->GetIntField(java_event, FID_Event_mouse_y);
- // This is a terrible hack. We stash "relativeness"
- // in the kbd.flags field until pollEvent() can work
- // it out.
- event.kbd.flags = env->GetBooleanField(
- java_event, FID_Event_mouse_relative) ? 1 : 0;
- break;
- default:
- break;
- }
-
- cpp_obj->pushEvent(event);
-}
-
uint32 OSystem_Android::getMillis() {
timeval curTime;
@@ -1401,177 +615,11 @@ void OSystem_Android::logMessage(LogMessageType::Type type, const char *message)
}
}
-static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
-
- const int MAX_NARGS = 32;
- int res = -1;
-
- int argc = env->GetArrayLength(args);
- if (argc > MAX_NARGS) {
- JNU_ThrowByName(env, "java/lang/IllegalArgumentException",
- "too many arguments");
- return 0;
- }
-
- char *argv[MAX_NARGS];
-
- // note use in cleanup loop below
- int nargs;
-
- for (nargs = 0; nargs < argc; ++nargs) {
- jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
-
- if (arg == 0) {
- argv[nargs] = 0;
- } else {
- const char *cstr = env->GetStringUTFChars(arg, 0);
-
- argv[nargs] = const_cast<char *>(cstr);
-
- // exception already thrown?
- if (cstr == 0)
- goto cleanup;
- }
-
- env->DeleteLocalRef(arg);
- }
-
- g_system = cpp_obj;
- assert(g_system);
-
- LOGI("Entering scummvm_main with %d args", argc);
-
- res = scummvm_main(argc, argv);
-
- LOGI("Exiting scummvm_main");
-
- g_system->quit();
-
-cleanup:
- nargs--;
-
- for (int i = 0; i < nargs; ++i) {
- if (argv[i] == 0)
- continue;
-
- jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
-
- // Exception already thrown?
- if (arg == 0)
- return res;
-
- env->ReleaseStringUTFChars(arg, argv[i]);
- env->DeleteLocalRef(arg);
- }
-
- return res;
-}
-
#ifdef DYNAMIC_MODULES
void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const {
- OSystem_Android *g_system_android = (OSystem_Android *)g_system;
- g_system_android->addPluginDirectories(dirs);
+ g_sys->addPluginDirectories(dirs);
}
#endif
-static void ScummVM_enableZoning(JNIEnv *env, jobject self, jboolean enable) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- cpp_obj->enableZoning(enable);
-}
-
-static void ScummVM_setSurfaceSize(JNIEnv *env, jobject self,
- jint width, jint height) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- cpp_obj->setSurfaceSize(width, height);
-}
-
-const static JNINativeMethod gMethods[] = {
- { "create", "(Landroid/content/res/AssetManager;)V",
- (void *)ScummVM_create },
- { "nativeDestroy", "()V",
- (void *)ScummVM_nativeDestroy },
- { "scummVMMain", "([Ljava/lang/String;)I",
- (void *)ScummVM_scummVMMain },
- { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V",
- (void *)ScummVM_pushEvent },
- { "audioMixCallback", "([B)V",
- (void *)ScummVM_audioMixCallback },
- { "setConfMan", "(Ljava/lang/String;I)V",
- (void *)ScummVM_setConfManInt },
- { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V",
- (void *)ScummVM_setConfManString },
- { "enableZoning", "(Z)V",
- (void *)ScummVM_enableZoning },
- { "setSurfaceSize", "(II)V",
- (void *)ScummVM_setSurfaceSize },
-};
-
-JNIEXPORT jint JNICALL
-JNI_OnLoad(JavaVM *jvm, void *reserved) {
- cached_jvm = jvm;
-
- JNIEnv *env;
-
- if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2))
- return JNI_ERR;
-
- jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM");
- if (cls == 0)
- return JNI_ERR;
-
- if (env->RegisterNatives(cls, gMethods, ARRAYSIZE(gMethods)) < 0)
- return JNI_ERR;
-
- FID_ScummVM_nativeScummVM = env->GetFieldID(cls, "nativeScummVM", "J");
- if (FID_ScummVM_nativeScummVM == 0)
- return JNI_ERR;
-
- jclass event = env->FindClass("org/inodes/gus/scummvm/Event");
- if (event == 0)
- return JNI_ERR;
-
- FID_Event_type = env->GetFieldID(event, "type", "I");
- if (FID_Event_type == 0)
- return JNI_ERR;
-
- FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z");
- if (FID_Event_synthetic == 0)
- return JNI_ERR;
-
- FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I");
- if (FID_Event_kbd_keycode == 0)
- return JNI_ERR;
-
- FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I");
- if (FID_Event_kbd_ascii == 0)
- return JNI_ERR;
-
- FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I");
- if (FID_Event_kbd_flags == 0)
- return JNI_ERR;
-
- FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I");
- if (FID_Event_mouse_x == 0)
- return JNI_ERR;
-
- FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I");
- if (FID_Event_mouse_y == 0)
- return JNI_ERR;
-
- FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z");
- if (FID_Event_mouse_relative == 0)
- return JNI_ERR;
-
- cls = env->FindClass("java/lang/Object");
- if (cls == 0)
- return JNI_ERR;
-
- MID_Object_wait = env->GetMethodID(cls, "wait", "()V");
- if (MID_Object_wait == 0)
- return JNI_ERR;
-
- return JNI_VERSION_1_2;
-}
-
#endif
+
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 855fb04b5d..b31c0fd385 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -23,8 +23,24 @@
*
*/
+#ifndef _ANDROID_H_
+#define _ANDROID_H_
+
#if defined(__ANDROID__)
+#include "common/fs.h"
+#include "common/archive.h"
+#include "audio/mixer_intern.h"
+#include "graphics/surface.h"
+#include "backends/base-backend.h"
+#include "backends/plugins/posix/posix-provider.h"
+#include "backends/fs/posix/posix-fs-factory.h"
+
+#include "backends/platform/android/texture.h"
+
+#include <pthread.h>
+
+#include <jni.h>
#include <android/log.h>
#include <GLES/gl.h>
@@ -62,9 +78,187 @@ extern void checkGlError(const char *expr, const char *file, int line);
#define GLCALL(x) do { (x); } while (false)
#endif
-// Fix JNIEXPORT declaration to actually do something useful
-#undef JNIEXPORT
-#define JNIEXPORT __attribute__ ((visibility("default")))
+extern JNIEnv *JNU_GetEnv();
+extern void JNU_AttachThread();
+extern void JNU_DetachThread();
+
+class OSystem_Android;
+extern OSystem_Android *g_sys;
+
+#ifdef DYNAMIC_MODULES
+class AndroidPluginProvider : public POSIXPluginProvider {
+protected:
+ virtual void addCustomDirectories(Common::FSList &dirs) const;
+};
+#endif
+
+class OSystem_Android : public BaseBackend, public PaletteManager {
+private:
+ // back pointer to (java) peer instance
+ jobject _back_ptr;
+
+ jmethodID MID_displayMessageOnOSD;
+ jmethodID MID_setWindowCaption;
+ jmethodID MID_initBackend;
+ jmethodID MID_audioSampleRate;
+ jmethodID MID_showVirtualKeyboard;
+ jmethodID MID_getSysArchives;
+ jmethodID MID_getPluginDirectories;
+ jmethodID MID_setupScummVMSurface;
+ jmethodID MID_destroyScummVMSurface;
+ jmethodID MID_swapBuffers;
+
+ int _screen_changeid;
+ int _egl_surface_width;
+ int _egl_surface_height;
+
+ bool _force_redraw;
+
+ // Game layer
+ GLESPaletteTexture *_game_texture;
+ int _shake_offset;
+ Common::Rect _focus_rect;
+
+ // Overlay layer
+ GLES4444Texture *_overlay_texture;
+ bool _show_overlay;
+
+ // Mouse layer
+ GLESPaletteATexture *_mouse_texture;
+ Common::Point _mouse_hotspot;
+ int _mouse_targetscale;
+ bool _show_mouse;
+ bool _use_mouse_palette;
+
+ Common::Queue<Common::Event> _event_queue;
+ MutexRef _event_queue_lock;
+
+ bool _timer_thread_exit;
+ pthread_t _timer_thread;
+ static void *timerThreadFunc(void *arg);
+
+ bool _enable_zoning;
+ bool _virtkeybd_on;
+
+ Common::SaveFileManager *_savefile;
+ Audio::MixerImpl *_mixer;
+ Common::TimerManager *_timer;
+ FilesystemFactory *_fsFactory;
+ Common::Archive *_asset_archive;
+ timeval _startTime;
+
+ void setupScummVMSurface();
+ void destroyScummVMSurface();
+ void setupKeymapper();
+ void _setCursorPalette(const byte *colors, uint start, uint num);
+
+public:
+ OSystem_Android(jobject am);
+ virtual ~OSystem_Android();
+ bool initJavaHooks(JNIEnv *env, jobject self);
+ virtual void initBackend();
+ void addPluginDirectories(Common::FSList &dirs) const;
+ void enableZoning(bool enable) { _enable_zoning = enable; }
+ void setSurfaceSize(int width, int height) {
+ _egl_surface_width = width;
+ _egl_surface_height = height;
+ }
+
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+ virtual const GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ bool setGraphicsMode(const char *name);
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+ virtual void initSize(uint width, uint height,
+ const Graphics::PixelFormat *format);
+
+ virtual int getScreenChangeID() const {
+ return _screen_changeid;
+ }
+
+ virtual int16 getHeight();
+ virtual int16 getWidth();
+
+ virtual PaletteManager *getPaletteManager() {
+ return this;
+ }
+
+protected:
+ // PaletteManager API
+ virtual void setPalette(const byte *colors, uint start, uint num);
+ virtual void grabPalette(byte *colors, uint start, uint num);
+
+public:
+ virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
+ virtual void updateScreen();
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+ virtual void setShakePos(int shakeOffset);
+ virtual void fillScreen(uint32 col);
+ virtual void setFocusRectangle(const Common::Rect& rect);
+ virtual void clearFocusRectangle();
+
+ virtual void showOverlay();
+ virtual void hideOverlay();
+ virtual void clearOverlay();
+ virtual void grabOverlay(OverlayColor *buf, int pitch);
+ virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+ virtual int16 getOverlayHeight();
+ virtual int16 getOverlayWidth();
+
+ // RGBA 4444
+ virtual Graphics::PixelFormat getOverlayFormat() const {
+ Graphics::PixelFormat format;
+
+ format.bytesPerPixel = 2;
+ format.rLoss = 8 - 4;
+ format.gLoss = 8 - 4;
+ format.bLoss = 8 - 4;
+ format.aLoss = 8 - 4;
+ format.rShift = 3 * 4;
+ format.gShift = 2 * 4;
+ format.bShift = 1 * 4;
+ format.aShift = 0 * 4;
+
+ return format;
+ }
+
+ virtual bool showMouse(bool visible);
+
+ virtual void warpMouse(int x, int y);
+ virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format);
+ virtual void setCursorPalette(const byte *colors, uint start, uint num);
+ virtual void disableCursorPalette(bool disable);
+
+ virtual bool pollEvent(Common::Event &event);
+ void pushEvent(const Common::Event& event);
+ virtual uint32 getMillis();
+ virtual void delayMillis(uint msecs);
+
+ virtual MutexRef createMutex(void);
+ virtual void lockMutex(MutexRef mutex);
+ virtual void unlockMutex(MutexRef mutex);
+ virtual void deleteMutex(MutexRef mutex);
+
+ virtual void quit();
+
+ virtual void setWindowCaption(const char *caption);
+ virtual void displayMessageOnOSD(const char *msg);
+ virtual void showVirtualKeyboard(bool enable);
+
+ virtual Common::SaveFileManager *getSavefileManager();
+ virtual Audio::Mixer *getMixer();
+ virtual void getTimeAndDate(TimeDate &t) const;
+ virtual Common::TimerManager *getTimerManager();
+ virtual FilesystemFactory *getFilesystemFactory();
+ virtual void logMessage(LogMessageType::Type type, const char *message);
+ virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
+};
+
+#endif
#endif
diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp
new file mode 100644
index 0000000000..eb5a66c6d9
--- /dev/null
+++ b/backends/platform/android/gfx.cpp
@@ -0,0 +1,459 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(__ANDROID__)
+
+#include "backends/platform/android/android.h"
+
+static inline GLfixed xdiv(int numerator, int denominator) {
+ assert(numerator < (1 << 16));
+ return (numerator << 16) / denominator;
+}
+
+const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const {
+ static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+ { "default", "Default", 1 },
+ { 0, 0, 0 },
+ };
+
+ return s_supportedGraphicsModes;
+}
+
+int OSystem_Android::getDefaultGraphicsMode() const {
+ return 1;
+}
+
+bool OSystem_Android::setGraphicsMode(const char *mode) {
+ ENTER("%s", mode);
+ return true;
+}
+
+bool OSystem_Android::setGraphicsMode(int mode) {
+ ENTER("%d", mode);
+ return true;
+}
+
+int OSystem_Android::getGraphicsMode() const {
+ return 1;
+}
+
+void OSystem_Android::setupScummVMSurface() {
+ ENTER();
+
+ JNIEnv *env = JNU_GetEnv();
+ env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface);
+
+ if (env->ExceptionCheck())
+ return;
+
+ // EGL set up with a new surface. Initialise OpenGLES context.
+ GLESTexture::initGLExtensions();
+
+ // Turn off anything that looks like 3D ;)
+ GLCALL(glDisable(GL_CULL_FACE));
+ GLCALL(glDisable(GL_DEPTH_TEST));
+ GLCALL(glDisable(GL_LIGHTING));
+ GLCALL(glDisable(GL_FOG));
+ GLCALL(glDisable(GL_DITHER));
+
+ GLCALL(glShadeModel(GL_FLAT));
+ GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
+
+ GLCALL(glEnable(GL_BLEND));
+ GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+
+ GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
+ GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+
+ GLCALL(glEnable(GL_TEXTURE_2D));
+
+ if (!_game_texture)
+ _game_texture = new GLESPaletteTexture();
+ else
+ _game_texture->reinitGL();
+
+ if (!_overlay_texture)
+ _overlay_texture = new GLES4444Texture();
+ else
+ _overlay_texture->reinitGL();
+
+ if (!_mouse_texture)
+ _mouse_texture = new GLESPaletteATexture();
+ else
+ _mouse_texture->reinitGL();
+
+ GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height));
+
+ GLCALL(glMatrixMode(GL_PROJECTION));
+ GLCALL(glLoadIdentity());
+ GLCALL(glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1));
+ GLCALL(glMatrixMode(GL_MODELVIEW));
+ GLCALL(glLoadIdentity());
+
+ clearFocusRectangle();
+}
+
+void OSystem_Android::destroyScummVMSurface() {
+ JNIEnv *env = JNU_GetEnv();
+ env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface);
+ // Can't use OpenGLES functions after this
+}
+
+void OSystem_Android::initSize(uint width, uint height,
+ const Graphics::PixelFormat *format) {
+ ENTER("%d, %d, %p", width, height, format);
+
+ _game_texture->allocBuffer(width, height);
+
+ // Cap at 320x200 or the ScummVM themes abort :/
+ GLuint overlay_width = MIN(_egl_surface_width, 320);
+ GLuint overlay_height = MIN(_egl_surface_height, 200);
+ _overlay_texture->allocBuffer(overlay_width, overlay_height);
+
+ // 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->allocBuffer(20, 20);
+}
+
+int16 OSystem_Android::getHeight() {
+ return _game_texture->height();
+}
+
+int16 OSystem_Android::getWidth() {
+ return _game_texture->width();
+}
+
+void OSystem_Android::setPalette(const byte *colors, uint start, uint num) {
+ ENTER("%p, %u, %u", colors, start, num);
+
+ if (!_use_mouse_palette)
+ _setCursorPalette(colors, start, num);
+
+ memcpy(_game_texture->palette() + start * 3, colors, num * 3);
+}
+
+void OSystem_Android::grabPalette(byte *colors, uint start, uint num) {
+ ENTER("%p, %u, %u", colors, start, num);
+ memcpy(colors, _game_texture->palette_const() + start * 3, num * 3);
+}
+
+void OSystem_Android::copyRectToScreen(const byte *buf, int pitch,
+ int x, int y, int w, int h) {
+ ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
+
+ _game_texture->updateBuffer(x, y, w, h, buf, pitch);
+}
+
+void OSystem_Android::updateScreen() {
+ //ENTER();
+
+ if (!_force_redraw &&
+ !_game_texture->dirty() &&
+ !_overlay_texture->dirty() &&
+ !_mouse_texture->dirty())
+ return;
+
+ _force_redraw = false;
+
+ GLCALL(glPushMatrix());
+
+ if (_shake_offset != 0 ||
+ (!_focus_rect.isEmpty() &&
+ !Common::Rect(_game_texture->width(),
+ _game_texture->height()).contains(_focus_rect))) {
+ // These are the only cases where _game_texture doesn't
+ // cover the entire screen.
+ GLCALL(glClearColorx(0, 0, 0, 1 << 16));
+ GLCALL(glClear(GL_COLOR_BUFFER_BIT));
+
+ // Move everything up by _shake_offset (game) pixels
+ GLCALL(glTranslatex(0, -_shake_offset << 16, 0));
+ }
+
+ if (_focus_rect.isEmpty()) {
+ _game_texture->drawTexture(0, 0,
+ _egl_surface_width, _egl_surface_height);
+ } else {
+ GLCALL(glPushMatrix());
+ GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()),
+ xdiv(_egl_surface_height, _focus_rect.height()),
+ 1 << 16));
+ GLCALL(glTranslatex(-_focus_rect.left << 16,
+ -_focus_rect.top << 16, 0));
+ GLCALL(glScalex(xdiv(_game_texture->width(), _egl_surface_width),
+ xdiv(_game_texture->height(), _egl_surface_height),
+ 1 << 16));
+
+ _game_texture->drawTexture(0, 0,
+ _egl_surface_width, _egl_surface_height);
+ GLCALL(glPopMatrix());
+ }
+
+ 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->drawTexture(0, 0,
+ _egl_surface_width,
+ _egl_surface_height));
+ }
+
+ if (_show_mouse) {
+ GLCALL(glPushMatrix());
+
+ // Scale up ScummVM -> OpenGL (pixel) coordinates
+ int texwidth, texheight;
+
+ if (_show_overlay) {
+ texwidth = getOverlayWidth();
+ texheight = getOverlayHeight();
+ } else {
+ texwidth = getWidth();
+ texheight = getHeight();
+ }
+
+ GLCALL(glScalex(xdiv(_egl_surface_width, texwidth),
+ xdiv(_egl_surface_height, texheight),
+ 1 << 16));
+
+ GLCALL(glTranslatex((-_mouse_hotspot.x * cs) << 16,
+ (-_mouse_hotspot.y * cs) << 16,
+ 0));
+
+ // Note the extra half texel to position the mouse in
+ // the middle of the x,y square:
+ const Common::Point& mouse = getEventManager()->getMousePos();
+ GLCALL(glTranslatex((mouse.x << 16) | 1 << 15,
+ (mouse.y << 16) | 1 << 15, 0));
+
+ GLCALL(glScalex(cs << 16, cs << 16, 1 << 16));
+
+ _mouse_texture->drawTexture();
+
+ GLCALL(glPopMatrix());
+ }
+
+ GLCALL(glPopMatrix());
+
+ JNIEnv *env = JNU_GetEnv();
+ if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) {
+ // Context lost -> need to reinit GL
+ destroyScummVMSurface();
+ setupScummVMSurface();
+ }
+}
+
+Graphics::Surface *OSystem_Android::lockScreen() {
+ ENTER();
+
+ Graphics::Surface *surface = _game_texture->surface();
+ assert(surface->pixels);
+
+ return surface;
+}
+
+void OSystem_Android::unlockScreen() {
+ ENTER();
+
+ assert(_game_texture->dirty());
+}
+
+void OSystem_Android::setShakePos(int shake_offset) {
+ ENTER("%d", shake_offset);
+
+ if (_shake_offset != shake_offset) {
+ _shake_offset = shake_offset;
+ _force_redraw = true;
+ }
+}
+
+void OSystem_Android::fillScreen(uint32 col) {
+ ENTER("%u", col);
+
+ assert(col < 256);
+ _game_texture->fillBuffer(col);
+}
+
+void OSystem_Android::setFocusRectangle(const Common::Rect& rect) {
+ ENTER("%d, %d, %d, %d", rect.left, rect.top, rect.right, rect.bottom);
+
+ if (_enable_zoning) {
+ _focus_rect = rect;
+ _force_redraw = true;
+ }
+}
+
+void OSystem_Android::clearFocusRectangle() {
+ ENTER();
+
+ if (_enable_zoning) {
+ _focus_rect = Common::Rect();
+ _force_redraw = true;
+ }
+}
+
+void OSystem_Android::showOverlay() {
+ ENTER();
+
+ _show_overlay = true;
+ _force_redraw = true;
+}
+
+void OSystem_Android::hideOverlay() {
+ ENTER();
+
+ _show_overlay = false;
+ _force_redraw = true;
+}
+
+void OSystem_Android::clearOverlay() {
+ ENTER();
+
+ _overlay_texture->fillBuffer(0);
+
+ // Shouldn't need this, but works around a 'blank screen' bug on Nexus1
+ updateScreen();
+}
+
+void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) {
+ ENTER("%p, %d", buf, pitch);
+
+ // We support overlay alpha blending, so the pixel data here
+ // shouldn't actually be used. Let's fill it with zeros, I'm sure
+ // it will be fine...
+ const Graphics::Surface *surface = _overlay_texture->surface_const();
+ assert(surface->bytesPerPixel == sizeof(buf[0]));
+
+ int h = surface->h;
+
+ do {
+ memset(buf, 0, surface->w * sizeof(buf[0]));
+
+ // This 'pitch' is pixels not bytes
+ buf += pitch;
+ } while (--h);
+}
+
+void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch,
+ int x, int y, int w, int h) {
+ ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
+
+ const Graphics::Surface *surface = _overlay_texture->surface_const();
+ assert(surface->bytesPerPixel == sizeof(buf[0]));
+
+ // This 'pitch' is pixels not bytes
+ _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0]));
+
+ // Shouldn't need this, but works around a 'blank screen' bug on Nexus1?
+ updateScreen();
+}
+
+int16 OSystem_Android::getOverlayHeight() {
+ return _overlay_texture->height();
+}
+
+int16 OSystem_Android::getOverlayWidth() {
+ return _overlay_texture->width();
+}
+
+bool OSystem_Android::showMouse(bool visible) {
+ ENTER("%d", visible);
+
+ _show_mouse = visible;
+
+ return true;
+}
+
+void OSystem_Android::warpMouse(int x, int y) {
+ ENTER("%d, %d", x, y);
+
+ // We use only the eventmanager's idea of the current mouse
+ // position, so there is nothing extra to do here.
+}
+
+void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,
+ int hotspotX, int hotspotY,
+ uint32 keycolor, int cursorTargetScale,
+ const Graphics::PixelFormat *format) {
+ ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
+ keycolor, cursorTargetScale, format);
+
+ assert(keycolor < 256);
+
+ _mouse_texture->allocBuffer(w, h);
+
+ // Update palette alpha based on keycolor
+ byte *palette = _mouse_texture->palette();
+ int i = 256;
+
+ do {
+ palette[3] = 0xff;
+ palette += 4;
+ } while (--i);
+
+ palette = _mouse_texture->palette();
+ palette[keycolor * 4 + 3] = 0x00;
+
+ _mouse_texture->updateBuffer(0, 0, w, h, buf, w);
+
+ _mouse_hotspot = Common::Point(hotspotX, hotspotY);
+ _mouse_targetscale = cursorTargetScale;
+}
+
+void OSystem_Android::_setCursorPalette(const byte *colors,
+ uint start, uint num) {
+ byte *palette = _mouse_texture->palette() + start * 4;
+
+ do {
+ for (int i = 0; i < 3; ++i)
+ palette[i] = colors[i];
+
+ // Leave alpha untouched to preserve keycolor
+
+ palette += 4;
+ colors += 3;
+ } while (--num);
+}
+
+void OSystem_Android::setCursorPalette(const byte *colors,
+ uint start, uint num) {
+ ENTER("%p, %u, %u", colors, start, num);
+
+ _setCursorPalette(colors, start, num);
+ _use_mouse_palette = true;
+}
+
+void OSystem_Android::disableCursorPalette(bool disable) {
+ ENTER("%d", disable);
+
+ _use_mouse_palette = !disable;
+}
+
+#endif
+
diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp
new file mode 100644
index 0000000000..0f1366148f
--- /dev/null
+++ b/backends/platform/android/jni.cpp
@@ -0,0 +1,387 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(__ANDROID__)
+
+#include "base/main.h"
+#include "common/config-manager.h"
+
+#include "backends/platform/android/android.h"
+
+// Fix JNIEXPORT declaration to actually do something useful
+#undef JNIEXPORT
+#define JNIEXPORT __attribute__ ((visibility("default")))
+
+static JavaVM *cached_jvm;
+static jfieldID FID_Event_type;
+static jfieldID FID_Event_synthetic;
+static jfieldID FID_Event_kbd_keycode;
+static jfieldID FID_Event_kbd_ascii;
+static jfieldID FID_Event_kbd_flags;
+static jfieldID FID_Event_mouse_x;
+static jfieldID FID_Event_mouse_y;
+static jfieldID FID_Event_mouse_relative;
+static jfieldID FID_ScummVM_nativeScummVM;
+static jmethodID MID_Object_wait;
+
+JNIEnv *JNU_GetEnv() {
+ JNIEnv *env = 0;
+
+ jint res = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2);
+
+ if (res != JNI_OK) {
+ LOGE("GetEnv() failed: %d", res);
+ abort();
+ }
+
+ return env;
+}
+
+void JNU_AttachThread() {
+ JNIEnv *env = 0;
+ jint res = cached_jvm->AttachCurrentThread(&env, 0);
+
+ if (res != JNI_OK) {
+ LOGE("AttachCurrentThread() failed: %d", res);
+ abort();
+ }
+}
+
+void JNU_DetachThread() {
+ jint res = cached_jvm->DetachCurrentThread();
+
+ if (res != JNI_OK) {
+ LOGE("DetachCurrentThread() failed: %d", res);
+ abort();
+ }
+}
+
+static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) {
+ jclass cls = env->FindClass(name);
+
+ // if cls is 0, an exception has already been thrown
+ if (cls != 0)
+ env->ThrowNew(cls, msg);
+
+ env->DeleteLocalRef(cls);
+}
+
+static void ScummVM_create(JNIEnv *env, jobject self, jobject am) {
+ assert(!g_system);
+
+ g_sys = new OSystem_Android(am);
+ assert(g_sys);
+
+ // Exception already thrown by initJavaHooks?
+ if (!g_sys->initJavaHooks(env, self))
+ return;
+
+ env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)g_sys);
+
+ g_system = g_sys;
+}
+
+static void ScummVM_nativeDestroy(JNIEnv *env, jobject self) {
+ assert(g_sys);
+
+ OSystem_Android *tmp = g_sys;
+ g_system = 0;
+ g_sys = 0;
+ delete tmp;
+}
+
+static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) {
+ assert(g_sys);
+
+ const int MAX_NARGS = 32;
+ int res = -1;
+
+ int argc = env->GetArrayLength(args);
+ if (argc > MAX_NARGS) {
+ JNU_ThrowByName(env, "java/lang/IllegalArgumentException",
+ "too many arguments");
+ return 0;
+ }
+
+ char *argv[MAX_NARGS];
+
+ // note use in cleanup loop below
+ int nargs;
+
+ for (nargs = 0; nargs < argc; ++nargs) {
+ jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
+
+ if (arg == 0) {
+ argv[nargs] = 0;
+ } else {
+ const char *cstr = env->GetStringUTFChars(arg, 0);
+
+ argv[nargs] = const_cast<char *>(cstr);
+
+ // exception already thrown?
+ if (cstr == 0)
+ goto cleanup;
+ }
+
+ env->DeleteLocalRef(arg);
+ }
+
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new AndroidPluginProvider());
+#endif
+
+ LOGI("Entering scummvm_main with %d args", argc);
+
+ res = scummvm_main(argc, argv);
+
+ LOGI("Exiting scummvm_main");
+
+ g_sys->quit();
+
+cleanup:
+ nargs--;
+
+ for (int i = 0; i < nargs; ++i) {
+ if (argv[i] == 0)
+ continue;
+
+ jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
+
+ // Exception already thrown?
+ if (arg == 0)
+ return res;
+
+ env->ReleaseStringUTFChars(arg, argv[i]);
+ env->DeleteLocalRef(arg);
+ }
+
+ return res;
+}
+
+static void ScummVM_pushEvent(JNIEnv *env, jobject self, jobject java_event) {
+ assert(g_sys);
+
+ Common::Event event;
+ event.type = (Common::EventType)env->GetIntField(java_event,
+ FID_Event_type);
+
+ event.synthetic =
+ env->GetBooleanField(java_event, FID_Event_synthetic);
+
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYUP:
+ event.kbd.keycode = (Common::KeyCode)env->GetIntField(
+ java_event, FID_Event_kbd_keycode);
+ event.kbd.ascii = static_cast<int>(env->GetIntField(
+ java_event, FID_Event_kbd_ascii));
+ event.kbd.flags = static_cast<int>(env->GetIntField(
+ java_event, FID_Event_kbd_flags));
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ case Common::EVENT_MBUTTONDOWN:
+ case Common::EVENT_MBUTTONUP:
+ event.mouse.x =
+ env->GetIntField(java_event, FID_Event_mouse_x);
+ event.mouse.y =
+ env->GetIntField(java_event, FID_Event_mouse_y);
+ // This is a terrible hack. We stash "relativeness"
+ // in the kbd.flags field until pollEvent() can work
+ // it out.
+ event.kbd.flags = env->GetBooleanField(
+ java_event, FID_Event_mouse_relative) ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+
+ g_sys->pushEvent(event);
+}
+
+static void ScummVM_audioMixCallback(JNIEnv *env, jobject self,
+ jbyteArray jbuf) {
+ assert(g_sys);
+
+ jsize len = env->GetArrayLength(jbuf);
+ jbyte *buf = env->GetByteArrayElements(jbuf, 0);
+
+ if (buf == 0) {
+ warning("Unable to get Java audio byte array. Skipping");
+ return;
+ }
+
+ Audio::MixerImpl *mixer =
+ static_cast<Audio::MixerImpl *>(g_sys->getMixer());
+ assert(mixer);
+ mixer->mixCallback(reinterpret_cast<byte *>(buf), len);
+
+ env->ReleaseByteArrayElements(jbuf, buf, 0);
+}
+
+static void ScummVM_setConfManInt(JNIEnv *env, jclass cls,
+ jstring key_obj, jint value) {
+ ENTER("%p, %d", key_obj, (int)value);
+
+ const char *key = env->GetStringUTFChars(key_obj, 0);
+
+ if (key == 0)
+ return;
+
+ ConfMan.setInt(key, value);
+
+ env->ReleaseStringUTFChars(key_obj, key);
+}
+
+static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj,
+ jstring value_obj) {
+ ENTER("%p, %p", key_obj, value_obj);
+
+ const char *key = env->GetStringUTFChars(key_obj, 0);
+
+ if (key == 0)
+ return;
+
+ const char *value = env->GetStringUTFChars(value_obj, 0);
+
+ if (value == 0) {
+ env->ReleaseStringUTFChars(key_obj, key);
+ return;
+ }
+
+ ConfMan.set(key, value);
+
+ env->ReleaseStringUTFChars(value_obj, value);
+ env->ReleaseStringUTFChars(key_obj, key);
+}
+
+static void ScummVM_enableZoning(JNIEnv *env, jobject self, jboolean enable) {
+ assert(g_sys);
+
+ g_sys->enableZoning(enable);
+}
+
+static void ScummVM_setSurfaceSize(JNIEnv *env, jobject self,
+ jint width, jint height) {
+ assert(g_sys);
+
+ g_sys->setSurfaceSize(width, height);
+}
+
+const static JNINativeMethod gMethods[] = {
+ { "create", "(Landroid/content/res/AssetManager;)V",
+ (void *)ScummVM_create },
+ { "nativeDestroy", "()V",
+ (void *)ScummVM_nativeDestroy },
+ { "scummVMMain", "([Ljava/lang/String;)I",
+ (void *)ScummVM_scummVMMain },
+ { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V",
+ (void *)ScummVM_pushEvent },
+ { "audioMixCallback", "([B)V",
+ (void *)ScummVM_audioMixCallback },
+ { "setConfMan", "(Ljava/lang/String;I)V",
+ (void *)ScummVM_setConfManInt },
+ { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V",
+ (void *)ScummVM_setConfManString },
+ { "enableZoning", "(Z)V",
+ (void *)ScummVM_enableZoning },
+ { "setSurfaceSize", "(II)V",
+ (void *)ScummVM_setSurfaceSize },
+};
+
+JNIEXPORT jint JNICALL
+JNI_OnLoad(JavaVM *jvm, void *reserved) {
+ cached_jvm = jvm;
+
+ JNIEnv *env;
+
+ if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2))
+ return JNI_ERR;
+
+ jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM");
+ if (cls == 0)
+ return JNI_ERR;
+
+ if (env->RegisterNatives(cls, gMethods, ARRAYSIZE(gMethods)) < 0)
+ return JNI_ERR;
+
+ FID_ScummVM_nativeScummVM = env->GetFieldID(cls, "nativeScummVM", "J");
+ if (FID_ScummVM_nativeScummVM == 0)
+ return JNI_ERR;
+
+ jclass event = env->FindClass("org/inodes/gus/scummvm/Event");
+ if (event == 0)
+ return JNI_ERR;
+
+ FID_Event_type = env->GetFieldID(event, "type", "I");
+ if (FID_Event_type == 0)
+ return JNI_ERR;
+
+ FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z");
+ if (FID_Event_synthetic == 0)
+ return JNI_ERR;
+
+ FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I");
+ if (FID_Event_kbd_keycode == 0)
+ return JNI_ERR;
+
+ FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I");
+ if (FID_Event_kbd_ascii == 0)
+ return JNI_ERR;
+
+ FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I");
+ if (FID_Event_kbd_flags == 0)
+ return JNI_ERR;
+
+ FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I");
+ if (FID_Event_mouse_x == 0)
+ return JNI_ERR;
+
+ FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I");
+ if (FID_Event_mouse_y == 0)
+ return JNI_ERR;
+
+ FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z");
+ if (FID_Event_mouse_relative == 0)
+ return JNI_ERR;
+
+ cls = env->FindClass("java/lang/Object");
+ if (cls == 0)
+ return JNI_ERR;
+
+ MID_Object_wait = env->GetMethodID(cls, "wait", "()V");
+ if (MID_Object_wait == 0)
+ return JNI_ERR;
+
+ return JNI_VERSION_1_2;
+}
+
+#endif
+
diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk
index 8b120b21ff..3bcfa7ad87 100644
--- a/backends/platform/android/module.mk
+++ b/backends/platform/android/module.mk
@@ -1,9 +1,11 @@
MODULE := backends/platform/android
MODULE_OBJS := \
- android.o \
+ jni.o \
+ texture.o \
asset-archive.o \
- video.o
+ android.o \
+ gfx.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/video.cpp b/backends/platform/android/texture.cpp
index f8427c2ac8..b638976dc4 100644
--- a/backends/platform/android/video.cpp
+++ b/backends/platform/android/texture.cpp
@@ -33,8 +33,8 @@
#include "common/util.h"
#include "common/tokenizer.h"
+#include "backends/platform/android/texture.h"
#include "backends/platform/android/android.h"
-#include "backends/platform/android/video.h"
// Unfortunately, Android devices are too varied to make broad assumptions :/
#define TEXSUBIMAGE_IS_EXPENSIVE 0
diff --git a/backends/platform/android/video.h b/backends/platform/android/texture.h
index da42ea876d..050eafa073 100644
--- a/backends/platform/android/video.h
+++ b/backends/platform/android/texture.h
@@ -23,6 +23,9 @@
*
*/
+#ifndef _ANDROID_TEXTURE_H_
+#define _ANDROID_TEXTURE_H_
+
#if defined(__ANDROID__)
#include <GLES/gl.h>
@@ -207,3 +210,5 @@ protected:
};
#endif
+#endif
+