From 257913676d5a21c6192a6146e662c21f299c9b09 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 20 Feb 2011 17:01:46 +0100 Subject: ANDROID: Split code into multiple files And get rid of unnecessary JNI calls to get a pointer to g_system --- backends/platform/android/android.cpp | 970 +--------------------------------- backends/platform/android/android.h | 200 ++++++- backends/platform/android/gfx.cpp | 459 ++++++++++++++++ backends/platform/android/jni.cpp | 387 ++++++++++++++ backends/platform/android/module.mk | 6 +- backends/platform/android/texture.cpp | 342 ++++++++++++ backends/platform/android/texture.h | 214 ++++++++ backends/platform/android/video.cpp | 342 ------------ backends/platform/android/video.h | 209 -------- 9 files changed, 1612 insertions(+), 1517 deletions(-) create mode 100644 backends/platform/android/gfx.cpp create mode 100644 backends/platform/android/jni.cpp create mode 100644 backends/platform/android/texture.cpp create mode 100644 backends/platform/android/texture.h delete mode 100644 backends/platform/android/video.cpp delete mode 100644 backends/platform/android/video.h (limited to 'backends/platform/android') 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 - -#include -#include -#include #include #include +#include -#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 static inline T scalef(T in, float numerator, float denominator) { return static_cast(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 _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(cpp_obj->getMixer()); - assert(mixer); - mixer->mixCallback(reinterpret_cast(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(env->GetIntField( - java_event, FID_Event_kbd_ascii)); - event.kbd.flags = static_cast(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(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 + +#include #include #include @@ -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 _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(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(env->GetIntField( + java_event, FID_Event_kbd_ascii)); + event.kbd.flags = static_cast(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(g_sys->getMixer()); + assert(mixer); + mixer->mixCallback(reinterpret_cast(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/texture.cpp b/backends/platform/android/texture.cpp new file mode 100644 index 0000000000..b638976dc4 --- /dev/null +++ b/backends/platform/android/texture.cpp @@ -0,0 +1,342 @@ +/* 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 "graphics/surface.h" + +#include "common/rect.h" +#include "common/array.h" +#include "common/util.h" +#include "common/tokenizer.h" + +#include "backends/platform/android/texture.h" +#include "backends/platform/android/android.h" + +// Unfortunately, Android devices are too varied to make broad assumptions :/ +#define TEXSUBIMAGE_IS_EXPENSIVE 0 + +// Supported GL extensions +static bool npot_supported = false; +#ifdef GL_OES_draw_texture +static bool draw_tex_supported = false; +#endif + +static inline GLfixed xdiv(int numerator, int denominator) { + assert(numerator < (1 << 16)); + return (numerator << 16) / denominator; +} + +template +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; +} + +void GLESTexture::initGLExtensions() { + const char *ext_string = + reinterpret_cast(glGetString(GL_EXTENSIONS)); + + LOGI("Extensions: %s", ext_string); + + Common::StringTokenizer tokenizer(ext_string, " "); + while (!tokenizer.empty()) { + Common::String token = tokenizer.nextToken(); + + if (token == "GL_ARB_texture_non_power_of_two") + npot_supported = true; + +#ifdef GL_OES_draw_texture + if (token == "GL_OES_draw_texture") + draw_tex_supported = true; +#endif + } +} + +GLESTexture::GLESTexture() : + _texture_width(0), + _texture_height(0), + _all_dirty(true) +{ + GLCALL(glGenTextures(1, &_texture_name)); + + // This all gets reset later in allocBuffer: + _surface.w = 0; + _surface.h = 0; + _surface.pitch = _texture_width; + _surface.pixels = 0; + _surface.bytesPerPixel = 0; +} + +GLESTexture::~GLESTexture() { + debug("Destroying texture %u", _texture_name); + GLCALL(glDeleteTextures(1, &_texture_name)); +} + +void GLESTexture::reinitGL() { + GLCALL(glDeleteTextures(1, &_texture_name)); + GLCALL(glGenTextures(1, &_texture_name)); + + // bypass allocBuffer() shortcut to reinit the texture properly + _texture_width = 0; + _texture_height = 0; + + allocBuffer(_surface.w, _surface.h); + setDirty(); +} + +void GLESTexture::allocBuffer(GLuint w, GLuint h) { + int bpp = bytesPerPixel(); + _surface.w = w; + _surface.h = h; + _surface.bytesPerPixel = bpp; + + // Already allocated a sufficiently large buffer? + 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); + } + + _surface.pitch = _texture_width * bpp; + + // 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, GL_NEAREST)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + 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 GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, + const void *buf, int pitch) { + ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch); + + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + + setDirtyRect(Common::Rect(x, y, x+w, y+h)); + + if (static_cast(w) * bytesPerPixel() == pitch) { + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, + glFormat(), glType(), buf)); + } else { + // GLES removed the ability to specify pitch, so we + // have to do this ourselves. + if (h == 0) + return; + +#if TEXSUBIMAGE_IS_EXPENSIVE + byte tmpbuf[w * h * bytesPerPixel()]; + const byte *src = static_cast(buf); + byte *dst = tmpbuf; + GLuint count = h; + + do { + memcpy(dst, src, w * bytesPerPixel()); + dst += w * bytesPerPixel(); + src += pitch; + } while (--count); + + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, + glFormat(), glType(), tmpbuf)); +#else + // This version avoids the intermediate copy at the expense of + // repeat glTexSubImage2D calls. On some devices this is worse. + const byte *src = static_cast(buf); + do { + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, + w, 1, glFormat(), glType(), src)); + ++y; + src += pitch; + } while (--h); +#endif + } +} + +void GLESTexture::fillBuffer(byte x) { + int rowbytes = _surface.w * bytesPerPixel(); + byte tmpbuf[_surface.h * rowbytes]; + memset(tmpbuf, x, _surface.h * rowbytes); + updateBuffer(0, 0, _surface.w, _surface.h, tmpbuf, rowbytes); +} + +void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + +#ifdef GL_OES_draw_texture + // Great extension, but only works under specific conditions. + // Still a work-in-progress - disabled for now. + if (false && draw_tex_supported && paletteSize() == 0) { + //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); + const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; + + GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop)); + + // Android GLES bug? + GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); + + GLCALL(glDrawTexiOES(x, y, 0, w, h)); + } else +#endif + { + const GLfixed tex_width = xdiv(_surface.w, _texture_width); + const GLfixed tex_height = xdiv(_surface.h, _texture_height); + const GLfixed texcoords[] = { + 0, 0, + tex_width, 0, + 0, tex_height, + tex_width, tex_height, + }; + + GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); + + const GLshort vertices[] = { + x, y, + x + w, y, + x, y + h, + x + w, y + h, + }; + + GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); + + assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); + GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); + } + + _all_dirty = false; + _dirty_rect = Common::Rect(); +} + +GLESPaletteTexture::GLESPaletteTexture() : + GLESTexture(), + _texture(0) +{ +} + +GLESPaletteTexture::~GLESPaletteTexture() { + delete[] _texture; +} + +void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { + int bpp = bytesPerPixel(); + _surface.w = w; + _surface.h = h; + _surface.bytesPerPixel = bpp; + + // Already allocated a sufficiently large buffer? + 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); + } + _surface.pitch = _texture_width * bpp; + + // Texture gets uploaded later (from drawTexture()) + + byte *new_buffer = new byte[paletteSize() + + _texture_width * _texture_height * bytesPerPixel()]; + if (_texture) { + // preserve palette + memcpy(new_buffer, _texture, paletteSize()); + delete[] _texture; + } + + _texture = new_buffer; + _surface.pixels = _texture + paletteSize(); +} + +void GLESPaletteTexture::fillBuffer(byte x) { + assert(_surface.pixels); + memset(_surface.pixels, x, _surface.pitch * _surface.h); + setDirty(); +} + +void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, + GLuint w, GLuint h, + const void *buf, int pitch) { + _all_dirty = true; + + const byte * src = static_cast(buf); + byte *dst = static_cast(_surface.getBasePtr(x, y)); + + do { + memcpy(dst, src, w * bytesPerPixel()); + dst += _surface.pitch; + src += pitch; + } while (--h); +} + +void GLESPaletteTexture::uploadTexture() const { + const size_t texture_size = + paletteSize() + _texture_width * _texture_height * bytesPerPixel(); + + GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, glType(), + _texture_width, _texture_height, + 0, texture_size, _texture)); +} + +void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { + if (_all_dirty) { + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_NEAREST)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_NEAREST)); + 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)); + uploadTexture(); + _all_dirty = false; + } + + GLESTexture::drawTexture(x, y, w, h); +} + +#endif + diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h new file mode 100644 index 0000000000..050eafa073 --- /dev/null +++ b/backends/platform/android/texture.h @@ -0,0 +1,214 @@ +/* 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$ + * + */ + +#ifndef _ANDROID_TEXTURE_H_ +#define _ANDROID_TEXTURE_H_ + +#if defined(__ANDROID__) + +#include + +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/array.h" + +class GLESTexture { +public: + static void initGLExtensions(); + + GLESTexture(); + virtual ~GLESTexture(); + + virtual void reinitGL(); + virtual void allocBuffer(GLuint width, GLuint height); + + virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, + const void *buf, int pitch); + virtual void fillBuffer(byte x); + + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); + + inline GLuint width() const { + return _surface.w; + } + + inline GLuint height() const { + return _surface.h; + } + + inline GLuint texture_name() const { + return _texture_name; + } + + inline const Graphics::Surface *surface_const() const { + return &_surface; + } + + inline Graphics::Surface *surface() { + setDirty(); + return &_surface; + } + + inline bool dirty() const { + return _all_dirty || !_dirty_rect.isEmpty(); + } + + inline void drawTexture() { + drawTexture(0, 0, _surface.w, _surface.h); + } + +protected: + virtual byte bytesPerPixel() const = 0; + virtual GLenum glFormat() const = 0; + virtual GLenum glType() const = 0; + + virtual size_t paletteSize() const { + return 0; + } + + inline void setDirty() { + _all_dirty = true; + _dirty_rect = Common::Rect(); + } + + inline void setDirtyRect(const Common::Rect& r) { + if (!_all_dirty) { + if (_dirty_rect.isEmpty()) + _dirty_rect = r; + else + _dirty_rect.extend(r); + } + } + + GLuint _texture_name; + Graphics::Surface _surface; + GLuint _texture_width; + GLuint _texture_height; + bool _all_dirty; + + // Covers dirty area + Common::Rect _dirty_rect; +}; + +// RGBA4444 texture +class GLES4444Texture : public GLESTexture { +protected: + virtual byte bytesPerPixel() const { + return 2; + } + + virtual GLenum glFormat() const { + return GL_RGBA; + } + + virtual GLenum glType() const { + return GL_UNSIGNED_SHORT_4_4_4_4; + } +}; + +// RGB565 texture +class GLES565Texture : public GLESTexture { +protected: + virtual byte bytesPerPixel() const { + return 2; + } + + virtual GLenum glFormat() const { + return GL_RGB; + } + + virtual GLenum glType() const { + return GL_UNSIGNED_SHORT_5_6_5; + } +}; + +// RGB888 256-entry paletted texture +class GLESPaletteTexture : public GLESTexture { +public: + GLESPaletteTexture(); + virtual ~GLESPaletteTexture(); + + virtual void allocBuffer(GLuint width, GLuint height); + virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, + const void *buf, int pitch); + virtual void fillBuffer(byte x); + + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); + + inline void drawTexture() { + drawTexture(0, 0, _surface.w, _surface.h); + } + + inline const byte *palette_const() const { + return _texture; + }; + + inline byte *palette() { + setDirty(); + return _texture; + }; + +protected: + virtual byte bytesPerPixel() const { + return 1; + } + + virtual GLenum glFormat() const { + return GL_RGB; + } + + virtual GLenum glType() const { + return GL_PALETTE8_RGB8_OES; + } + + virtual size_t paletteSize() const { + return 256 * 3; + } + + void uploadTexture() const; + + byte *_texture; +}; + +// RGBA8888 256-entry paletted texture +class GLESPaletteATexture : public GLESPaletteTexture { +protected: + virtual GLenum glFormat() const { + return GL_RGBA; + } + + virtual GLenum glType() const { + return GL_PALETTE8_RGBA8_OES; + } + + virtual size_t paletteSize() const { + return 256 * 4; + } +}; + +#endif +#endif + diff --git a/backends/platform/android/video.cpp b/backends/platform/android/video.cpp deleted file mode 100644 index f8427c2ac8..0000000000 --- a/backends/platform/android/video.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/* 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 "graphics/surface.h" - -#include "common/rect.h" -#include "common/array.h" -#include "common/util.h" -#include "common/tokenizer.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 - -// Supported GL extensions -static bool npot_supported = false; -#ifdef GL_OES_draw_texture -static bool draw_tex_supported = false; -#endif - -static inline GLfixed xdiv(int numerator, int denominator) { - assert(numerator < (1 << 16)); - return (numerator << 16) / denominator; -} - -template -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; -} - -void GLESTexture::initGLExtensions() { - const char *ext_string = - reinterpret_cast(glGetString(GL_EXTENSIONS)); - - LOGI("Extensions: %s", ext_string); - - Common::StringTokenizer tokenizer(ext_string, " "); - while (!tokenizer.empty()) { - Common::String token = tokenizer.nextToken(); - - if (token == "GL_ARB_texture_non_power_of_two") - npot_supported = true; - -#ifdef GL_OES_draw_texture - if (token == "GL_OES_draw_texture") - draw_tex_supported = true; -#endif - } -} - -GLESTexture::GLESTexture() : - _texture_width(0), - _texture_height(0), - _all_dirty(true) -{ - GLCALL(glGenTextures(1, &_texture_name)); - - // This all gets reset later in allocBuffer: - _surface.w = 0; - _surface.h = 0; - _surface.pitch = _texture_width; - _surface.pixels = 0; - _surface.bytesPerPixel = 0; -} - -GLESTexture::~GLESTexture() { - debug("Destroying texture %u", _texture_name); - GLCALL(glDeleteTextures(1, &_texture_name)); -} - -void GLESTexture::reinitGL() { - GLCALL(glDeleteTextures(1, &_texture_name)); - GLCALL(glGenTextures(1, &_texture_name)); - - // bypass allocBuffer() shortcut to reinit the texture properly - _texture_width = 0; - _texture_height = 0; - - allocBuffer(_surface.w, _surface.h); - setDirty(); -} - -void GLESTexture::allocBuffer(GLuint w, GLuint h) { - int bpp = bytesPerPixel(); - _surface.w = w; - _surface.h = h; - _surface.bytesPerPixel = bpp; - - // Already allocated a sufficiently large buffer? - 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); - } - - _surface.pitch = _texture_width * bpp; - - // 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, GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - 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 GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, - const void *buf, int pitch) { - ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch); - - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); - - setDirtyRect(Common::Rect(x, y, x+w, y+h)); - - if (static_cast(w) * bytesPerPixel() == pitch) { - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - glFormat(), glType(), buf)); - } else { - // GLES removed the ability to specify pitch, so we - // have to do this ourselves. - if (h == 0) - return; - -#if TEXSUBIMAGE_IS_EXPENSIVE - byte tmpbuf[w * h * bytesPerPixel()]; - const byte *src = static_cast(buf); - byte *dst = tmpbuf; - GLuint count = h; - - do { - memcpy(dst, src, w * bytesPerPixel()); - dst += w * bytesPerPixel(); - src += pitch; - } while (--count); - - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - glFormat(), glType(), tmpbuf)); -#else - // This version avoids the intermediate copy at the expense of - // repeat glTexSubImage2D calls. On some devices this is worse. - const byte *src = static_cast(buf); - do { - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, - w, 1, glFormat(), glType(), src)); - ++y; - src += pitch; - } while (--h); -#endif - } -} - -void GLESTexture::fillBuffer(byte x) { - int rowbytes = _surface.w * bytesPerPixel(); - byte tmpbuf[_surface.h * rowbytes]; - memset(tmpbuf, x, _surface.h * rowbytes); - updateBuffer(0, 0, _surface.w, _surface.h, tmpbuf, rowbytes); -} - -void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - -#ifdef GL_OES_draw_texture - // Great extension, but only works under specific conditions. - // Still a work-in-progress - disabled for now. - if (false && draw_tex_supported && paletteSize() == 0) { - //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); - const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; - - GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop)); - - // Android GLES bug? - GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); - - GLCALL(glDrawTexiOES(x, y, 0, w, h)); - } else -#endif - { - const GLfixed tex_width = xdiv(_surface.w, _texture_width); - const GLfixed tex_height = xdiv(_surface.h, _texture_height); - const GLfixed texcoords[] = { - 0, 0, - tex_width, 0, - 0, tex_height, - tex_width, tex_height, - }; - - GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); - - const GLshort vertices[] = { - x, y, - x + w, y, - x, y + h, - x + w, y + h, - }; - - GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); - - assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); - GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); - } - - _all_dirty = false; - _dirty_rect = Common::Rect(); -} - -GLESPaletteTexture::GLESPaletteTexture() : - GLESTexture(), - _texture(0) -{ -} - -GLESPaletteTexture::~GLESPaletteTexture() { - delete[] _texture; -} - -void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { - int bpp = bytesPerPixel(); - _surface.w = w; - _surface.h = h; - _surface.bytesPerPixel = bpp; - - // Already allocated a sufficiently large buffer? - 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); - } - _surface.pitch = _texture_width * bpp; - - // Texture gets uploaded later (from drawTexture()) - - byte *new_buffer = new byte[paletteSize() + - _texture_width * _texture_height * bytesPerPixel()]; - if (_texture) { - // preserve palette - memcpy(new_buffer, _texture, paletteSize()); - delete[] _texture; - } - - _texture = new_buffer; - _surface.pixels = _texture + paletteSize(); -} - -void GLESPaletteTexture::fillBuffer(byte x) { - assert(_surface.pixels); - memset(_surface.pixels, x, _surface.pitch * _surface.h); - setDirty(); -} - -void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, - GLuint w, GLuint h, - const void *buf, int pitch) { - _all_dirty = true; - - const byte * src = static_cast(buf); - byte *dst = static_cast(_surface.getBasePtr(x, y)); - - do { - memcpy(dst, src, w * bytesPerPixel()); - dst += _surface.pitch; - src += pitch; - } while (--h); -} - -void GLESPaletteTexture::uploadTexture() const { - const size_t texture_size = - paletteSize() + _texture_width * _texture_height * bytesPerPixel(); - - GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, glType(), - _texture_width, _texture_height, - 0, texture_size, _texture)); -} - -void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { - if (_all_dirty) { - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_NEAREST)); - 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)); - uploadTexture(); - _all_dirty = false; - } - - GLESTexture::drawTexture(x, y, w, h); -} - -#endif - diff --git a/backends/platform/android/video.h b/backends/platform/android/video.h deleted file mode 100644 index da42ea876d..0000000000 --- a/backends/platform/android/video.h +++ /dev/null @@ -1,209 +0,0 @@ -/* 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 - -#include "graphics/surface.h" - -#include "common/rect.h" -#include "common/array.h" - -class GLESTexture { -public: - static void initGLExtensions(); - - GLESTexture(); - virtual ~GLESTexture(); - - virtual void reinitGL(); - virtual void allocBuffer(GLuint width, GLuint height); - - virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, - const void *buf, int pitch); - virtual void fillBuffer(byte x); - - virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - - inline GLuint width() const { - return _surface.w; - } - - inline GLuint height() const { - return _surface.h; - } - - inline GLuint texture_name() const { - return _texture_name; - } - - inline const Graphics::Surface *surface_const() const { - return &_surface; - } - - inline Graphics::Surface *surface() { - setDirty(); - return &_surface; - } - - inline bool dirty() const { - return _all_dirty || !_dirty_rect.isEmpty(); - } - - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - -protected: - virtual byte bytesPerPixel() const = 0; - virtual GLenum glFormat() const = 0; - virtual GLenum glType() const = 0; - - virtual size_t paletteSize() const { - return 0; - } - - inline void setDirty() { - _all_dirty = true; - _dirty_rect = Common::Rect(); - } - - inline void setDirtyRect(const Common::Rect& r) { - if (!_all_dirty) { - if (_dirty_rect.isEmpty()) - _dirty_rect = r; - else - _dirty_rect.extend(r); - } - } - - GLuint _texture_name; - Graphics::Surface _surface; - GLuint _texture_width; - GLuint _texture_height; - bool _all_dirty; - - // Covers dirty area - Common::Rect _dirty_rect; -}; - -// RGBA4444 texture -class GLES4444Texture : public GLESTexture { -protected: - virtual byte bytesPerPixel() const { - return 2; - } - - virtual GLenum glFormat() const { - return GL_RGBA; - } - - virtual GLenum glType() const { - return GL_UNSIGNED_SHORT_4_4_4_4; - } -}; - -// RGB565 texture -class GLES565Texture : public GLESTexture { -protected: - virtual byte bytesPerPixel() const { - return 2; - } - - virtual GLenum glFormat() const { - return GL_RGB; - } - - virtual GLenum glType() const { - return GL_UNSIGNED_SHORT_5_6_5; - } -}; - -// RGB888 256-entry paletted texture -class GLESPaletteTexture : public GLESTexture { -public: - GLESPaletteTexture(); - virtual ~GLESPaletteTexture(); - - virtual void allocBuffer(GLuint width, GLuint height); - virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, - const void *buf, int pitch); - virtual void fillBuffer(byte x); - - virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - - inline const byte *palette_const() const { - return _texture; - }; - - inline byte *palette() { - setDirty(); - return _texture; - }; - -protected: - virtual byte bytesPerPixel() const { - return 1; - } - - virtual GLenum glFormat() const { - return GL_RGB; - } - - virtual GLenum glType() const { - return GL_PALETTE8_RGB8_OES; - } - - virtual size_t paletteSize() const { - return 256 * 3; - } - - void uploadTexture() const; - - byte *_texture; -}; - -// RGBA8888 256-entry paletted texture -class GLESPaletteATexture : public GLESPaletteTexture { -protected: - virtual GLenum glFormat() const { - return GL_RGBA; - } - - virtual GLenum glType() const { - return GL_PALETTE8_RGBA8_OES; - } - - virtual size_t paletteSize() const { - return 256 * 4; - } -}; - -#endif -- cgit v1.2.3 From 4af28f96ab4075cb5e512d4050ac085df73a029a Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 20 Feb 2011 20:16:51 +0100 Subject: ANDROID: Remove unused jmethod Object.wait() --- backends/platform/android/jni.cpp | 9 --------- 1 file changed, 9 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 0f1366148f..e5d0f71f53 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -44,7 +44,6 @@ 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; @@ -372,14 +371,6 @@ JNI_OnLoad(JavaVM *jvm, void *reserved) { 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; } -- cgit v1.2.3 From c4706733d45de09803b7cd40c3536a4e04b4f767 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 20 Feb 2011 20:46:17 +0100 Subject: ANDROID: Move the global back reference to jni.cpp --- backends/platform/android/android.cpp | 29 +++++++++-------------------- backends/platform/android/android.h | 8 ++++---- backends/platform/android/gfx.cpp | 6 +++--- backends/platform/android/jni.cpp | 14 +++++++++++++- 4 files changed, 29 insertions(+), 28 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index a0a53474e8..f2c9a7407d 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -101,7 +101,6 @@ static inline T scalef(T in, float numerator, float denominator) { OSystem_Android *g_sys = 0; OSystem_Android::OSystem_Android(jobject am) : - _back_ptr(0), _screen_changeid(0), _force_redraw(false), _game_texture(0), @@ -129,11 +128,6 @@ OSystem_Android::~OSystem_Android() { destroyScummVMSurface(); - JNIEnv *env = JNU_GetEnv(); - // see below - //env->DeleteWeakGlobalRef(_back_ptr); - env->DeleteGlobalRef(_back_ptr); - delete _savefile; delete _mixer; delete _timer; @@ -143,13 +137,8 @@ OSystem_Android::~OSystem_Android() { deleteMutex(_event_queue_lock); } -bool OSystem_Android::initJavaHooks(JNIEnv *env, jobject self) { - // weak global ref to allow class to be unloaded - // ... except dalvik implements NewWeakGlobalRef only on froyo - //_back_ptr = env->NewWeakGlobalRef(self); - _back_ptr = env->NewGlobalRef(self); - - jclass cls = env->GetObjectClass(_back_ptr); +bool OSystem_Android::initJavaHooks(JNIEnv *env) { + jclass cls = env->GetObjectClass(back_ptr); #define FIND_METHOD(name, signature) do { \ MID_ ## name = env->GetMethodID(cls, #name, signature); \ @@ -213,7 +202,7 @@ void OSystem_Android::initBackend() { gettimeofday(&_startTime, 0); - jint sample_rate = env->CallIntMethod(_back_ptr, MID_audioSampleRate); + jint sample_rate = env->CallIntMethod(back_ptr, MID_audioSampleRate); if (env->ExceptionCheck()) { warning("Error finding audio sample rate - assuming 11025HZ"); @@ -226,7 +215,7 @@ void OSystem_Android::initBackend() { _mixer = new Audio::MixerImpl(this, sample_rate); _mixer->setReady(true); - env->CallVoidMethod(_back_ptr, MID_initBackend); + env->CallVoidMethod(back_ptr, MID_initBackend); if (env->ExceptionCheck()) { error("Error in Java initBackend"); @@ -249,7 +238,7 @@ void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { JNIEnv *env = JNU_GetEnv(); jobjectArray array = - (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getPluginDirectories); + (jobjectArray)env->CallObjectMethod(back_ptr, MID_getPluginDirectories); if (env->ExceptionCheck()) { warning("Error finding plugin directories"); @@ -490,7 +479,7 @@ void OSystem_Android::setWindowCaption(const char *caption) { JNIEnv *env = JNU_GetEnv(); jstring java_caption = env->NewStringUTF(caption); - env->CallVoidMethod(_back_ptr, MID_setWindowCaption, java_caption); + env->CallVoidMethod(back_ptr, MID_setWindowCaption, java_caption); if (env->ExceptionCheck()) { warning("Failed to set window caption"); @@ -508,7 +497,7 @@ void OSystem_Android::displayMessageOnOSD(const char *msg) { JNIEnv *env = JNU_GetEnv(); jstring java_msg = env->NewStringUTF(msg); - env->CallVoidMethod(_back_ptr, MID_displayMessageOnOSD, java_msg); + env->CallVoidMethod(back_ptr, MID_displayMessageOnOSD, java_msg); if (env->ExceptionCheck()) { warning("Failed to display OSD message"); @@ -525,7 +514,7 @@ void OSystem_Android::showVirtualKeyboard(bool enable) { JNIEnv *env = JNU_GetEnv(); - env->CallVoidMethod(_back_ptr, MID_showVirtualKeyboard, enable); + env->CallVoidMethod(back_ptr, MID_showVirtualKeyboard, enable); if (env->ExceptionCheck()) { error("Error trying to show virtual keyboard"); @@ -574,7 +563,7 @@ void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, JNIEnv *env = JNU_GetEnv(); jobjectArray array = - (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getSysArchives); + (jobjectArray)env->CallObjectMethod(back_ptr, MID_getSysArchives); if (env->ExceptionCheck()) { warning("Error finding system archive path"); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index b31c0fd385..da487c5ceb 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -78,6 +78,9 @@ extern void checkGlError(const char *expr, const char *file, int line); #define GLCALL(x) do { (x); } while (false) #endif +// back pointer to (java) peer instance +extern jobject back_ptr; + extern JNIEnv *JNU_GetEnv(); extern void JNU_AttachThread(); extern void JNU_DetachThread(); @@ -94,9 +97,6 @@ protected: 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; @@ -155,7 +155,7 @@ private: public: OSystem_Android(jobject am); virtual ~OSystem_Android(); - bool initJavaHooks(JNIEnv *env, jobject self); + bool initJavaHooks(JNIEnv *env); virtual void initBackend(); void addPluginDirectories(Common::FSList &dirs) const; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index eb5a66c6d9..2b730385e6 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -63,7 +63,7 @@ void OSystem_Android::setupScummVMSurface() { ENTER(); JNIEnv *env = JNU_GetEnv(); - env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface); + env->CallVoidMethod(back_ptr, MID_setupScummVMSurface); if (env->ExceptionCheck()) return; @@ -117,7 +117,7 @@ void OSystem_Android::setupScummVMSurface() { void OSystem_Android::destroyScummVMSurface() { JNIEnv *env = JNU_GetEnv(); - env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface); + env->CallVoidMethod(back_ptr, MID_destroyScummVMSurface); // Can't use OpenGLES functions after this } @@ -262,7 +262,7 @@ void OSystem_Android::updateScreen() { GLCALL(glPopMatrix()); JNIEnv *env = JNU_GetEnv(); - if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) { + if (!env->CallBooleanMethod(back_ptr, MID_swapBuffers)) { // Context lost -> need to reinit GL destroyScummVMSurface(); setupScummVMSurface(); diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index e5d0f71f53..b81587b3ba 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -34,7 +34,10 @@ #undef JNIEXPORT #define JNIEXPORT __attribute__ ((visibility("default"))) +jobject back_ptr; + static JavaVM *cached_jvm; + static jfieldID FID_Event_type; static jfieldID FID_Event_synthetic; static jfieldID FID_Event_kbd_keycode; @@ -93,8 +96,13 @@ static void ScummVM_create(JNIEnv *env, jobject self, jobject am) { g_sys = new OSystem_Android(am); assert(g_sys); + // weak global ref to allow class to be unloaded + // ... except dalvik implements NewWeakGlobalRef only on froyo + //back_ptr = env->NewWeakGlobalRef(self); + back_ptr = env->NewGlobalRef(self); + // Exception already thrown by initJavaHooks? - if (!g_sys->initJavaHooks(env, self)) + if (!g_sys->initJavaHooks(env)) return; env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)g_sys); @@ -109,6 +117,10 @@ static void ScummVM_nativeDestroy(JNIEnv *env, jobject self) { g_system = 0; g_sys = 0; delete tmp; + + // see above + //JNU_GetEnv()->DeleteWeakGlobalRef(back_ptr); + JNU_GetEnv()->DeleteGlobalRef(back_ptr); } static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) { -- cgit v1.2.3 From f80d993860257a8e74936bc74eb99bda2fbfcaa4 Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 23 Feb 2011 22:44:33 +0100 Subject: ANDROID: Wrap JNI code in a class --- backends/platform/android/android.cpp | 25 +-- backends/platform/android/android.h | 8 +- backends/platform/android/asset-archive.cpp | 21 +- backends/platform/android/gfx.cpp | 6 +- backends/platform/android/jni.cpp | 301 ++++++++++++++-------------- backends/platform/android/jni.h | 87 ++++++++ 6 files changed, 265 insertions(+), 183 deletions(-) create mode 100644 backends/platform/android/jni.h (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index f2c9a7407d..9437bf540c 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -98,8 +98,6 @@ static inline T scalef(T in, float numerator, float denominator) { return static_cast(in) * numerator / denominator; } -OSystem_Android *g_sys = 0; - OSystem_Android::OSystem_Android(jobject am) : _screen_changeid(0), _force_redraw(false), @@ -166,7 +164,7 @@ void *OSystem_Android::timerThreadFunc(void *arg) { OSystem_Android *system = (OSystem_Android *)arg; DefaultTimerManager *timer = (DefaultTimerManager *)(system->_timer); - JNU_AttachThread(); + JNI::attachThread(); struct timespec tv; tv.tv_sec = 0; @@ -177,7 +175,7 @@ void *OSystem_Android::timerThreadFunc(void *arg) { nanosleep(&tv, 0); } - JNU_DetachThread(); + JNI::detachThread(); return 0; } @@ -185,7 +183,7 @@ void *OSystem_Android::timerThreadFunc(void *arg) { void OSystem_Android::initBackend() { ENTER(); - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); ConfMan.setInt("autosave_period", 0); ConfMan.setInt("FM_medium_quality", true); @@ -235,10 +233,10 @@ void OSystem_Android::initBackend() { void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { ENTER(); - JNIEnv *env = JNU_GetEnv(); - + JNIEnv *env = JNI::getEnv(); jobjectArray array = (jobjectArray)env->CallObjectMethod(back_ptr, MID_getPluginDirectories); + if (env->ExceptionCheck()) { warning("Error finding plugin directories"); @@ -477,7 +475,7 @@ void OSystem_Android::quit() { void OSystem_Android::setWindowCaption(const char *caption) { ENTER("%s", caption); - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); jstring java_caption = env->NewStringUTF(caption); env->CallVoidMethod(back_ptr, MID_setWindowCaption, java_caption); @@ -494,9 +492,8 @@ void OSystem_Android::setWindowCaption(const char *caption) { void OSystem_Android::displayMessageOnOSD(const char *msg) { ENTER("%s", msg); - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); jstring java_msg = env->NewStringUTF(msg); - env->CallVoidMethod(back_ptr, MID_displayMessageOnOSD, java_msg); if (env->ExceptionCheck()) { @@ -512,8 +509,7 @@ void OSystem_Android::displayMessageOnOSD(const char *msg) { void OSystem_Android::showVirtualKeyboard(bool enable) { ENTER("%d", enable); - JNIEnv *env = JNU_GetEnv(); - + JNIEnv *env = JNI::getEnv(); env->CallVoidMethod(back_ptr, MID_showVirtualKeyboard, enable); if (env->ExceptionCheck()) { @@ -560,8 +556,7 @@ void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { s.add("ASSET", _asset_archive, priority, false); - JNIEnv *env = JNU_GetEnv(); - + JNIEnv *env = JNI::getEnv(); jobjectArray array = (jobjectArray)env->CallObjectMethod(back_ptr, MID_getSysArchives); @@ -606,7 +601,7 @@ void OSystem_Android::logMessage(LogMessageType::Type type, const char *message) #ifdef DYNAMIC_MODULES void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const { - g_sys->addPluginDirectories(dirs); + ((OSystem_Android *)g_system)->addPluginDirectories(dirs); } #endif diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index da487c5ceb..0ccf57e7c1 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -36,6 +36,7 @@ #include "backends/plugins/posix/posix-provider.h" #include "backends/fs/posix/posix-fs-factory.h" +#include "backends/platform/android/jni.h" #include "backends/platform/android/texture.h" #include @@ -81,13 +82,6 @@ extern void checkGlError(const char *expr, const char *file, int line); // back pointer to (java) peer instance extern jobject back_ptr; -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: diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index 71ce25aa72..eb2530823d 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -36,10 +36,9 @@ #include "common/archive.h" #include "common/debug.h" +#include "backends/platform/android/jni.h" #include "backends/platform/android/asset-archive.h" -extern JNIEnv *JNU_GetEnv(); - // Must match android.content.res.AssetManager.ACCESS_* const jint ACCESS_UNKNOWN = 0; const jint ACCESS_RANDOM = 1; @@ -124,7 +123,7 @@ JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) : } JavaInputStream::~JavaInputStream() { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); close(env); env->DeleteGlobalRef(_buf); @@ -139,7 +138,7 @@ void JavaInputStream::close(JNIEnv *env) { } uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); if (_buflen < jint(dataSize)) { _buflen = dataSize; @@ -171,7 +170,7 @@ uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { } bool JavaInputStream::seek(int32 offset, int whence) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); uint32 newpos; switch (whence) { @@ -318,7 +317,7 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) : } AssetFdReadStream::~AssetFdReadStream() { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); env->CallVoidMethod(_assetfd, MID_close); if (env->ExceptionCheck()) @@ -369,7 +368,7 @@ bool AssetFdReadStream::seek(int32 offset, int whence) { } AndroidAssetArchive::AndroidAssetArchive(jobject am) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); _am = env->NewGlobalRef(am); jclass cls = env->GetObjectClass(_am); @@ -387,12 +386,12 @@ AndroidAssetArchive::AndroidAssetArchive(jobject am) { } AndroidAssetArchive::~AndroidAssetArchive() { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); env->DeleteGlobalRef(_am); } bool AndroidAssetArchive::hasFile(const Common::String &name) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); jstring path = env->NewStringUTF(name.c_str()); jobject result = env->CallObjectMethod(_am, MID_open, path, ACCESS_UNKNOWN); if (env->ExceptionCheck()) { @@ -412,7 +411,7 @@ bool AndroidAssetArchive::hasFile(const Common::String &name) { } int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); Common::List dirlist; dirlist.push_back(""); @@ -469,7 +468,7 @@ Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &na } Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); jstring jpath = env->NewStringUTF(path.c_str()); // Try openFd() first ... diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 2b730385e6..2370958d30 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -62,7 +62,7 @@ int OSystem_Android::getGraphicsMode() const { void OSystem_Android::setupScummVMSurface() { ENTER(); - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); env->CallVoidMethod(back_ptr, MID_setupScummVMSurface); if (env->ExceptionCheck()) @@ -116,7 +116,7 @@ void OSystem_Android::setupScummVMSurface() { } void OSystem_Android::destroyScummVMSurface() { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); env->CallVoidMethod(back_ptr, MID_destroyScummVMSurface); // Can't use OpenGLES functions after this } @@ -261,7 +261,7 @@ void OSystem_Android::updateScreen() { GLCALL(glPopMatrix()); - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); if (!env->CallBooleanMethod(back_ptr, MID_swapBuffers)) { // Context lost -> need to reinit GL destroyScummVMSurface(); diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index b81587b3ba..4fa08ef7ab 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -30,28 +30,116 @@ #include "backends/platform/android/android.h" -// Fix JNIEXPORT declaration to actually do something useful -#undef JNIEXPORT -#define JNIEXPORT __attribute__ ((visibility("default"))) - jobject back_ptr; -static JavaVM *cached_jvm; +__attribute__ ((visibility("default"))) +jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return JNI::onLoad(vm); +} + +JavaVM *JNI::_vm = 0; +jobject JNI::_jobj = 0; +OSystem_Android *JNI::_system = 0; + +jfieldID JNI::_FID_Event_type = 0; +jfieldID JNI::_FID_Event_synthetic = 0; +jfieldID JNI::_FID_Event_kbd_keycode = 0; +jfieldID JNI::_FID_Event_kbd_ascii = 0; +jfieldID JNI::_FID_Event_kbd_flags = 0; +jfieldID JNI::_FID_Event_mouse_x = 0; +jfieldID JNI::_FID_Event_mouse_y = 0; +jfieldID JNI::_FID_Event_mouse_relative = 0; +jfieldID JNI::_FID_ScummVM_nativeScummVM = 0; + +const JNINativeMethod JNI::_natives[] = { + { "create", "(Landroid/content/res/AssetManager;)V", + (void *)JNI::create }, + { "nativeDestroy", "()V", + (void *)JNI::destroy }, + { "scummVMMain", "([Ljava/lang/String;)I", + (void *)JNI::main }, + { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", + (void *)JNI::pushEvent }, + { "audioMixCallback", "([B)V", + (void *)JNI::audioMixCallback }, + { "setConfMan", "(Ljava/lang/String;I)V", + (void *)JNI::setConfManInt }, + { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V", + (void *)JNI::setConfManString }, + { "enableZoning", "(Z)V", + (void *)JNI::enableZoning }, + { "setSurfaceSize", "(II)V", + (void *)JNI::setSurfaceSize }, +}; + +JNI::JNI() { +} + +JNI::~JNI() { +} + +jint JNI::onLoad(JavaVM *vm) { + _vm = vm; + + JNIEnv *env; + + if (_vm->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, _natives, ARRAYSIZE(_natives)) < 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; -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; + return JNI_VERSION_1_2; +} -JNIEnv *JNU_GetEnv() { +JNIEnv *JNI::getEnv() { JNIEnv *env = 0; - jint res = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2); + jint res = _vm->GetEnv((void **)&env, JNI_VERSION_1_2); if (res != JNI_OK) { LOGE("GetEnv() failed: %d", res); @@ -61,9 +149,10 @@ JNIEnv *JNU_GetEnv() { return env; } -void JNU_AttachThread() { +void JNI::attachThread() { JNIEnv *env = 0; - jint res = cached_jvm->AttachCurrentThread(&env, 0); + + jint res = _vm->AttachCurrentThread(&env, 0); if (res != JNI_OK) { LOGE("AttachCurrentThread() failed: %d", res); @@ -71,8 +160,8 @@ void JNU_AttachThread() { } } -void JNU_DetachThread() { - jint res = cached_jvm->DetachCurrentThread(); +void JNI::detachThread() { + jint res = _vm->DetachCurrentThread(); if (res != JNI_OK) { LOGE("DetachCurrentThread() failed: %d", res); @@ -80,7 +169,7 @@ void JNU_DetachThread() { } } -static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) { +void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) { jclass cls = env->FindClass(name); // if cls is 0, an exception has already been thrown @@ -90,49 +179,50 @@ static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) { env->DeleteLocalRef(cls); } -static void ScummVM_create(JNIEnv *env, jobject self, jobject am) { - assert(!g_system); +void JNI::create(JNIEnv *env, jobject self, jobject am) { + assert(!_system); - g_sys = new OSystem_Android(am); - assert(g_sys); + _system = new OSystem_Android(am); + assert(_system); // weak global ref to allow class to be unloaded // ... except dalvik implements NewWeakGlobalRef only on froyo - //back_ptr = env->NewWeakGlobalRef(self); - back_ptr = env->NewGlobalRef(self); + //_jobj = env->NewWeakGlobalRef(self); + _jobj = env->NewGlobalRef(self); + back_ptr = _jobj; // Exception already thrown by initJavaHooks? - if (!g_sys->initJavaHooks(env)) + if (!_system->initJavaHooks(env)) return; - env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)g_sys); + env->SetLongField(self, _FID_ScummVM_nativeScummVM, (jlong)_system); - g_system = g_sys; + g_system = _system; } -static void ScummVM_nativeDestroy(JNIEnv *env, jobject self) { - assert(g_sys); +void JNI::destroy(JNIEnv *env, jobject self) { + assert(_system); - OSystem_Android *tmp = g_sys; + OSystem_Android *tmp = _system; g_system = 0; - g_sys = 0; + _system = 0; delete tmp; // see above - //JNU_GetEnv()->DeleteWeakGlobalRef(back_ptr); - JNU_GetEnv()->DeleteGlobalRef(back_ptr); + //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); + JNI::getEnv()->DeleteGlobalRef(_jobj); } -static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) { - assert(g_sys); +jint JNI::main(JNIEnv *env, jobject self, jobjectArray args) { + assert(_system); 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"); + throwByName(env, "java/lang/IllegalArgumentException", + "too many arguments"); return 0; } @@ -169,7 +259,7 @@ static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) { LOGI("Exiting scummvm_main"); - g_sys->quit(); + _system->quit(); cleanup: nargs--; @@ -191,25 +281,25 @@ cleanup: return res; } -static void ScummVM_pushEvent(JNIEnv *env, jobject self, jobject java_event) { - assert(g_sys); +void JNI::pushEvent(JNIEnv *env, jobject self, jobject java_event) { + assert(_system); Common::Event event; event.type = (Common::EventType)env->GetIntField(java_event, - FID_Event_type); + _FID_Event_type); event.synthetic = - env->GetBooleanField(java_event, FID_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); + java_event, _FID_Event_kbd_keycode); event.kbd.ascii = static_cast(env->GetIntField( - java_event, FID_Event_kbd_ascii)); + java_event, _FID_Event_kbd_ascii)); event.kbd.flags = static_cast(env->GetIntField( - java_event, FID_Event_kbd_flags)); + java_event, _FID_Event_kbd_flags)); break; case Common::EVENT_MOUSEMOVE: case Common::EVENT_LBUTTONDOWN: @@ -221,25 +311,24 @@ static void ScummVM_pushEvent(JNIEnv *env, jobject self, jobject java_event) { case Common::EVENT_MBUTTONDOWN: case Common::EVENT_MBUTTONUP: event.mouse.x = - env->GetIntField(java_event, FID_Event_mouse_x); + env->GetIntField(java_event, _FID_Event_mouse_x); event.mouse.y = - env->GetIntField(java_event, FID_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; + java_event, _FID_Event_mouse_relative) ? 1 : 0; break; default: break; } - g_sys->pushEvent(event); + _system->pushEvent(event); } -static void ScummVM_audioMixCallback(JNIEnv *env, jobject self, - jbyteArray jbuf) { - assert(g_sys); +void JNI::audioMixCallback(JNIEnv *env, jobject self, jbyteArray jbuf) { + assert(_system); jsize len = env->GetArrayLength(jbuf); jbyte *buf = env->GetByteArrayElements(jbuf, 0); @@ -250,15 +339,14 @@ static void ScummVM_audioMixCallback(JNIEnv *env, jobject self, } Audio::MixerImpl *mixer = - static_cast(g_sys->getMixer()); + static_cast(_system->getMixer()); assert(mixer); mixer->mixCallback(reinterpret_cast(buf), len); env->ReleaseByteArrayElements(jbuf, buf, 0); } -static void ScummVM_setConfManInt(JNIEnv *env, jclass cls, - jstring key_obj, jint value) { +void JNI::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); @@ -271,8 +359,8 @@ static void ScummVM_setConfManInt(JNIEnv *env, jclass cls, env->ReleaseStringUTFChars(key_obj, key); } -static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj, - jstring value_obj) { +void JNI::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); @@ -293,97 +381,16 @@ static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj, env->ReleaseStringUTFChars(key_obj, key); } -static void ScummVM_enableZoning(JNIEnv *env, jobject self, jboolean enable) { - assert(g_sys); +void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { + assert(_system); - g_sys->enableZoning(enable); + _system->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; +void JNI::setSurfaceSize(JNIEnv *env, jobject self, jint width, jint height) { + assert(_system); - 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; - - return JNI_VERSION_1_2; + _system->setSurfaceSize(width, height); } #endif diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h new file mode 100644 index 0000000000..39276b9388 --- /dev/null +++ b/backends/platform/android/jni.h @@ -0,0 +1,87 @@ +/* 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$ + * + */ + +#ifndef _ANDROID_JNI_H_ +#define _ANDROID_JNI_H_ + +#if defined(__ANDROID__) + +#include + +extern jobject back_ptr; + +class OSystem_Android; + +class JNI { +public: + static jint onLoad(JavaVM *vm); + + static JNIEnv *getEnv(); + + static void attachThread(); + static void detachThread(); + +private: + JNI(); + virtual ~JNI(); + +private: + static JavaVM *_vm; + // back pointer to (java) peer instance + static jobject _jobj; + static OSystem_Android *_system; + + 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 const JNINativeMethod _natives[]; + + static void throwByName(JNIEnv *env, const char *name, const char *msg); + + // natives for the dark side + static void create(JNIEnv *env, jobject self, jobject am); + static void destroy(JNIEnv *env, jobject self); + static jint main(JNIEnv *env, jobject self, jobjectArray args); + static void pushEvent(JNIEnv *env, jobject self, jobject java_event); + static void audioMixCallback(JNIEnv *env, jobject self, jbyteArray jbuf); + static void setConfManInt(JNIEnv *env, jclass cls, jstring key_obj, + jint value); + static void setConfManString(JNIEnv *env, jclass cls, jstring key_obj, + jstring value_obj); + static void enableZoning(JNIEnv *env, jobject self, jboolean enable); + static void setSurfaceSize(JNIEnv *env, jobject self, jint width, + jint height); +}; + +#endif +#endif + -- cgit v1.2.3 From 53b5808d4f16a44779ef5fd8a5c8ca5e262e0379 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 24 Feb 2011 00:45:41 +0100 Subject: ANDROID: Move rest of everything JNI --- backends/platform/android/android.cpp | 162 +++--------------------- backends/platform/android/android.h | 23 +--- backends/platform/android/asset-archive.h | 5 + backends/platform/android/gfx.cpp | 24 ++-- backends/platform/android/jni.cpp | 201 ++++++++++++++++++++++++++++-- backends/platform/android/jni.h | 54 +++++++- 6 files changed, 274 insertions(+), 195 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 9437bf540c..36399873cd 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -40,8 +40,8 @@ #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" +#include "backends/platform/android/jni.h" #include "backends/platform/android/android.h" -#include "backends/platform/android/asset-archive.h" const char *android_log_tag = "ScummVM"; @@ -98,7 +98,7 @@ static inline T scalef(T in, float numerator, float denominator) { return static_cast(in) * numerator / denominator; } -OSystem_Android::OSystem_Android(jobject am) : +OSystem_Android::OSystem_Android() : _screen_changeid(0), _force_redraw(false), _game_texture(0), @@ -112,7 +112,6 @@ OSystem_Android::OSystem_Android(jobject am) : _mixer(0), _timer(0), _fsFactory(new POSIXFilesystemFactory()), - _asset_archive(new AndroidAssetArchive(am)), _shake_offset(0), _event_queue_lock(createMutex()) { } @@ -124,42 +123,16 @@ OSystem_Android::~OSystem_Android() { delete _overlay_texture; delete _mouse_texture; - destroyScummVMSurface(); + JNI::destroySurface(); delete _savefile; delete _mixer; delete _timer; delete _fsFactory; - delete _asset_archive; deleteMutex(_event_queue_lock); } -bool OSystem_Android::initJavaHooks(JNIEnv *env) { - jclass cls = env->GetObjectClass(back_ptr); - -#define FIND_METHOD(name, signature) do { \ - MID_ ## name = env->GetMethodID(cls, #name, signature); \ - if (MID_ ## name == 0) \ - return false; \ - } while (0) - - FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V"); - FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V"); - FIND_METHOD(initBackend, "()V"); - FIND_METHOD(audioSampleRate, "()I"); - FIND_METHOD(showVirtualKeyboard, "(Z)V"); - FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); - FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); - FIND_METHOD(setupScummVMSurface, "()V"); - FIND_METHOD(destroyScummVMSurface, "()V"); - FIND_METHOD(swapBuffers, "()Z"); - -#undef FIND_METHOD - - return true; -} - void *OSystem_Android::timerThreadFunc(void *arg) { OSystem_Android *system = (OSystem_Android *)arg; DefaultTimerManager *timer = (DefaultTimerManager *)(system->_timer); @@ -183,8 +156,6 @@ void *OSystem_Android::timerThreadFunc(void *arg) { void OSystem_Android::initBackend() { ENTER(); - JNIEnv *env = JNI::getEnv(); - ConfMan.setInt("autosave_period", 0); ConfMan.setInt("FM_medium_quality", true); @@ -200,74 +171,23 @@ void OSystem_Android::initBackend() { gettimeofday(&_startTime, 0); - jint sample_rate = env->CallIntMethod(back_ptr, MID_audioSampleRate); - if (env->ExceptionCheck()) { - warning("Error finding audio sample rate - assuming 11025HZ"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - sample_rate = 11025; - } - - _mixer = new Audio::MixerImpl(this, sample_rate); + _mixer = new Audio::MixerImpl(this, JNI::getAudioSampleRate()); _mixer->setReady(true); - env->CallVoidMethod(back_ptr, MID_initBackend); - - if (env->ExceptionCheck()) { - error("Error in Java initBackend"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } + JNI::initBackend(); _timer_thread_exit = false; pthread_create(&_timer_thread, 0, timerThreadFunc, this); OSystem::initBackend(); - setupScummVMSurface(); + setupSurface(); } void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { ENTER(); - JNIEnv *env = JNI::getEnv(); - jobjectArray array = - (jobjectArray)env->CallObjectMethod(back_ptr, MID_getPluginDirectories); - - if (env->ExceptionCheck()) { - warning("Error finding plugin directories"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return; - } - - jsize size = env->GetArrayLength(array); - for (jsize i = 0; i < size; ++i) { - jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); - - if (path_obj == 0) - continue; - - const char *path = env->GetStringUTFChars(path_obj, 0); - if (path == 0) { - warning("Error getting string characters from plugin directory"); - - env->ExceptionClear(); - env->DeleteLocalRef(path_obj); - - continue; - } - - dirs.push_back(Common::FSNode(path)); - - env->ReleaseStringUTFChars(path_obj, path); - env->DeleteLocalRef(path_obj); - } + JNI::getPluginDirectories(dirs); } bool OSystem_Android::hasFeature(Feature f) { @@ -380,8 +300,8 @@ bool OSystem_Android::pollEvent(Common::Event &event) { case Common::EVENT_SCREEN_CHANGED: debug("EVENT_SCREEN_CHANGED"); _screen_changeid++; - destroyScummVMSurface(); - setupScummVMSurface(); + JNI::destroySurface(); + setupSurface(); break; default: break; @@ -475,49 +395,19 @@ void OSystem_Android::quit() { void OSystem_Android::setWindowCaption(const char *caption) { ENTER("%s", caption); - JNIEnv *env = JNI::getEnv(); - jstring java_caption = env->NewStringUTF(caption); - env->CallVoidMethod(back_ptr, MID_setWindowCaption, java_caption); - - if (env->ExceptionCheck()) { - warning("Failed to set window caption"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteLocalRef(java_caption); + JNI::setWindowCaption(caption); } void OSystem_Android::displayMessageOnOSD(const char *msg) { ENTER("%s", msg); - JNIEnv *env = JNI::getEnv(); - jstring java_msg = env->NewStringUTF(msg); - env->CallVoidMethod(back_ptr, MID_displayMessageOnOSD, java_msg); - - if (env->ExceptionCheck()) { - warning("Failed to display OSD message"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteLocalRef(java_msg); + JNI::displayMessageOnOSD(msg); } void OSystem_Android::showVirtualKeyboard(bool enable) { ENTER("%d", enable); - JNIEnv *env = JNI::getEnv(); - env->CallVoidMethod(back_ptr, MID_showVirtualKeyboard, enable); - - if (env->ExceptionCheck()) { - error("Error trying to show virtual keyboard"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } + JNI::showVirtualKeyboard(enable); } Common::SaveFileManager *OSystem_Android::getSavefileManager() { @@ -554,33 +444,9 @@ FilesystemFactory *OSystem_Android::getFilesystemFactory() { void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { - s.add("ASSET", _asset_archive, priority, false); - - JNIEnv *env = JNI::getEnv(); - jobjectArray array = - (jobjectArray)env->CallObjectMethod(back_ptr, MID_getSysArchives); - - if (env->ExceptionCheck()) { - warning("Error finding system archive path"); - - env->ExceptionDescribe(); - env->ExceptionClear(); + ENTER(""); - return; - } - - jsize size = env->GetArrayLength(array); - for (jsize i = 0; i < size; ++i) { - jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); - const char *path = env->GetStringUTFChars(path_obj, 0); - - if (path != 0) { - s.addDirectory(path, path, priority); - env->ReleaseStringUTFChars(path_obj, path); - } - - env->DeleteLocalRef(path_obj); - } + JNI::addSysArchivesToSearchSet(s, priority); } void OSystem_Android::logMessage(LogMessageType::Type type, const char *message) { diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 0ccf57e7c1..8fc138d42b 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -36,12 +36,10 @@ #include "backends/plugins/posix/posix-provider.h" #include "backends/fs/posix/posix-fs-factory.h" -#include "backends/platform/android/jni.h" #include "backends/platform/android/texture.h" #include -#include #include #include @@ -79,9 +77,6 @@ extern void checkGlError(const char *expr, const char *file, int line); #define GLCALL(x) do { (x); } while (false) #endif -// back pointer to (java) peer instance -extern jobject back_ptr; - #ifdef DYNAMIC_MODULES class AndroidPluginProvider : public POSIXPluginProvider { protected: @@ -91,17 +86,6 @@ protected: class OSystem_Android : public BaseBackend, public PaletteManager { private: - 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; @@ -138,18 +122,15 @@ private: Audio::MixerImpl *_mixer; Common::TimerManager *_timer; FilesystemFactory *_fsFactory; - Common::Archive *_asset_archive; timeval _startTime; - void setupScummVMSurface(); - void destroyScummVMSurface(); + void setupSurface(); void setupKeymapper(); void _setCursorPalette(const byte *colors, uint start, uint num); public: - OSystem_Android(jobject am); + OSystem_Android(); virtual ~OSystem_Android(); - bool initJavaHooks(JNIEnv *env); virtual void initBackend(); void addPluginDirectories(Common::FSList &dirs) const; diff --git a/backends/platform/android/asset-archive.h b/backends/platform/android/asset-archive.h index 28e48426e9..6ec86e4cd0 100644 --- a/backends/platform/android/asset-archive.h +++ b/backends/platform/android/asset-archive.h @@ -23,6 +23,9 @@ * */ +#ifndef _ANDROID_ASSET_H_ +#define _ANDROID_ASSET_H_ + #if defined(__ANDROID__) #include @@ -51,3 +54,5 @@ private: }; #endif +#endif + diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 2370958d30..838e5bc223 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -26,6 +26,7 @@ #if defined(__ANDROID__) #include "backends/platform/android/android.h" +#include "backends/platform/android/jni.h" static inline GLfixed xdiv(int numerator, int denominator) { assert(numerator < (1 << 16)); @@ -47,11 +48,13 @@ int OSystem_Android::getDefaultGraphicsMode() const { bool OSystem_Android::setGraphicsMode(const char *mode) { ENTER("%s", mode); + return true; } bool OSystem_Android::setGraphicsMode(int mode) { ENTER("%d", mode); + return true; } @@ -59,13 +62,10 @@ int OSystem_Android::getGraphicsMode() const { return 1; } -void OSystem_Android::setupScummVMSurface() { +void OSystem_Android::setupSurface() { ENTER(); - JNIEnv *env = JNI::getEnv(); - env->CallVoidMethod(back_ptr, MID_setupScummVMSurface); - - if (env->ExceptionCheck()) + if (!JNI::setupSurface()) return; // EGL set up with a new surface. Initialise OpenGLES context. @@ -115,12 +115,6 @@ void OSystem_Android::setupScummVMSurface() { clearFocusRectangle(); } -void OSystem_Android::destroyScummVMSurface() { - JNIEnv *env = JNI::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); @@ -158,6 +152,7 @@ void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { 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); } @@ -261,11 +256,10 @@ void OSystem_Android::updateScreen() { GLCALL(glPopMatrix()); - JNIEnv *env = JNI::getEnv(); - if (!env->CallBooleanMethod(back_ptr, MID_swapBuffers)) { + if (!JNI::swapBuffers()) { // Context lost -> need to reinit GL - destroyScummVMSurface(); - setupScummVMSurface(); + JNI::destroySurface(); + setupSurface(); } } diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 4fa08ef7ab..f24a60d48d 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -29,8 +29,8 @@ #include "common/config-manager.h" #include "backends/platform/android/android.h" - -jobject back_ptr; +#include "backends/platform/android/asset-archive.h" +#include "backends/platform/android/jni.h" __attribute__ ((visibility("default"))) jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { @@ -39,6 +39,8 @@ jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { JavaVM *JNI::_vm = 0; jobject JNI::_jobj = 0; + +Common::Archive *JNI::_asset_archive = 0; OSystem_Android *JNI::_system = 0; jfieldID JNI::_FID_Event_type = 0; @@ -51,6 +53,17 @@ jfieldID JNI::_FID_Event_mouse_y = 0; jfieldID JNI::_FID_Event_mouse_relative = 0; jfieldID JNI::_FID_ScummVM_nativeScummVM = 0; +jmethodID JNI::_MID_displayMessageOnOSD = 0; +jmethodID JNI::_MID_setWindowCaption = 0; +jmethodID JNI::_MID_initBackend = 0; +jmethodID JNI::_MID_audioSampleRate = 0; +jmethodID JNI::_MID_showVirtualKeyboard = 0; +jmethodID JNI::_MID_getSysArchives = 0; +jmethodID JNI::_MID_getPluginDirectories = 0; +jmethodID JNI::_MID_setupScummVMSurface = 0; +jmethodID JNI::_MID_destroyScummVMSurface = 0; +jmethodID JNI::_MID_swapBuffers = 0; + const JNINativeMethod JNI::_natives[] = { { "create", "(Landroid/content/res/AssetManager;)V", (void *)JNI::create }, @@ -179,21 +192,192 @@ void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) { env->DeleteLocalRef(cls); } +// calls to the dark side + +int JNI::getAudioSampleRate() { + JNIEnv *env = JNI::getEnv(); + + jint sample_rate = env->CallIntMethod(_jobj, _MID_audioSampleRate); + + if (env->ExceptionCheck()) { + warning("Error finding audio sample rate - assuming 11025HZ"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return 11025; + } + + return sample_rate; +} + +void JNI::initBackend() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_initBackend); + + if (env->ExceptionCheck()) { + error("Error in Java initBackend"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + // TODO now what? + } +} + +void JNI::getPluginDirectories(Common::FSList &dirs) { + JNIEnv *env = JNI::getEnv(); + + jobjectArray array = + (jobjectArray)env->CallObjectMethod(_jobj, _MID_getPluginDirectories); + + if (env->ExceptionCheck()) { + warning("Error finding plugin directories"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return; + } + + jsize size = env->GetArrayLength(array); + for (jsize i = 0; i < size; ++i) { + jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + + if (path_obj == 0) + continue; + + const char *path = env->GetStringUTFChars(path_obj, 0); + + if (path == 0) { + warning("Error getting string characters from plugin directory"); + + env->ExceptionClear(); + env->DeleteLocalRef(path_obj); + + continue; + } + + dirs.push_back(Common::FSNode(path)); + + env->ReleaseStringUTFChars(path_obj, path); + env->DeleteLocalRef(path_obj); + } +} + +void JNI::setWindowCaption(const char *caption) { + JNIEnv *env = JNI::getEnv(); + jstring java_caption = env->NewStringUTF(caption); + + env->CallVoidMethod(_jobj, _MID_setWindowCaption, java_caption); + + if (env->ExceptionCheck()) { + warning("Failed to set window caption"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + env->DeleteLocalRef(java_caption); +} + +void JNI::displayMessageOnOSD(const char *msg) { + JNIEnv *env = JNI::getEnv(); + jstring java_msg = env->NewStringUTF(msg); + + env->CallVoidMethod(_jobj, _MID_displayMessageOnOSD, java_msg); + + if (env->ExceptionCheck()) { + warning("Failed to display OSD message"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + env->DeleteLocalRef(java_msg); +} + +void JNI::showVirtualKeyboard(bool enable) { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_showVirtualKeyboard, enable); + + if (env->ExceptionCheck()) { + error("Error trying to show virtual keyboard"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { + JNIEnv *env = JNI::getEnv(); + + s.add("ASSET", _asset_archive, priority, false); + + jobjectArray array = + (jobjectArray)env->CallObjectMethod(_jobj, _MID_getSysArchives); + + if (env->ExceptionCheck()) { + warning("Error finding system archive path"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return; + } + + jsize size = env->GetArrayLength(array); + for (jsize i = 0; i < size; ++i) { + jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + const char *path = env->GetStringUTFChars(path_obj, 0); + + if (path != 0) { + s.addDirectory(path, path, priority); + env->ReleaseStringUTFChars(path_obj, path); + } + + env->DeleteLocalRef(path_obj); + } +} + +// natives for the dark side + void JNI::create(JNIEnv *env, jobject self, jobject am) { assert(!_system); - _system = new OSystem_Android(am); + _asset_archive = new AndroidAssetArchive(am); + assert(_asset_archive); + + _system = new OSystem_Android(); assert(_system); // weak global ref to allow class to be unloaded // ... except dalvik implements NewWeakGlobalRef only on froyo //_jobj = env->NewWeakGlobalRef(self); _jobj = env->NewGlobalRef(self); - back_ptr = _jobj; - // Exception already thrown by initJavaHooks? - if (!_system->initJavaHooks(env)) - return; + jclass cls = env->GetObjectClass(_jobj); + +#define FIND_METHOD(name, signature) do { \ + _MID_ ## name = env->GetMethodID(cls, #name, signature); \ + if (_MID_ ## name == 0) \ + return; \ + } while (0) + + FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V"); + FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V"); + FIND_METHOD(initBackend, "()V"); + FIND_METHOD(audioSampleRate, "()I"); + FIND_METHOD(showVirtualKeyboard, "(Z)V"); + FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); + FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); + FIND_METHOD(setupScummVMSurface, "()V"); + FIND_METHOD(destroyScummVMSurface, "()V"); + FIND_METHOD(swapBuffers, "()Z"); + +#undef FIND_METHOD env->SetLongField(self, _FID_ScummVM_nativeScummVM, (jlong)_system); @@ -208,6 +392,9 @@ void JNI::destroy(JNIEnv *env, jobject self) { _system = 0; delete tmp; + delete _asset_archive; + _asset_archive = 0; + // see above //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); JNI::getEnv()->DeleteGlobalRef(_jobj); diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 39276b9388..02eabba569 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -30,11 +30,16 @@ #include -extern jobject back_ptr; +#include "common/fs.h" +#include "common/archive.h" class OSystem_Android; class JNI { +private: + JNI(); + virtual ~JNI(); + public: static jint onLoad(JavaVM *vm); @@ -43,14 +48,24 @@ public: static void attachThread(); static void detachThread(); -private: - JNI(); - virtual ~JNI(); + static int getAudioSampleRate(); + static void initBackend(); + static void getPluginDirectories(Common::FSList &dirs); + static void setWindowCaption(const char *caption); + static void displayMessageOnOSD(const char *msg); + static void showVirtualKeyboard(bool enable); + static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); + + static inline bool setupSurface(); + static inline void destroySurface(); + static inline bool swapBuffers(); private: static JavaVM *_vm; // back pointer to (java) peer instance static jobject _jobj; + + static Common::Archive *_asset_archive; static OSystem_Android *_system; static jfieldID _FID_Event_type; @@ -63,6 +78,17 @@ private: static jfieldID _FID_Event_mouse_relative; static jfieldID _FID_ScummVM_nativeScummVM; + static jmethodID _MID_displayMessageOnOSD; + static jmethodID _MID_setWindowCaption; + static jmethodID _MID_initBackend; + static jmethodID _MID_audioSampleRate; + static jmethodID _MID_showVirtualKeyboard; + static jmethodID _MID_getSysArchives; + static jmethodID _MID_getPluginDirectories; + static jmethodID _MID_setupScummVMSurface; + static jmethodID _MID_destroyScummVMSurface; + static jmethodID _MID_swapBuffers; + static const JNINativeMethod _natives[]; static void throwByName(JNIEnv *env, const char *name, const char *msg); @@ -82,6 +108,26 @@ private: jint height); }; +inline bool JNI::setupSurface() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_setupScummVMSurface); + + return !env->ExceptionCheck(); +} + +inline void JNI::destroySurface() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_destroyScummVMSurface); +} + +inline bool JNI::swapBuffers() { + JNIEnv *env = JNI::getEnv(); + + return env->CallBooleanMethod(_jobj, _MID_swapBuffers); +} + #endif #endif -- cgit v1.2.3 From 0e9b4f3c506d64b0dfd931ac510ed773789f272e Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 21 Feb 2011 10:29:19 +0100 Subject: ANDROID: We are not a text editor This was probably set to ensure onCreateInputConnection() gets called, but it is regardless of this flag. Now the soft keyboard doesn't show up on startup on devices without physical keyboard, which prevents unnecessary surface changes. --- .../platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java index 5b71d4a3a5..1a0972d4dd 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java +++ b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java @@ -25,7 +25,7 @@ public class EditableSurfaceView extends SurfaceView { @Override public boolean onCheckIsTextEditor() { - return true; + return false; } private class MyInputConnection extends BaseInputConnection { -- cgit v1.2.3 From 867fa2696def58300cd376d03be6755007abbe43 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 22 Feb 2011 22:36:34 +0100 Subject: ANDROID: Let's not do that on the stack --- backends/platform/android/texture.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index b638976dc4..c5cba97dcd 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -166,9 +166,11 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, return; #if TEXSUBIMAGE_IS_EXPENSIVE - byte tmpbuf[w * h * bytesPerPixel()]; + byte *tmp = new byte[w * h * bytesPerPixel()]; + assert(tmp); + const byte *src = static_cast(buf); - byte *dst = tmpbuf; + byte *dst = tmp; GLuint count = h; do { @@ -178,7 +180,9 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, } while (--count); GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - glFormat(), glType(), tmpbuf)); + glFormat(), glType(), tmp)); + + delete[] tmp; #else // This version avoids the intermediate copy at the expense of // repeat glTexSubImage2D calls. On some devices this is worse. @@ -194,10 +198,15 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, } void GLESTexture::fillBuffer(byte x) { - int rowbytes = _surface.w * bytesPerPixel(); - byte tmpbuf[_surface.h * rowbytes]; - memset(tmpbuf, x, _surface.h * rowbytes); - updateBuffer(0, 0, _surface.w, _surface.h, tmpbuf, rowbytes); + uint rowbytes = _surface.w * bytesPerPixel(); + + byte *tmp = new byte[_surface.h * rowbytes]; + assert(tmp); + + memset(tmp, x, _surface.h * rowbytes); + updateBuffer(0, 0, _surface.w, _surface.h, tmp, rowbytes); + + delete[] tmp; } void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { -- cgit v1.2.3 From d8acbc0311fd126b0b3a2298082dadc98022f933 Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 23 Feb 2011 20:35:27 +0100 Subject: ANDROID: Deuglify overlay gfx Use the native surface resolution of the device if its not too big. If it is, use a clean scale factor of 2 to prevent eyecancer. --- backends/platform/android/gfx.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 838e5bc223..d4d96a239c 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -121,9 +121,22 @@ void OSystem_Android::initSize(uint width, uint height, _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); + GLuint overlay_width = _egl_surface_width; + GLuint overlay_height = _egl_surface_height; + + // 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 + if (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); // Don't know mouse size yet - it gets reallocated in -- cgit v1.2.3 From 36135443b9263e0125c8f9f2834818c2f9465983 Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 23 Feb 2011 21:13:25 +0100 Subject: ANDROID: Disable zoning for now --- backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index fae35b6695..09d39d25ea 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -52,7 +52,9 @@ public class ScummVMActivity extends Activity { super(ScummVMActivity.this); // Enable ScummVM zoning on 'small' screens. - enableZoning(usingSmallScreen()); + // FIXME make this optional for the user + // disabled for now since it crops too much + //enableZoning(usingSmallScreen()); } @Override -- cgit v1.2.3 From a636d41ca8c066adfed4fd16d9a2e46de5fab871 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 24 Feb 2011 18:24:27 +0100 Subject: ANDROID: Check thread origin when debugging GL --- backends/platform/android/android.cpp | 3 +++ backends/platform/android/android.h | 10 +++++++++- backends/platform/android/gfx.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 36399873cd..4968e4bba1 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -156,6 +156,8 @@ void *OSystem_Android::timerThreadFunc(void *arg) { void OSystem_Android::initBackend() { ENTER(); + _main_thread = pthread_self(); + ConfMan.setInt("autosave_period", 0); ConfMan.setInt("FM_medium_quality", true); @@ -350,6 +352,7 @@ void OSystem_Android::delayMillis(uint msecs) { OSystem::MutexRef OSystem_Android::createMutex() { pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 8fc138d42b..23c1e85a43 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -61,7 +61,7 @@ extern const char *android_log_tag; #ifdef ANDROID_DEBUG_ENTER #define ENTER(fmt, args...) LOGD("%s(" fmt ")", __FUNCTION__, ##args) #else -#define ENTER(fmt, args...) /**/ +#define ENTER(fmt, args...) do { } while (false) #endif #ifdef ANDROID_DEBUG_GL @@ -73,8 +73,14 @@ extern void checkGlError(const char *expr, const char *file, int line); 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 #ifdef DYNAMIC_MODULES @@ -111,6 +117,8 @@ private: Common::Queue _event_queue; MutexRef _event_queue_lock; + pthread_t _main_thread; + bool _timer_thread_exit; pthread_t _timer_thread; static void *timerThreadFunc(void *arg); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index d4d96a239c..a84e5ce4a0 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -119,6 +119,8 @@ void OSystem_Android::initSize(uint width, uint height, const Graphics::PixelFormat *format) { ENTER("%d, %d, %p", width, height, format); + GLTHREADCHECK; + _game_texture->allocBuffer(width, height); GLuint overlay_width = _egl_surface_width; @@ -157,6 +159,8 @@ int16 OSystem_Android::getWidth() { void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { ENTER("%p, %u, %u", colors, start, num); + GLTHREADCHECK; + if (!_use_mouse_palette) _setCursorPalette(colors, start, num); @@ -166,6 +170,8 @@ void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { ENTER("%p, %u, %u", colors, start, num); + GLTHREADCHECK; + memcpy(colors, _game_texture->palette_const() + start * 3, num * 3); } @@ -173,12 +179,16 @@ 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); + GLTHREADCHECK; + _game_texture->updateBuffer(x, y, w, h, buf, pitch); } void OSystem_Android::updateScreen() { //ENTER(); + GLTHREADCHECK; + if (!_force_redraw && !_game_texture->dirty() && !_overlay_texture->dirty() && @@ -279,6 +289,8 @@ void OSystem_Android::updateScreen() { Graphics::Surface *OSystem_Android::lockScreen() { ENTER(); + GLTHREADCHECK; + Graphics::Surface *surface = _game_texture->surface(); assert(surface->pixels); @@ -288,6 +300,8 @@ Graphics::Surface *OSystem_Android::lockScreen() { void OSystem_Android::unlockScreen() { ENTER(); + GLTHREADCHECK; + assert(_game_texture->dirty()); } @@ -303,6 +317,8 @@ void OSystem_Android::setShakePos(int shake_offset) { void OSystem_Android::fillScreen(uint32 col) { ENTER("%u", col); + GLTHREADCHECK; + assert(col < 256); _game_texture->fillBuffer(col); } @@ -342,6 +358,8 @@ void OSystem_Android::hideOverlay() { void OSystem_Android::clearOverlay() { ENTER(); + GLTHREADCHECK; + _overlay_texture->fillBuffer(0); // Shouldn't need this, but works around a 'blank screen' bug on Nexus1 @@ -351,6 +369,8 @@ void OSystem_Android::clearOverlay() { void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { ENTER("%p, %d", buf, pitch); + GLTHREADCHECK; + // 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... @@ -371,6 +391,8 @@ 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); + GLTHREADCHECK; + const Graphics::Surface *surface = _overlay_texture->surface_const(); assert(surface->bytesPerPixel == sizeof(buf[0])); @@ -411,6 +433,8 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY, keycolor, cursorTargetScale, format); + GLTHREADCHECK; + assert(keycolor < 256); _mouse_texture->allocBuffer(w, h); @@ -452,6 +476,8 @@ void OSystem_Android::setCursorPalette(const byte *colors, uint start, uint num) { ENTER("%p, %u, %u", colors, start, num); + GLTHREADCHECK; + _setCursorPalette(colors, start, num); _use_mouse_palette = true; } -- cgit v1.2.3 From e06b7431e8e199c169dd55b675bf7b8e70251e61 Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 25 Feb 2011 00:06:18 +0100 Subject: ANDROID: Remove weird workaround in clearScreen() This resulted in flickering all over the GUI --- backends/platform/android/gfx.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index a84e5ce4a0..35c91d724c 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -362,8 +362,9 @@ void OSystem_Android::clearOverlay() { _overlay_texture->fillBuffer(0); + // breaks more than it fixes, disabled for now // Shouldn't need this, but works around a 'blank screen' bug on Nexus1 - updateScreen(); + //updateScreen(); } void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { -- cgit v1.2.3 From 3fb85835a10eb75c7a5b2f40504004abd94c73c3 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 26 Feb 2011 11:18:12 +0100 Subject: ANDROID: Allow softkeybd on all devices --- .../org/inodes/gus/scummvm/ScummVMActivity.java | 33 +++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 09d39d25ea..8929809999 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -97,14 +97,11 @@ public class ScummVMActivity extends Activity { @Override protected void showVirtualKeyboard(final boolean enable) { - if (getResources().getConfiguration().keyboard == - Configuration.KEYBOARD_NOKEYS) { - runOnUiThread(new Runnable() { - public void run() { - showKeyboard(enable); - } - }); - } + runOnUiThread(new Runnable() { + public void run() { + showKeyboard(enable); + } + }); } } private MyScummVM scummvm; @@ -271,18 +268,16 @@ public class ScummVMActivity extends Activity { if (kevent.getRepeatCount() > 0) // Ignore keyrepeat for menu return false; - boolean timeout_fired = false; - if (getResources().getConfiguration().keyboard == - Configuration.KEYBOARD_NOKEYS) { - timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS); - keycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - if (kevent.getAction() == KeyEvent.ACTION_DOWN) { - keycodeMenuTimeoutHandler.sendMessageDelayed( - keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); - return true; - } + + boolean timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS); + keycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + + if (kevent.getAction() == KeyEvent.ACTION_DOWN) { + keycodeMenuTimeoutHandler.sendMessageDelayed(keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), + ViewConfiguration.getLongPressTimeout()); + return true; } + if (kevent.getAction() == KeyEvent.ACTION_UP) { if (!timeout_fired) scummvm.pushEvent(new Event(Event.EVENT_MAINMENU)); -- cgit v1.2.3 From 6b1c575d1d6471a922978559c69426b1f9856768 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 26 Feb 2011 12:34:55 +0100 Subject: ANDROID: Remove another weird workaround --- backends/platform/android/gfx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 35c91d724c..8601a3bfca 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -401,7 +401,7 @@ void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, _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(); + //updateScreen(); } int16 OSystem_Android::getOverlayHeight() { -- cgit v1.2.3 From 983e16b36a68292021833aa9b69305a37ffe2f91 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 26 Feb 2011 12:51:13 +0100 Subject: ANDROID: Formatting --- .../inodes/gus/scummvm/EditableSurfaceView.java | 13 ++- .../org/inodes/gus/scummvm/PluginProvider.java | 14 +-- .../android/org/inodes/gus/scummvm/ScummVM.java | 128 ++++++++++++++------- .../org/inodes/gus/scummvm/ScummVMActivity.java | 90 +++++++++++---- .../org/inodes/gus/scummvm/ScummVMApplication.java | 4 +- 5 files changed, 174 insertions(+), 75 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java index 1a0972d4dd..cede7eedd4 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java +++ b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java @@ -19,7 +19,7 @@ public class EditableSurfaceView extends SurfaceView { } public EditableSurfaceView(Context context, AttributeSet attrs, - int defStyle) { + int defStyle) { super(context, attrs, defStyle); } @@ -40,7 +40,9 @@ public class EditableSurfaceView extends SurfaceView { getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getWindowToken(), 0); } - return super.performEditorAction(actionCode); // Sends enter key + + // Sends enter key + return super.performEditorAction(actionCode); } } @@ -49,11 +51,12 @@ public class EditableSurfaceView extends SurfaceView { outAttrs.initialCapsMode = 0; outAttrs.initialSelEnd = outAttrs.initialSelStart = -1; outAttrs.inputType = (InputType.TYPE_CLASS_TEXT | - InputType.TYPE_TEXT_VARIATION_NORMAL | - InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); + InputType.TYPE_TEXT_VARIATION_NORMAL | + InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); outAttrs.imeOptions = (EditorInfo.IME_ACTION_DONE | - EditorInfo.IME_FLAG_NO_EXTRACT_UI); + EditorInfo.IME_FLAG_NO_EXTRACT_UI); return new MyInputConnection(); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java index c94ab0a3ff..3c91d9f5dc 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java +++ b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java @@ -28,7 +28,7 @@ public class PluginProvider extends BroadcastReceiver { try { info = context.getPackageManager() .getReceiverInfo(new ComponentName(context, this.getClass()), - PackageManager.GET_META_DATA); + PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { Log.e(LOG_TAG, "Error finding my own info?", e); return; @@ -38,17 +38,17 @@ public class PluginProvider extends BroadcastReceiver { if (mylib != null) { ArrayList all_libs = extras.getStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS); - all_libs.add(new Uri.Builder() - .scheme("plugin") - .authority(context.getPackageName()) - .path(mylib) - .toString()); + .scheme("plugin") + .authority(context.getPackageName()) + .path(mylib) + .toString()); extras.putStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS, - all_libs); + all_libs); } setResultExtras(extras); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 0e905f43a5..698e508605 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -35,16 +35,19 @@ import java.util.LinkedHashMap; public class ScummVM implements SurfaceHolder.Callback { protected final static String LOG_TAG = "ScummVM"; - private final int AUDIO_FRAME_SIZE = 2 * 2; // bytes. 16bit audio * stereo + // bytes. 16bit audio * stereo + private final int AUDIO_FRAME_SIZE = 2 * 2; public static class AudioSetupException extends Exception {} - private long nativeScummVM; // native code hangs itself here + // native code hangs itself here + private long nativeScummVM; boolean scummVMRunning = false; private native void create(AssetManager am); public ScummVM(Context context) { - create(context.getAssets()); // Init C++ code, set nativeScummVM + // Init C++ code, set nativeScummVM + create(context.getAssets()); } private native void nativeDestroy(); @@ -55,6 +58,7 @@ public class ScummVM implements SurfaceHolder.Callback { nativeScummVM = 0; } } + protected void finalize() { destroy(); } @@ -62,17 +66,17 @@ public class ScummVM implements SurfaceHolder.Callback { // Surface creation: // GUI thread: create surface, release lock // ScummVM thread: acquire lock (block), read surface - // + // Surface deletion: // GUI thread: post event, acquire lock (block), return // ScummVM thread: read event, free surface, release lock - // + // In other words, ScummVM thread does this: // acquire lock // setup surface // when SCREEN_CHANGED arrives: - // destroy surface - // release lock + // destroy surface + // release lock // back to acquire lock static final int configSpec[] = { EGL10.EGL_RED_SIZE, 5, @@ -82,6 +86,7 @@ public class ScummVM implements SurfaceHolder.Callback { EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT, EGL10.EGL_NONE, }; + EGL10 egl; EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY; EGLConfig eglConfig; @@ -96,7 +101,7 @@ public class ScummVM implements SurfaceHolder.Callback { } public void surfaceChanged(SurfaceHolder holder, int format, - int width, int height) { + int width, int height) { // Disabled while I debug GL problems pushEvent(new Event(Event.EVENT_SCREEN_CHANGED)); } @@ -111,6 +116,7 @@ public class ScummVM implements SurfaceHolder.Callback { // For debugging private static final Map attribs; + static { attribs = new LinkedHashMap(); attribs.put("CONFIG_ID", EGL10.EGL_CONFIG_ID); @@ -141,11 +147,14 @@ public class ScummVM implements SurfaceHolder.Callback { attribs.put("TRANSPARENT_GREEN_VALUE", EGL10.EGL_TRANSPARENT_GREEN_VALUE); attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE); } + private void dumpEglConfig(EGLConfig config) { int[] value = new int[1]; + for (Map.Entry entry : attribs.entrySet()) { egl.eglGetConfigAttrib(eglDisplay, config, - entry.getValue(), value); + entry.getValue(), value); + if (value[0] == EGL10.EGL_NONE) Log.d(LOG_TAG, entry.getKey() + ": NONE"); else @@ -157,12 +166,15 @@ public class ScummVM implements SurfaceHolder.Callback { private void createScummVMGLContext() { egl = (EGL10)EGLContext.getEGL(); eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + int[] version = new int[2]; egl.eglInitialize(eglDisplay, version); + int[] num_config = new int[1]; egl.eglChooseConfig(eglDisplay, configSpec, null, 0, num_config); final int numConfigs = num_config[0]; + if (numConfigs <= 0) throw new IllegalArgumentException("No configs match configSpec"); @@ -179,13 +191,15 @@ public class ScummVM implements SurfaceHolder.Callback { // Android's eglChooseConfig is busted in several versions and // devices so we have to filter/rank the configs again ourselves. eglConfig = chooseEglConfig(configs); + if (false) { Log.d(LOG_TAG, String.format("Chose EGL config from %d possibilities.", numConfigs)); dumpEglConfig(eglConfig); } eglContext = egl.eglCreateContext(eglDisplay, eglConfig, - EGL10.EGL_NO_CONTEXT, null); + EGL10.EGL_NO_CONTEXT, null); + if (eglContext == EGL10.EGL_NO_CONTEXT) throw new RuntimeException("Failed to create context"); } @@ -198,32 +212,43 @@ public class ScummVM implements SurfaceHolder.Callback { for (int i = 0; i < configs.length; i++) { EGLConfig config = configs[i]; int score = 10000; + egl.eglGetConfigAttrib(eglDisplay, config, - EGL10.EGL_SURFACE_TYPE, value); + EGL10.EGL_SURFACE_TYPE, value); + + // must have if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0) - continue; // must have + continue; egl.eglGetConfigAttrib(eglDisplay, config, - EGL10.EGL_CONFIG_CAVEAT, value); + EGL10.EGL_CONFIG_CAVEAT, value); + if (value[0] != EGL10.EGL_NONE) score -= 1000; // Must be at least 555, but then smaller is better - final int[] colorBits = {EGL10.EGL_RED_SIZE, - EGL10.EGL_GREEN_SIZE, - EGL10.EGL_BLUE_SIZE, - EGL10.EGL_ALPHA_SIZE}; + final int[] colorBits = { EGL10.EGL_RED_SIZE, + EGL10.EGL_GREEN_SIZE, + EGL10.EGL_BLUE_SIZE, + EGL10.EGL_ALPHA_SIZE + }; + for (int component : colorBits) { - egl.eglGetConfigAttrib(eglDisplay, config, - component, value); + egl.eglGetConfigAttrib(eglDisplay, config, component, value); + + // boost if >5 bits accuracy if (value[0] >= 5) - score += 10; // boost if >5 bits accuracy - score -= value[0]; // penalize for wasted bits + score += 10; + + // penalize for wasted bits + score -= value[0]; } egl.eglGetConfigAttrib(eglDisplay, config, - EGL10.EGL_DEPTH_SIZE, value); - score -= value[0]; // penalize for wasted bits + EGL10.EGL_DEPTH_SIZE, value); + + // penalize for wasted bits + score -= value[0]; if (score > bestScore) { best = i; @@ -248,28 +273,35 @@ public class ScummVM implements SurfaceHolder.Callback { Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e); return; } + eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, nativeSurface, null); + if (eglSurface == EGL10.EGL_NO_SURFACE) Log.e(LOG_TAG, "CreateWindowSurface failed!"); + egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); GL10 gl = (GL10)eglContext.getGL(); if (_log_version) { Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)", - egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION), - egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR), - gl.glGetString(GL10.GL_VERSION), - gl.glGetString(GL10.GL_RENDERER), - gl.glGetString(GL10.GL_VENDOR))); - _log_version = false; // only log this once + egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION), + egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR), + gl.glGetString(GL10.GL_VERSION), + gl.glGetString(GL10.GL_RENDERER), + gl.glGetString(GL10.GL_VENDOR))); + + // only log this once + _log_version = false; } int[] value = new int[1]; egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, value); + int width = value[0]; egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, value); + int height = value[0]; Log.i(LOG_TAG, String.format("New surface is %dx%d", width, height)); setSurfaceSize(width, height); @@ -279,7 +311,8 @@ public class ScummVM implements SurfaceHolder.Callback { protected void destroyScummVMSurface() { if (eglSurface != null) { egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + egl.eglDestroySurface(eglDisplay, eglSurface); eglSurface = EGL10.EGL_NO_SURFACE; } @@ -298,6 +331,7 @@ public class ScummVM implements SurfaceHolder.Callback { if (error == EGL11.EGL_CONTEXT_LOST) return false; } + return true; } @@ -324,6 +358,7 @@ public class ScummVM implements SurfaceHolder.Callback { protected void showVirtualKeyboard(boolean enable) {} protected String[] getSysArchives() { return new String[0]; } protected String[] getPluginDirectories() { return new String[0]; } + protected void initBackend() throws AudioSetupException { createScummVMGLContext(); initAudio(); @@ -375,17 +410,19 @@ public class ScummVM implements SurfaceHolder.Callback { scummvm.audioMixCallback(buf); offset = 0; } + int len = buf.length - offset; int ret = audio_track.write(buf, offset, len); if (ret < 0) { Log.w(LOG_TAG, String.format( - "AudioTrack.write(%dB) returned error %d", - buf.length, ret)); + "AudioTrack.write(%dB) returned error %d", + buf.length, ret)); break; } else if (ret != len) { Log.w(LOG_TAG, String.format( - "Short audio write. Wrote %dB, not %dB", - ret, buf.length)); + "Short audio write. Wrote %dB, not %dB", + ret, buf.length)); + // Buffer is full, so yield cpu for a while Thread.sleep(100); } @@ -409,21 +446,27 @@ public class ScummVM implements SurfaceHolder.Callback { AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT); if (buf_size < 0) { - int guess = AUDIO_FRAME_SIZE * sample_rate / 100; // 10ms of audio + // 10ms of audio + int guess = AUDIO_FRAME_SIZE * sample_rate / 100; + Log.w(LOG_TAG, String.format( "Unable to get min audio buffer size (error %d). Guessing %dB.", buf_size, guess)); + buf_size = guess; } + Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio", - buf_size, sample_rate)); + buf_size, sample_rate)); + AudioTrack audio_track = new AudioTrack(AudioManager.STREAM_MUSIC, - sample_rate, - AudioFormat.CHANNEL_CONFIGURATION_STEREO, - AudioFormat.ENCODING_PCM_16BIT, - buf_size, - AudioTrack.MODE_STREAM); + sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT, + buf_size, + AudioTrack.MODE_STREAM); + if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) { Log.e(LOG_TAG, "Error initialising Android audio system."); throw new AudioSetupException(); @@ -448,7 +491,7 @@ public class ScummVM implements SurfaceHolder.Callback { final boolean sleep_for_debugger = false; if (sleep_for_debugger) { try { - Thread.sleep(20*1000); + Thread.sleep(20 * 1000); } catch (InterruptedException e) { } } @@ -460,3 +503,4 @@ public class ScummVM implements SurfaceHolder.Callback { System.load(libpath.getPath()); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 8929809999..0dd110942b 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -38,6 +38,7 @@ public class ScummVMActivity extends Activity { // devices :( DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); + try { // This 'density' term is very confusing. int DENSITY_LOW = metrics.getClass().getField("DENSITY_LOW").getInt(null); @@ -63,6 +64,7 @@ public class ScummVMActivity extends Activity { scummvmRunning = true; notifyAll(); } + super.initBackend(); } @@ -104,6 +106,7 @@ public class ScummVMActivity extends Activity { }); } } + private MyScummVM scummvm; private Thread scummvm_thread; @@ -125,18 +128,18 @@ public class ScummVMActivity extends Activity { .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(R.string.no_sdcard) .setNegativeButton(R.string.quit, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int which) { - finish(); - } - }) + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + finish(); + } + }) .show(); + return; } SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); - main_surface.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { return onTouchEvent(event); @@ -151,6 +154,7 @@ public class ScummVMActivity extends Activity { // Start ScummVM scummvm = new MyScummVM(); + scummvm_thread = new Thread(new Runnable() { public void run() { try { @@ -166,6 +170,7 @@ public class ScummVMActivity extends Activity { } } }, "ScummVM"); + scummvm_thread.start(); // Block UI thread until ScummVM has started. In particular, @@ -207,14 +212,17 @@ public class ScummVMActivity extends Activity { was_paused = true; scummvm.pause(); } + super.onPause(); } @Override public void onResume() { super.onResume(); + if (scummvm != null && was_paused) scummvm.resume(); + was_paused = false; } @@ -222,16 +230,20 @@ public class ScummVMActivity extends Activity { public void onStop() { if (scummvm != null) { scummvm.pushEvent(new Event(Event.EVENT_QUIT)); + try { - scummvm_thread.join(1000); // 1s timeout + // 1s timeout + scummvm_thread.join(1000); } catch (InterruptedException e) { Log.i(ScummVM.LOG_TAG, "Error while joining ScummVM thread", e); } } + super.onStop(); } static final int MSG_MENU_LONG_PRESS = 1; + private final Handler keycodeMenuTimeoutHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -251,7 +263,7 @@ public class ScummVMActivity extends Activity { @Override public boolean onKeyMultiple(int keyCode, int repeatCount, - KeyEvent kevent) { + KeyEvent kevent) { return onKeyDown(keyCode, kevent); } @@ -261,12 +273,12 @@ public class ScummVMActivity extends Activity { switch (keyCode) { case KeyEvent.KEYCODE_MENU: // Have to reimplement hold-down-menu-brings-up-softkeybd - // ourselves, since we are otherwise hijacking the menu - // key :( + // ourselves, since we are otherwise hijacking the menu key :( // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel() // for the usual Android implementation of this feature. + + // Ignore keyrepeat for menu if (kevent.getRepeatCount() > 0) - // Ignore keyrepeat for menu return false; boolean timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS); @@ -274,20 +286,24 @@ public class ScummVMActivity extends Activity { if (kevent.getAction() == KeyEvent.ACTION_DOWN) { keycodeMenuTimeoutHandler.sendMessageDelayed(keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); + ViewConfiguration.getLongPressTimeout()); return true; } if (kevent.getAction() == KeyEvent.ACTION_UP) { if (!timeout_fired) scummvm.pushEvent(new Event(Event.EVENT_MAINMENU)); + return true; } + return false; + case KeyEvent.KEYCODE_CAMERA: case KeyEvent.KEYCODE_SEARCH: _do_right_click = (kevent.getAction() == KeyEvent.ACTION_DOWN); return true; + case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_DOWN: @@ -299,45 +315,59 @@ public class ScummVMActivity extends Activity { // Some other handsets lack a trackball, so the DPAD is // the only way of moving the cursor. int motion_action; + // FIXME: this logic is a mess. if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { switch (kevent.getAction()) { case KeyEvent.ACTION_DOWN: motion_action = MotionEvent.ACTION_DOWN; break; + case KeyEvent.ACTION_UP: motion_action = MotionEvent.ACTION_UP; break; - default: // ACTION_MULTIPLE + + // ACTION_MULTIPLE + default: return false; } - } else + } else { motion_action = MotionEvent.ACTION_MOVE; + } Event e = new Event(getEventType(motion_action)); + e.mouse_x = 0; e.mouse_y = 0; e.mouse_relative = true; + switch (keyCode) { case KeyEvent.KEYCODE_DPAD_UP: e.mouse_y = -TRACKBALL_SCALE; break; + case KeyEvent.KEYCODE_DPAD_DOWN: e.mouse_y = TRACKBALL_SCALE; break; + case KeyEvent.KEYCODE_DPAD_LEFT: e.mouse_x = -TRACKBALL_SCALE; break; + case KeyEvent.KEYCODE_DPAD_RIGHT: e.mouse_x = TRACKBALL_SCALE; break; } + scummvm.pushEvent(e); + return true; } + case KeyEvent.KEYCODE_BACK: // skip isSystem() check and fall through to main code break; + default: if (kevent.isSystem()) return false; @@ -352,51 +382,63 @@ public class ScummVMActivity extends Activity { e.type = Event.EVENT_KEYDOWN; e.synthetic = false; break; + case KeyEvent.ACTION_UP: e.type = Event.EVENT_KEYUP; e.synthetic = false; break; + case KeyEvent.ACTION_MULTIPLE: // e.type is handled below e.synthetic = true; break; + default: return false; } e.kbd_keycode = Event.androidKeyMap.containsKey(keyCode) ? Event.androidKeyMap.get(keyCode) : Event.KEYCODE_INVALID; + e.kbd_ascii = kevent.getUnicodeChar(); + if (e.kbd_ascii == 0) e.kbd_ascii = e.kbd_keycode; // scummvm keycodes are mostly ascii - e.kbd_flags = 0; + if (kevent.isAltPressed()) e.kbd_flags |= Event.KBD_ALT; - if (kevent.isSymPressed()) // no ctrl key in android, so use sym (?) + + // no ctrl key in android, so use sym (?) + if (kevent.isSymPressed()) e.kbd_flags |= Event.KBD_CTRL; + if (kevent.isShiftPressed()) { if (keyCode >= KeyEvent.KEYCODE_0 && - keyCode <= KeyEvent.KEYCODE_9) { + keyCode <= KeyEvent.KEYCODE_9) { // Shift+number -> convert to F* key int offset = keyCode == KeyEvent.KEYCODE_0 ? 10 : keyCode - KeyEvent.KEYCODE_1; // turn 0 into 10 + e.kbd_keycode = Event.KEYCODE_F1 + offset; e.kbd_ascii = Event.ASCII_F1 + offset; - } else + } else { e.kbd_flags |= Event.KBD_SHIFT; + } } if (kevent.getAction() == KeyEvent.ACTION_MULTIPLE) { for (int i = 0; i <= kevent.getRepeatCount(); i++) { e.type = Event.EVENT_KEYDOWN; scummvm.pushEvent(e); + e.type = Event.EVENT_KEYUP; scummvm.pushEvent(e); } - } else + } else { scummvm.pushEvent(e); + } return true; } @@ -407,11 +449,14 @@ public class ScummVMActivity extends Activity { _last_click_was_right = _do_right_click; return _last_click_was_right ? Event.EVENT_RBUTTONDOWN : Event.EVENT_LBUTTONDOWN; + case MotionEvent.ACTION_UP: return _last_click_was_right ? Event.EVENT_RBUTTONUP : Event.EVENT_LBUTTONUP; + case MotionEvent.ACTION_MOVE: return Event.EVENT_MOUSEMOVE; + default: return Event.EVENT_INVALID; } @@ -429,6 +474,7 @@ public class ScummVMActivity extends Activity { e.mouse_y = (int)(event.getY() * event.getYPrecision()) * TRACKBALL_SCALE; e.mouse_relative = true; + scummvm.pushEvent(e); return true; @@ -437,6 +483,7 @@ public class ScummVMActivity extends Activity { @Override public boolean onTouchEvent(MotionEvent event) { int type = getEventType(event.getAction()); + if (type == Event.EVENT_INVALID) return false; @@ -444,6 +491,7 @@ public class ScummVMActivity extends Activity { e.mouse_x = (int)event.getX(); e.mouse_y = (int)event.getY(); e.mouse_relative = false; + scummvm.pushEvent(e); return true; @@ -453,6 +501,7 @@ public class ScummVMActivity extends Activity { SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + if (show) imm.showSoftInput(main_surface, InputMethodManager.SHOW_IMPLICIT); else @@ -460,3 +509,4 @@ public class ScummVMActivity extends Activity { InputMethodManager.HIDE_IMPLICIT_ONLY); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java index 37a9d09e1a..80735e2c2a 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java @@ -13,11 +13,12 @@ public class ScummVMApplication extends Application { @Override public void onCreate() { super.onCreate(); + // This is still on /data :( cache_dir = getCacheDir(); // This is mounted noexec :( //cache_dir = new File(Environment.getExternalStorageDirectory(), - // "/.ScummVM.tmp"); + // "/.ScummVM.tmp"); // This is owned by download manager and requires special // permissions to access :( //cache_dir = Environment.getDownloadCacheDirectory(); @@ -27,3 +28,4 @@ public class ScummVMApplication extends Application { return cache_dir; } } + -- cgit v1.2.3 From 25d895b859af0df8ea6daa85ba6ec5a0acb81f9d Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 26 Feb 2011 14:53:02 +0100 Subject: ANDROID: Rework audio system Move the audio thread to the bright side --- backends/platform/android/android.cpp | 87 ++++++++++- backends/platform/android/android.h | 10 +- backends/platform/android/jni.cpp | 111 ++++++++------ backends/platform/android/jni.h | 23 ++- .../android/org/inodes/gus/scummvm/ScummVM.java | 168 +++++---------------- .../org/inodes/gus/scummvm/ScummVMActivity.java | 12 +- 6 files changed, 231 insertions(+), 180 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 4968e4bba1..08b957999e 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -26,6 +26,7 @@ #if defined(__ANDROID__) #include +#include #include #include @@ -98,7 +99,9 @@ static inline T scalef(T in, float numerator, float denominator) { return static_cast(in) * numerator / denominator; } -OSystem_Android::OSystem_Android() : +OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : + _audio_sample_rate(audio_sample_rate), + _audio_buffer_size(audio_buffer_size), _screen_changeid(0), _force_redraw(false), _game_texture(0), @@ -137,6 +140,10 @@ void *OSystem_Android::timerThreadFunc(void *arg) { OSystem_Android *system = (OSystem_Android *)arg; DefaultTimerManager *timer = (DefaultTimerManager *)(system->_timer); + // renice this thread to boost the audio thread + if (setpriority(PRIO_PROCESS, 0, 19) < 0) + warning("couldn't renice the timer thread"); + JNI::attachThread(); struct timespec tv; @@ -153,6 +160,72 @@ void *OSystem_Android::timerThreadFunc(void *arg) { return 0; } +void *OSystem_Android::audioThreadFunc(void *arg) { + JNI::attachThread(); + + JNI::setAudioPlay(); + + OSystem_Android *system = (OSystem_Android *)arg; + Audio::MixerImpl *mixer = system->_mixer; + + uint buf_size = system->_audio_buffer_size; + + JNIEnv *env = JNI::getEnv(); + + jbyteArray bufa = env->NewByteArray(buf_size); + + byte *buf; + int offset, left, written; + + struct timespec tv; + tv.tv_sec = 0; + tv.tv_nsec = 20 * 1000 * 1000; + + while (!system->_audio_thread_exit) { + buf = (byte *)env->GetPrimitiveArrayCritical(bufa, 0); + assert(buf); + + mixer->mixCallback(buf, buf_size); + + env->ReleasePrimitiveArrayCritical(bufa, buf, 0); + + offset = 0; + left = buf_size; + written = 0; + + while (left > 0) { + written = JNI::writeAudio(env, bufa, offset, left); + + if (written < 0) { + error("AudioTrack error: %d", written); + break; + } + + // buffer full + if (written < left) + nanosleep(&tv, 0); + + offset += written; + left -= written; + } + + if (written < 0) + break; + + // sleep a little, prepare the next buffer, and run into the + // blocking AudioTrack.write + nanosleep(&tv, 0); + } + + JNI::setAudioStop(); + + env->DeleteLocalRef(bufa); + + JNI::detachThread(); + + return 0; +} + void OSystem_Android::initBackend() { ENTER(); @@ -173,7 +246,7 @@ void OSystem_Android::initBackend() { gettimeofday(&_startTime, 0); - _mixer = new Audio::MixerImpl(this, JNI::getAudioSampleRate()); + _mixer = new Audio::MixerImpl(this, _audio_sample_rate); _mixer->setReady(true); JNI::initBackend(); @@ -181,9 +254,16 @@ void OSystem_Android::initBackend() { _timer_thread_exit = false; pthread_create(&_timer_thread, 0, timerThreadFunc, this); + _audio_thread_exit = false; + pthread_create(&_audio_thread, 0, audioThreadFunc, this); + OSystem::initBackend(); setupSurface(); + + // renice this thread to boost the audio thread + if (setpriority(PRIO_PROCESS, 0, 19) < 0) + warning("couldn't renice the main thread"); } void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { @@ -391,6 +471,9 @@ void OSystem_Android::deleteMutex(MutexRef mutex) { void OSystem_Android::quit() { ENTER(); + _audio_thread_exit = true; + pthread_join(_audio_thread, 0); + _timer_thread_exit = true; pthread_join(_timer_thread, 0); } diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 23c1e85a43..f4e9d611d4 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -92,6 +92,10 @@ protected: class OSystem_Android : public BaseBackend, public PaletteManager { private: + // passed from the dark side + int _audio_sample_rate; + int _audio_buffer_size; + int _screen_changeid; int _egl_surface_width; int _egl_surface_height; @@ -123,6 +127,10 @@ private: pthread_t _timer_thread; static void *timerThreadFunc(void *arg); + bool _audio_thread_exit; + pthread_t _audio_thread; + static void *audioThreadFunc(void *arg); + bool _enable_zoning; bool _virtkeybd_on; @@ -137,7 +145,7 @@ private: void _setCursorPalette(const byte *colors, uint start, uint num); public: - OSystem_Android(); + OSystem_Android(int audio_sample_rate, int audio_buffer_size); virtual ~OSystem_Android(); virtual void initBackend(); diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index f24a60d48d..5e11203db8 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -39,6 +39,7 @@ jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { JavaVM *JNI::_vm = 0; jobject JNI::_jobj = 0; +jobject JNI::_jobj_audio_track = 0; Common::Archive *JNI::_asset_archive = 0; OSystem_Android *JNI::_system = 0; @@ -56,7 +57,6 @@ jfieldID JNI::_FID_ScummVM_nativeScummVM = 0; jmethodID JNI::_MID_displayMessageOnOSD = 0; jmethodID JNI::_MID_setWindowCaption = 0; jmethodID JNI::_MID_initBackend = 0; -jmethodID JNI::_MID_audioSampleRate = 0; jmethodID JNI::_MID_showVirtualKeyboard = 0; jmethodID JNI::_MID_getSysArchives = 0; jmethodID JNI::_MID_getPluginDirectories = 0; @@ -64,8 +64,14 @@ jmethodID JNI::_MID_setupScummVMSurface = 0; jmethodID JNI::_MID_destroyScummVMSurface = 0; jmethodID JNI::_MID_swapBuffers = 0; +jmethodID JNI::_MID_AudioTrack_pause = 0; +jmethodID JNI::_MID_AudioTrack_play = 0; +jmethodID JNI::_MID_AudioTrack_stop = 0; +jmethodID JNI::_MID_AudioTrack_write = 0; + const JNINativeMethod JNI::_natives[] = { - { "create", "(Landroid/content/res/AssetManager;)V", + { "create", "(Landroid/content/res/AssetManager;" + "Landroid/media/AudioTrack;II)V", (void *)JNI::create }, { "nativeDestroy", "()V", (void *)JNI::destroy }, @@ -73,8 +79,6 @@ const JNINativeMethod JNI::_natives[] = { (void *)JNI::main }, { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", (void *)JNI::pushEvent }, - { "audioMixCallback", "([B)V", - (void *)JNI::audioMixCallback }, { "setConfMan", "(Ljava/lang/String;I)V", (void *)JNI::setConfManInt }, { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V", @@ -194,23 +198,6 @@ void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) { // calls to the dark side -int JNI::getAudioSampleRate() { - JNIEnv *env = JNI::getEnv(); - - jint sample_rate = env->CallIntMethod(_jobj, _MID_audioSampleRate); - - if (env->ExceptionCheck()) { - warning("Error finding audio sample rate - assuming 11025HZ"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return 11025; - } - - return sample_rate; -} - void JNI::initBackend() { JNIEnv *env = JNI::getEnv(); @@ -342,15 +329,55 @@ void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { } } +void JNI::setAudioPause() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_pause); + + if (env->ExceptionCheck()) { + warning("Error setting AudioTrack: pause"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +void JNI::setAudioPlay() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_play); + + if (env->ExceptionCheck()) { + warning("Error setting AudioTrack: play"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +void JNI::setAudioStop() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_stop); + + if (env->ExceptionCheck()) { + warning("Error setting AudioTrack: stop"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + // natives for the dark side -void JNI::create(JNIEnv *env, jobject self, jobject am) { +void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, + jint audio_sample_rate, jint audio_buffer_size) { assert(!_system); _asset_archive = new AndroidAssetArchive(am); assert(_asset_archive); - _system = new OSystem_Android(); + _system = new OSystem_Android(audio_sample_rate, audio_buffer_size); assert(_system); // weak global ref to allow class to be unloaded @@ -369,7 +396,6 @@ void JNI::create(JNIEnv *env, jobject self, jobject am) { FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V"); FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V"); FIND_METHOD(initBackend, "()V"); - FIND_METHOD(audioSampleRate, "()I"); FIND_METHOD(showVirtualKeyboard, "(Z)V"); FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); @@ -381,6 +407,23 @@ void JNI::create(JNIEnv *env, jobject self, jobject am) { env->SetLongField(self, _FID_ScummVM_nativeScummVM, (jlong)_system); + _jobj_audio_track = env->NewGlobalRef(at); + + cls = env->GetObjectClass(_jobj_audio_track); + +#define FIND_METHOD(name, signature) do { \ + _MID_AudioTrack_ ## name = env->GetMethodID(cls, #name, signature); \ + if (_MID_AudioTrack_ ## name == 0) \ + return; \ + } while (0) + + FIND_METHOD(pause, "()V"); + FIND_METHOD(play, "()V"); + FIND_METHOD(stop, "()V"); + FIND_METHOD(write, "([BII)I"); + +#undef FIND_METHOD + g_system = _system; } @@ -397,6 +440,7 @@ void JNI::destroy(JNIEnv *env, jobject self) { // see above //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); + JNI::getEnv()->DeleteGlobalRef(_jobj_audio_track); JNI::getEnv()->DeleteGlobalRef(_jobj); } @@ -514,25 +558,6 @@ void JNI::pushEvent(JNIEnv *env, jobject self, jobject java_event) { _system->pushEvent(event); } -void JNI::audioMixCallback(JNIEnv *env, jobject self, jbyteArray jbuf) { - assert(_system); - - 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(_system->getMixer()); - assert(mixer); - mixer->mixCallback(reinterpret_cast(buf), len); - - env->ReleaseByteArrayElements(jbuf, buf, 0); -} - void JNI::setConfManInt(JNIEnv *env, jclass cls, jstring key_obj, jint value) { ENTER("%p, %d", key_obj, (int)value); diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 02eabba569..a1fc3df67e 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -48,7 +48,6 @@ public: static void attachThread(); static void detachThread(); - static int getAudioSampleRate(); static void initBackend(); static void getPluginDirectories(Common::FSList &dirs); static void setWindowCaption(const char *caption); @@ -60,10 +59,18 @@ public: static inline void destroySurface(); static inline bool swapBuffers(); + static void setAudioPause(); + static void setAudioPlay(); + static void setAudioStop(); + + static inline int writeAudio(JNIEnv *env, jbyteArray &data, int offset, + int size); + private: static JavaVM *_vm; // back pointer to (java) peer instance static jobject _jobj; + static jobject _jobj_audio_track; static Common::Archive *_asset_archive; static OSystem_Android *_system; @@ -81,7 +88,6 @@ private: static jmethodID _MID_displayMessageOnOSD; static jmethodID _MID_setWindowCaption; static jmethodID _MID_initBackend; - static jmethodID _MID_audioSampleRate; static jmethodID _MID_showVirtualKeyboard; static jmethodID _MID_getSysArchives; static jmethodID _MID_getPluginDirectories; @@ -89,16 +95,21 @@ private: static jmethodID _MID_destroyScummVMSurface; static jmethodID _MID_swapBuffers; + static jmethodID _MID_AudioTrack_pause; + static jmethodID _MID_AudioTrack_play; + static jmethodID _MID_AudioTrack_stop; + static jmethodID _MID_AudioTrack_write; + static const JNINativeMethod _natives[]; static void throwByName(JNIEnv *env, const char *name, const char *msg); // natives for the dark side - static void create(JNIEnv *env, jobject self, jobject am); + static void create(JNIEnv *env, jobject self, jobject am, jobject at, + jint sample_rate, jint buffer_size); static void destroy(JNIEnv *env, jobject self); static jint main(JNIEnv *env, jobject self, jobjectArray args); static void pushEvent(JNIEnv *env, jobject self, jobject java_event); - static void audioMixCallback(JNIEnv *env, jobject self, jbyteArray jbuf); static void setConfManInt(JNIEnv *env, jclass cls, jstring key_obj, jint value); static void setConfManString(JNIEnv *env, jclass cls, jstring key_obj, @@ -128,6 +139,10 @@ inline bool JNI::swapBuffers() { return env->CallBooleanMethod(_jobj, _MID_swapBuffers); } +inline int JNI::writeAudio(JNIEnv *env, jbyteArray &data, int offset, int size) { + return env->CallIntMethod(_jobj_audio_track, _MID_AudioTrack_write, data, offset, size); +} + #endif #endif diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 698e508605..7a326454d9 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -35,19 +35,48 @@ import java.util.LinkedHashMap; public class ScummVM implements SurfaceHolder.Callback { protected final static String LOG_TAG = "ScummVM"; - // bytes. 16bit audio * stereo - private final int AUDIO_FRAME_SIZE = 2 * 2; - public static class AudioSetupException extends Exception {} - // native code hangs itself here private long nativeScummVM; boolean scummVMRunning = false; - private native void create(AssetManager am); + private native void create(AssetManager am, AudioTrack audio_track, + int sample_rate, int buffer_size); + + public ScummVM(Context context) throws Exception { + int sample_rate = AudioTrack.getNativeOutputSampleRate( + AudioManager.STREAM_MUSIC); + int buffer_size = AudioTrack.getMinBufferSize(sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT); + + // ~100ms + int buffer_size_want = (sample_rate * 2 * 2 / 10) & ~1023; + + if (buffer_size < buffer_size_want) { + Log.w(LOG_TAG, String.format( + "adjusting audio buffer size (was: %d)", buffer_size)); + + buffer_size = buffer_size_want; + } + + Log.i(LOG_TAG, String.format("Using %d bytes buffer for %dHz audio", + buffer_size, sample_rate)); + + AudioTrack audio_track = + new AudioTrack(AudioManager.STREAM_MUSIC, + sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT, + buffer_size, + AudioTrack.MODE_STREAM); + + if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) + throw new Exception( + String.format("Error initialising AudioTrack: %d", + audio_track.getState())); - public ScummVM(Context context) { // Init C++ code, set nativeScummVM - create(context.getAssets()); + create(context.getAssets(), audio_track, sample_rate, buffer_size); } private native void nativeDestroy(); @@ -345,8 +374,6 @@ public class ScummVM implements SurfaceHolder.Callback { // Feed an event to ScummVM. Safe to call from other threads. final public native void pushEvent(Event e); - final private native void audioMixCallback(byte[] buf); - // Runs the actual ScummVM program and returns when it does. // This should not be called from multiple threads simultaneously... final public native int scummVMMain(String[] argv); @@ -359,131 +386,18 @@ public class ScummVM implements SurfaceHolder.Callback { protected String[] getSysArchives() { return new String[0]; } protected String[] getPluginDirectories() { return new String[0]; } - protected void initBackend() throws AudioSetupException { + protected void initBackend() { createScummVMGLContext(); - initAudio(); - } - - private static class AudioThread extends Thread { - final private int buf_size; - private boolean is_paused = false; - final private ScummVM scummvm; - final private AudioTrack audio_track; - - AudioThread(ScummVM scummvm, AudioTrack audio_track, int buf_size) { - super("AudioThread"); - this.scummvm = scummvm; - this.audio_track = audio_track; - this.buf_size = buf_size; - setPriority(Thread.MAX_PRIORITY); - setDaemon(true); - } - - public void pauseAudio() { - synchronized (this) { - is_paused = true; - } - audio_track.pause(); - } - - public void resumeAudio() { - synchronized (this) { - is_paused = false; - notifyAll(); - } - audio_track.play(); - } - - public void run() { - byte[] buf = new byte[buf_size]; - audio_track.play(); - int offset = 0; - try { - while (true) { - synchronized (this) { - while (is_paused) - wait(); - } - - if (offset == buf.length) { - // Grab new audio data - scummvm.audioMixCallback(buf); - offset = 0; - } - - int len = buf.length - offset; - int ret = audio_track.write(buf, offset, len); - if (ret < 0) { - Log.w(LOG_TAG, String.format( - "AudioTrack.write(%dB) returned error %d", - buf.length, ret)); - break; - } else if (ret != len) { - Log.w(LOG_TAG, String.format( - "Short audio write. Wrote %dB, not %dB", - ret, buf.length)); - - // Buffer is full, so yield cpu for a while - Thread.sleep(100); - } - offset += ret; - } - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Audio thread interrupted", e); - } - } - } - private AudioThread audio_thread; - - final public int audioSampleRate() { - return AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); - } - - private void initAudio() throws AudioSetupException { - int sample_rate = audioSampleRate(); - int buf_size = - AudioTrack.getMinBufferSize(sample_rate, - AudioFormat.CHANNEL_CONFIGURATION_STEREO, - AudioFormat.ENCODING_PCM_16BIT); - if (buf_size < 0) { - // 10ms of audio - int guess = AUDIO_FRAME_SIZE * sample_rate / 100; - - Log.w(LOG_TAG, String.format( - "Unable to get min audio buffer size (error %d). Guessing %dB.", - buf_size, guess)); - - buf_size = guess; - } - - Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio", - buf_size, sample_rate)); - - AudioTrack audio_track = - new AudioTrack(AudioManager.STREAM_MUSIC, - sample_rate, - AudioFormat.CHANNEL_CONFIGURATION_STEREO, - AudioFormat.ENCODING_PCM_16BIT, - buf_size, - AudioTrack.MODE_STREAM); - - if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) { - Log.e(LOG_TAG, "Error initialising Android audio system."); - throw new AudioSetupException(); - } - - audio_thread = new AudioThread(this, audio_track, buf_size); - audio_thread.start(); } public void pause() { - audio_thread.pauseAudio(); - // TODO: need to pause engine too + // TODO: need to pause audio + // TODO: need to pause engine } public void resume() { - // TODO: need to resume engine too - audio_thread.resumeAudio(); + // TODO: need to resume audio + // TODO: need to resume engine } static { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 0dd110942b..fb6020cf1c 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -49,7 +49,7 @@ public class ScummVMActivity extends Activity { } } - public MyScummVM() { + public MyScummVM() throws Exception { super(ScummVMActivity.this); // Enable ScummVM zoning on 'small' screens. @@ -59,7 +59,7 @@ public class ScummVMActivity extends Activity { } @Override - protected void initBackend() throws ScummVM.AudioSetupException { + protected void initBackend() { synchronized (this) { scummvmRunning = true; notifyAll(); @@ -153,7 +153,13 @@ public class ScummVMActivity extends Activity { main_surface.requestFocus(); // Start ScummVM - scummvm = new MyScummVM(); + try { + scummvm = new MyScummVM(); + } catch (Exception e) { + Log.e(ScummVM.LOG_TAG, "Fatal error", e); + finish(); + return; + } scummvm_thread = new Thread(new Runnable() { public void run() { -- cgit v1.2.3 From 0e869a5cf0e455f7cd5ce5c39192f3433b931e97 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 26 Feb 2011 18:44:17 +0100 Subject: ANDROID: Pause the AudioTrack when possible Only works in situations without any registered channels (or all paused) at the mixer (like on the launcher or GMM). CPU usage before (Galaxy Tab): ~5% scummvm ~15% mediaserver After: ~2% scummvm 0% mediaserver ;) --- backends/platform/android/android.cpp | 53 +++++++++++++++++++++++++++++------ backends/platform/android/jni.cpp | 11 ++++++++ backends/platform/android/jni.h | 1 + 3 files changed, 57 insertions(+), 8 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 08b957999e..860ff1f7ee 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -163,8 +163,6 @@ void *OSystem_Android::timerThreadFunc(void *arg) { void *OSystem_Android::audioThreadFunc(void *arg) { JNI::attachThread(); - JNI::setAudioPlay(); - OSystem_Android *system = (OSystem_Android *)arg; Audio::MixerImpl *mixer = system->_mixer; @@ -174,21 +172,60 @@ void *OSystem_Android::audioThreadFunc(void *arg) { jbyteArray bufa = env->NewByteArray(buf_size); + bool paused = true; + byte *buf; int offset, left, written; + int samples; - struct timespec tv; - tv.tv_sec = 0; - tv.tv_nsec = 20 * 1000 * 1000; + struct timespec tv_delay; + tv_delay.tv_sec = 0; + tv_delay.tv_nsec = 20 * 1000 * 1000; + + uint msecs_full = buf_size * 1000 / (mixer->getOutputRate() * 2 * 2); + + struct timespec tv_full; + tv_full.tv_sec = 0; + tv_full.tv_nsec = msecs_full * 1000 * 1000; + + uint silence_count = 0; while (!system->_audio_thread_exit) { buf = (byte *)env->GetPrimitiveArrayCritical(bufa, 0); assert(buf); - mixer->mixCallback(buf, buf_size); + samples = mixer->mixCallback(buf, buf_size); env->ReleasePrimitiveArrayCritical(bufa, buf, 0); + if (samples < 1) { + if (!paused) + silence_count++; + + // only pause after a while to prevent toggle mania + if (silence_count > 32) { + if (!paused) { + LOGD("AudioTrack pause"); + + JNI::setAudioPause(); + paused = true; + } + + nanosleep(&tv_full, 0); + + continue; + } + } + + if (paused) { + LOGD("AudioTrack play"); + + JNI::setAudioPlay(); + paused = false; + + silence_count = 0; + } + offset = 0; left = buf_size; written = 0; @@ -203,7 +240,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { // buffer full if (written < left) - nanosleep(&tv, 0); + nanosleep(&tv_delay, 0); offset += written; left -= written; @@ -214,7 +251,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { // sleep a little, prepare the next buffer, and run into the // blocking AudioTrack.write - nanosleep(&tv, 0); + nanosleep(&tv_delay, 0); } JNI::setAudioStop(); diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 5e11203db8..8964fe63d8 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -64,6 +64,7 @@ jmethodID JNI::_MID_setupScummVMSurface = 0; jmethodID JNI::_MID_destroyScummVMSurface = 0; jmethodID JNI::_MID_swapBuffers = 0; +jmethodID JNI::_MID_AudioTrack_flush = 0; jmethodID JNI::_MID_AudioTrack_pause = 0; jmethodID JNI::_MID_AudioTrack_play = 0; jmethodID JNI::_MID_AudioTrack_stop = 0; @@ -332,6 +333,15 @@ void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { void JNI::setAudioPause() { JNIEnv *env = JNI::getEnv(); + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_flush); + + if (env->ExceptionCheck()) { + warning("Error flushing AudioTrack"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_pause); if (env->ExceptionCheck()) { @@ -417,6 +427,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, return; \ } while (0) + FIND_METHOD(flush, "()V"); FIND_METHOD(pause, "()V"); FIND_METHOD(play, "()V"); FIND_METHOD(stop, "()V"); diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index a1fc3df67e..0bc64980e2 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -95,6 +95,7 @@ private: static jmethodID _MID_destroyScummVMSurface; static jmethodID _MID_swapBuffers; + static jmethodID _MID_AudioTrack_flush; static jmethodID _MID_AudioTrack_pause; static jmethodID _MID_AudioTrack_play; static jmethodID _MID_AudioTrack_stop; -- cgit v1.2.3 From d4c0501d1fcc8c98d39b2b7ba627cccb29cbc476 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 26 Feb 2011 22:23:17 +0100 Subject: ANDROID: Check audio buffer for silence Most games register a music channel, and when there is no music, they still stream silence (and run through all the Converter::flow code!). Scan the buffer for that to pause the AudioTrack. Ugly, but worth it - reduces CPU usage on many games and hence saves battery life. --- backends/platform/android/android.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 860ff1f7ee..f20cf848d4 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -176,7 +176,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { byte *buf; int offset, left, written; - int samples; + int samples, i; struct timespec tv_delay; tv_delay.tv_sec = 0; @@ -188,6 +188,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { tv_full.tv_sec = 0; tv_full.tv_nsec = msecs_full * 1000 * 1000; + bool silence; uint silence_count = 0; while (!system->_audio_thread_exit) { @@ -196,9 +197,24 @@ void *OSystem_Android::audioThreadFunc(void *arg) { samples = mixer->mixCallback(buf, buf_size); + silence = samples < 1; + + // looks stupid, and it is, but currently there's no way to detect + // silence-only buffers from the mixer + if (!silence) { + silence = true; + + for (i = 0; i < samples; i += 2) + // SID streams constant crap + if (READ_UINT16(buf + i) > 32) { + silence = false; + break; + } + } + env->ReleasePrimitiveArrayCritical(bufa, buf, 0); - if (samples < 1) { + if (silence) { if (!paused) silence_count++; -- cgit v1.2.3 From a73b2ec97279b1ef1562ece18c7905591e6a7cc4 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 26 Feb 2011 23:04:18 +0100 Subject: ANDROID: Remove unnecessary code --- backends/platform/android/jni.cpp | 10 ++-------- .../platform/android/org/inodes/gus/scummvm/ScummVM.java | 12 +++--------- 2 files changed, 5 insertions(+), 17 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 8964fe63d8..d8203e2a57 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -52,7 +52,6 @@ jfieldID JNI::_FID_Event_kbd_flags = 0; jfieldID JNI::_FID_Event_mouse_x = 0; jfieldID JNI::_FID_Event_mouse_y = 0; jfieldID JNI::_FID_Event_mouse_relative = 0; -jfieldID JNI::_FID_ScummVM_nativeScummVM = 0; jmethodID JNI::_MID_displayMessageOnOSD = 0; jmethodID JNI::_MID_setWindowCaption = 0; @@ -111,10 +110,6 @@ jint JNI::onLoad(JavaVM *vm) { if (env->RegisterNatives(cls, _natives, ARRAYSIZE(_natives)) < 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; @@ -415,8 +410,6 @@ void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, #undef FIND_METHOD - env->SetLongField(self, _FID_ScummVM_nativeScummVM, (jlong)_system); - _jobj_audio_track = env->NewGlobalRef(at); cls = env->GetObjectClass(_jobj_audio_track); @@ -439,7 +432,8 @@ void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, } void JNI::destroy(JNIEnv *env, jobject self) { - assert(_system); + if (!_system) + return; OSystem_Android *tmp = _system; g_system = 0; diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 7a326454d9..a6bc5fafc0 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -35,10 +35,6 @@ import java.util.LinkedHashMap; public class ScummVM implements SurfaceHolder.Callback { protected final static String LOG_TAG = "ScummVM"; - // native code hangs itself here - private long nativeScummVM; - boolean scummVMRunning = false; - private native void create(AssetManager am, AudioTrack audio_track, int sample_rate, int buffer_size); @@ -75,17 +71,14 @@ public class ScummVM implements SurfaceHolder.Callback { String.format("Error initialising AudioTrack: %d", audio_track.getState())); - // Init C++ code, set nativeScummVM + // Init C++ code create(context.getAssets(), audio_track, sample_rate, buffer_size); } private native void nativeDestroy(); public synchronized void destroy() { - if (nativeScummVM != 0) { - nativeDestroy(); - nativeScummVM = 0; - } + nativeDestroy(); } protected void finalize() { @@ -295,6 +288,7 @@ public class ScummVM implements SurfaceHolder.Callback { // Called by ScummVM thread static private boolean _log_version = true; + protected void setupScummVMSurface() { try { surfaceLock.acquire(); -- cgit v1.2.3 From 72889ee24fc290ba9353084bbf1e1a3fa47a115c Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 27 Feb 2011 11:23:11 +0100 Subject: ANDROID: Remove dead code --- backends/platform/android/android.cpp | 3 +- backends/platform/android/jni.cpp | 39 ---------------------- .../android/org/inodes/gus/scummvm/ScummVM.java | 3 -- 3 files changed, 2 insertions(+), 43 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index f20cf848d4..62b8b60495 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -285,7 +285,8 @@ void OSystem_Android::initBackend() { _main_thread = pthread_self(); ConfMan.setInt("autosave_period", 0); - ConfMan.setInt("FM_medium_quality", true); + ConfMan.setBool("FM_high_quality", false); + ConfMan.setBool("FM_medium_quality", true); // must happen before creating TimerManager to avoid race in // creating EventManager diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index d8203e2a57..69d1083320 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -79,10 +79,6 @@ const JNINativeMethod JNI::_natives[] = { (void *)JNI::main }, { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", (void *)JNI::pushEvent }, - { "setConfMan", "(Ljava/lang/String;I)V", - (void *)JNI::setConfManInt }, - { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V", - (void *)JNI::setConfManString }, { "enableZoning", "(Z)V", (void *)JNI::enableZoning }, { "setSurfaceSize", "(II)V", @@ -563,41 +559,6 @@ void JNI::pushEvent(JNIEnv *env, jobject self, jobject java_event) { _system->pushEvent(event); } -void JNI::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); -} - -void JNI::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 JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { assert(_system); diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index a6bc5fafc0..ae7204f752 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -359,9 +359,6 @@ public class ScummVM implements SurfaceHolder.Callback { } // Set scummvm config options - final public native static void loadConfigFile(String path); - final public native static void setConfMan(String key, int value); - final public native static void setConfMan(String key, String value); final public native void enableZoning(boolean enable); final public native void setSurfaceSize(int width, int height); -- cgit v1.2.3 From 24a332bd22073257ae9ed33dc0549bfde4538f1b Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 27 Feb 2011 11:25:03 +0100 Subject: ANDROID: Prevent AudioTrack unpause on startup --- backends/platform/android/android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 62b8b60495..57e84d07c6 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -189,7 +189,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { tv_full.tv_nsec = msecs_full * 1000 * 1000; bool silence; - uint silence_count = 0; + uint silence_count = 33; while (!system->_audio_thread_exit) { buf = (byte *)env->GetPrimitiveArrayCritical(bufa, 0); -- cgit v1.2.3 From 807971f8af9430ee19f66c7bac7cc9566fccf432 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 27 Feb 2011 20:16:52 +0100 Subject: ANDROID: Don't use warning()/error() in a thread --- backends/platform/android/android.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 57e84d07c6..f886347685 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -142,7 +142,7 @@ void *OSystem_Android::timerThreadFunc(void *arg) { // renice this thread to boost the audio thread if (setpriority(PRIO_PROCESS, 0, 19) < 0) - warning("couldn't renice the timer thread"); + LOGW("couldn't renice the timer thread"); JNI::attachThread(); @@ -250,7 +250,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { written = JNI::writeAudio(env, bufa, offset, left); if (written < 0) { - error("AudioTrack error: %d", written); + LOGE("AudioTrack error: %d", written); break; } -- cgit v1.2.3 From 2f008d0cd6ffa84071fe2f5c343ef19328cc83ae Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 28 Feb 2011 19:48:41 +0100 Subject: ANDROID: Don't use warning() in JNI functions --- backends/platform/android/jni.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 69d1083320..99934fb640 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -212,7 +212,7 @@ void JNI::getPluginDirectories(Common::FSList &dirs) { (jobjectArray)env->CallObjectMethod(_jobj, _MID_getPluginDirectories); if (env->ExceptionCheck()) { - warning("Error finding plugin directories"); + LOGE("Error finding plugin directories"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -230,7 +230,7 @@ void JNI::getPluginDirectories(Common::FSList &dirs) { const char *path = env->GetStringUTFChars(path_obj, 0); if (path == 0) { - warning("Error getting string characters from plugin directory"); + LOGE("Error getting string characters from plugin directory"); env->ExceptionClear(); env->DeleteLocalRef(path_obj); @@ -252,7 +252,7 @@ void JNI::setWindowCaption(const char *caption) { env->CallVoidMethod(_jobj, _MID_setWindowCaption, java_caption); if (env->ExceptionCheck()) { - warning("Failed to set window caption"); + LOGE("Failed to set window caption"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -268,7 +268,7 @@ void JNI::displayMessageOnOSD(const char *msg) { env->CallVoidMethod(_jobj, _MID_displayMessageOnOSD, java_msg); if (env->ExceptionCheck()) { - warning("Failed to display OSD message"); + LOGE("Failed to display OSD message"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -283,7 +283,7 @@ void JNI::showVirtualKeyboard(bool enable) { env->CallVoidMethod(_jobj, _MID_showVirtualKeyboard, enable); if (env->ExceptionCheck()) { - error("Error trying to show virtual keyboard"); + LOGE("Error trying to show virtual keyboard"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -299,7 +299,7 @@ void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { (jobjectArray)env->CallObjectMethod(_jobj, _MID_getSysArchives); if (env->ExceptionCheck()) { - warning("Error finding system archive path"); + LOGE("Error finding system archive path"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -327,7 +327,7 @@ void JNI::setAudioPause() { env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_flush); if (env->ExceptionCheck()) { - warning("Error flushing AudioTrack"); + LOGE("Error flushing AudioTrack"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -336,7 +336,7 @@ void JNI::setAudioPause() { env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_pause); if (env->ExceptionCheck()) { - warning("Error setting AudioTrack: pause"); + LOGE("Error setting AudioTrack: pause"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -349,7 +349,7 @@ void JNI::setAudioPlay() { env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_play); if (env->ExceptionCheck()) { - warning("Error setting AudioTrack: play"); + LOGE("Error setting AudioTrack: play"); env->ExceptionDescribe(); env->ExceptionClear(); @@ -362,7 +362,7 @@ void JNI::setAudioStop() { env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_stop); if (env->ExceptionCheck()) { - warning("Error setting AudioTrack: stop"); + LOGE("Error setting AudioTrack: stop"); env->ExceptionDescribe(); env->ExceptionClear(); -- cgit v1.2.3 From 2333a32697cda8f5f73861856889001839f38f25 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 27 Feb 2011 20:13:48 +0100 Subject: ANDROID: Untangle JNI interweaving - make the startup sequence more linear - use SurfaceHolder events - get rid of the surface lock - remove unnecessary JNI calls - make the ScummVM class implement Runnable - cleanup --- backends/platform/android/android.cpp | 44 +- backends/platform/android/android.h | 9 +- backends/platform/android/gfx.cpp | 23 +- backends/platform/android/jni.cpp | 192 +++++---- backends/platform/android/jni.h | 48 +-- .../android/org/inodes/gus/scummvm/ScummVM.java | 478 +++++++++++---------- .../org/inodes/gus/scummvm/ScummVMActivity.java | 91 +--- 7 files changed, 443 insertions(+), 442 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index f886347685..2af367e903 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -103,6 +103,8 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _audio_sample_rate(audio_sample_rate), _audio_buffer_size(audio_buffer_size), _screen_changeid(0), + _egl_surface_width(0), + _egl_surface_height(0), _force_redraw(false), _game_texture(0), _overlay_texture(0), @@ -126,11 +128,9 @@ OSystem_Android::~OSystem_Android() { delete _overlay_texture; delete _mouse_texture; - JNI::destroySurface(); - delete _savefile; - delete _mixer; delete _timer; + delete _mixer; delete _fsFactory; deleteMutex(_event_queue_lock); @@ -303,21 +303,19 @@ void OSystem_Android::initBackend() { _mixer = new Audio::MixerImpl(this, _audio_sample_rate); _mixer->setReady(true); - JNI::initBackend(); - _timer_thread_exit = false; pthread_create(&_timer_thread, 0, timerThreadFunc, this); _audio_thread_exit = false; pthread_create(&_audio_thread, 0, audioThreadFunc, this); - OSystem::initBackend(); - setupSurface(); // renice this thread to boost the audio thread if (setpriority(PRIO_PROCESS, 0, 19) < 0) warning("couldn't renice the main thread"); + + JNI::setReadyForEvents(true); } void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { @@ -385,6 +383,28 @@ void OSystem_Android::setupKeymapper() { bool OSystem_Android::pollEvent(Common::Event &event) { //ENTER(); + if (pthread_self() == _main_thread) { + if (_screen_changeid != JNI::surface_changeid) { + if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { + LOGD("initializing surface"); + + JNI::deinitSurface(); + setupSurface(); + + event.type = Common::EVENT_SCREEN_CHANGED; + + return true; + } + + LOGD("deinitialiting surface"); + + _screen_changeid = JNI::surface_changeid; + JNI::deinitSurface(); + + // TODO prevent swapBuffers + } + } + lockMutex(_event_queue_lock); if (_event_queue.empty()) { @@ -433,12 +453,6 @@ bool OSystem_Android::pollEvent(Common::Event &event) { } break; } - case Common::EVENT_SCREEN_CHANGED: - debug("EVENT_SCREEN_CHANGED"); - _screen_changeid++; - JNI::destroySurface(); - setupSurface(); - break; default: break; } @@ -525,11 +539,15 @@ void OSystem_Android::deleteMutex(MutexRef mutex) { void OSystem_Android::quit() { ENTER(); + JNI::setReadyForEvents(false); + _audio_thread_exit = true; pthread_join(_audio_thread, 0); _timer_thread_exit = true; pthread_join(_timer_thread, 0); + + JNI::deinitSurface(); } void OSystem_Android::setWindowCaption(const char *caption) { diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index f4e9d611d4..aa6016e3d2 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -151,10 +151,6 @@ public: 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); @@ -166,10 +162,7 @@ public: virtual int getGraphicsMode() const; virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); - - virtual int getScreenChangeID() const { - return _screen_changeid; - } + virtual int getScreenChangeID() const; virtual int16 getHeight(); virtual int16 getWidth(); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 8601a3bfca..49f3d40e39 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -65,8 +65,13 @@ int OSystem_Android::getGraphicsMode() const { void OSystem_Android::setupSurface() { ENTER(); - if (!JNI::setupSurface()) - return; + _screen_changeid = JNI::surface_changeid; + JNI::initSurface(); + + _egl_surface_width = JNI::egl_surface_width; + _egl_surface_height = JNI::egl_surface_height; + + assert(_egl_surface_width > 0 && _egl_surface_height > 0); // EGL set up with a new surface. Initialise OpenGLES context. GLESTexture::initGLExtensions(); @@ -148,6 +153,10 @@ void OSystem_Android::initSize(uint width, uint height, _mouse_texture->allocBuffer(20, 20); } +int OSystem_Android::getScreenChangeID() const { + return _screen_changeid; +} + int16 OSystem_Android::getHeight() { return _game_texture->height(); } @@ -279,10 +288,14 @@ void OSystem_Android::updateScreen() { GLCALL(glPopMatrix()); - if (!JNI::swapBuffers()) { - // Context lost -> need to reinit GL - JNI::destroySurface(); + int res = JNI::swapBuffers(); + + if (res) { + warning("swapBuffers returned 0x%x", res); +#if 0 + JNI::initSurface(); setupSurface(); +#endif } } diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 99934fb640..28a03d0555 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -44,6 +44,11 @@ jobject JNI::_jobj_audio_track = 0; Common::Archive *JNI::_asset_archive = 0; OSystem_Android *JNI::_system = 0; +int JNI::surface_changeid = 0; +int JNI::egl_surface_width = 0; +int JNI::egl_surface_height = 0; +bool JNI::_ready_for_events = 0; + jfieldID JNI::_FID_Event_type = 0; jfieldID JNI::_FID_Event_synthetic = 0; jfieldID JNI::_FID_Event_kbd_keycode = 0; @@ -55,13 +60,12 @@ jfieldID JNI::_FID_Event_mouse_relative = 0; jmethodID JNI::_MID_displayMessageOnOSD = 0; jmethodID JNI::_MID_setWindowCaption = 0; -jmethodID JNI::_MID_initBackend = 0; jmethodID JNI::_MID_showVirtualKeyboard = 0; jmethodID JNI::_MID_getSysArchives = 0; jmethodID JNI::_MID_getPluginDirectories = 0; -jmethodID JNI::_MID_setupScummVMSurface = 0; -jmethodID JNI::_MID_destroyScummVMSurface = 0; jmethodID JNI::_MID_swapBuffers = 0; +jmethodID JNI::_MID_initSurface = 0; +jmethodID JNI::_MID_deinitSurface = 0; jmethodID JNI::_MID_AudioTrack_flush = 0; jmethodID JNI::_MID_AudioTrack_pause = 0; @@ -73,16 +77,16 @@ const JNINativeMethod JNI::_natives[] = { { "create", "(Landroid/content/res/AssetManager;" "Landroid/media/AudioTrack;II)V", (void *)JNI::create }, - { "nativeDestroy", "()V", + { "destroy", "()V", (void *)JNI::destroy }, - { "scummVMMain", "([Ljava/lang/String;)I", + { "setSurface", "(II)V", + (void *)JNI::setSurface }, + { "main", "([Ljava/lang/String;)I", (void *)JNI::main }, { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", (void *)JNI::pushEvent }, { "enableZoning", "(Z)V", (void *)JNI::enableZoning }, - { "setSurfaceSize", "(II)V", - (void *)JNI::setSurfaceSize }, }; JNI::JNI() { @@ -178,6 +182,10 @@ void JNI::detachThread() { } } +void JNI::setReadyForEvents(bool ready) { + _ready_for_events = ready; +} + void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) { jclass cls = env->FindClass(name); @@ -188,61 +196,26 @@ void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) { env->DeleteLocalRef(cls); } -// calls to the dark side - -void JNI::initBackend() { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj, _MID_initBackend); - - if (env->ExceptionCheck()) { - error("Error in Java initBackend"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - // TODO now what? - } +void JNI::throwRuntimeException(JNIEnv *env, const char *msg) { + throwByName(env, "java/lang/RuntimeException", msg); } -void JNI::getPluginDirectories(Common::FSList &dirs) { +// calls to the dark side + +void JNI::displayMessageOnOSD(const char *msg) { JNIEnv *env = JNI::getEnv(); + jstring java_msg = env->NewStringUTF(msg); - jobjectArray array = - (jobjectArray)env->CallObjectMethod(_jobj, _MID_getPluginDirectories); + env->CallVoidMethod(_jobj, _MID_displayMessageOnOSD, java_msg); if (env->ExceptionCheck()) { - LOGE("Error finding plugin directories"); + LOGE("Failed to display OSD message"); env->ExceptionDescribe(); env->ExceptionClear(); - - return; } - jsize size = env->GetArrayLength(array); - for (jsize i = 0; i < size; ++i) { - jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); - - if (path_obj == 0) - continue; - - const char *path = env->GetStringUTFChars(path_obj, 0); - - if (path == 0) { - LOGE("Error getting string characters from plugin directory"); - - env->ExceptionClear(); - env->DeleteLocalRef(path_obj); - - continue; - } - - dirs.push_back(Common::FSNode(path)); - - env->ReleaseStringUTFChars(path_obj, path); - env->DeleteLocalRef(path_obj); - } + env->DeleteLocalRef(java_msg); } void JNI::setWindowCaption(const char *caption) { @@ -261,22 +234,6 @@ void JNI::setWindowCaption(const char *caption) { env->DeleteLocalRef(java_caption); } -void JNI::displayMessageOnOSD(const char *msg) { - JNIEnv *env = JNI::getEnv(); - jstring java_msg = env->NewStringUTF(msg); - - env->CallVoidMethod(_jobj, _MID_displayMessageOnOSD, java_msg); - - if (env->ExceptionCheck()) { - LOGE("Failed to display OSD message"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteLocalRef(java_msg); -} - void JNI::showVirtualKeyboard(bool enable) { JNIEnv *env = JNI::getEnv(); @@ -321,6 +278,72 @@ void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { } } +void JNI::getPluginDirectories(Common::FSList &dirs) { + JNIEnv *env = JNI::getEnv(); + + jobjectArray array = + (jobjectArray)env->CallObjectMethod(_jobj, _MID_getPluginDirectories); + + if (env->ExceptionCheck()) { + LOGE("Error finding plugin directories"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return; + } + + jsize size = env->GetArrayLength(array); + for (jsize i = 0; i < size; ++i) { + jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + + if (path_obj == 0) + continue; + + const char *path = env->GetStringUTFChars(path_obj, 0); + + if (path == 0) { + LOGE("Error getting string characters from plugin directory"); + + env->ExceptionClear(); + env->DeleteLocalRef(path_obj); + + continue; + } + + dirs.push_back(Common::FSNode(path)); + + env->ReleaseStringUTFChars(path_obj, path); + env->DeleteLocalRef(path_obj); + } +} + +void JNI::initSurface() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_initSurface); + + if (env->ExceptionCheck()) { + LOGE("initSurface failed"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +void JNI::deinitSurface() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_deinitSurface); + + if (env->ExceptionCheck()) { + LOGE("deinitSurface failed"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + void JNI::setAudioPause() { JNIEnv *env = JNI::getEnv(); @@ -396,13 +419,12 @@ void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V"); FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V"); - FIND_METHOD(initBackend, "()V"); FIND_METHOD(showVirtualKeyboard, "(Z)V"); FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); - FIND_METHOD(setupScummVMSurface, "()V"); - FIND_METHOD(destroyScummVMSurface, "()V"); - FIND_METHOD(swapBuffers, "()Z"); + FIND_METHOD(swapBuffers, "()I"); + FIND_METHOD(initSurface, "()V"); + FIND_METHOD(deinitSurface, "()V"); #undef FIND_METHOD @@ -428,16 +450,12 @@ void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, } void JNI::destroy(JNIEnv *env, jobject self) { - if (!_system) - return; + delete _asset_archive; + _asset_archive = 0; - OSystem_Android *tmp = _system; + delete _system; g_system = 0; _system = 0; - delete tmp; - - delete _asset_archive; - _asset_archive = 0; // see above //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); @@ -445,6 +463,12 @@ void JNI::destroy(JNIEnv *env, jobject self) { JNI::getEnv()->DeleteGlobalRef(_jobj); } +void JNI::setSurface(JNIEnv *env, jobject self, jint width, jint height) { + egl_surface_width = width; + egl_surface_height = height; + surface_changeid++; +} + jint JNI::main(JNIEnv *env, jobject self, jobjectArray args) { assert(_system); @@ -489,7 +513,7 @@ jint JNI::main(JNIEnv *env, jobject self, jobjectArray args) { res = scummvm_main(argc, argv); - LOGI("Exiting scummvm_main"); + LOGI("scummvm_main exited with code %d", res); _system->quit(); @@ -514,6 +538,10 @@ cleanup: } void JNI::pushEvent(JNIEnv *env, jobject self, jobject java_event) { + // drop events until we're ready and after we quit + if (!_ready_for_events) + return; + assert(_system); Common::Event event; @@ -565,11 +593,5 @@ void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { _system->enableZoning(enable); } -void JNI::setSurfaceSize(JNIEnv *env, jobject self, jint width, jint height) { - assert(_system); - - _system->setSurfaceSize(width, height); -} - #endif diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 0bc64980e2..0005136966 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -41,6 +41,10 @@ private: virtual ~JNI(); public: + static int surface_changeid; + static int egl_surface_width; + static int egl_surface_height; + static jint onLoad(JavaVM *vm); static JNIEnv *getEnv(); @@ -48,16 +52,17 @@ public: static void attachThread(); static void detachThread(); - static void initBackend(); + static void setReadyForEvents(bool ready); + static void getPluginDirectories(Common::FSList &dirs); static void setWindowCaption(const char *caption); static void displayMessageOnOSD(const char *msg); static void showVirtualKeyboard(bool enable); static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); - static inline bool setupSurface(); - static inline void destroySurface(); - static inline bool swapBuffers(); + static inline int swapBuffers(); + static void initSurface(); + static void deinitSurface(); static void setAudioPause(); static void setAudioPlay(); @@ -75,6 +80,8 @@ private: static Common::Archive *_asset_archive; static OSystem_Android *_system; + static bool _ready_for_events; + static jfieldID _FID_Event_type; static jfieldID _FID_Event_synthetic; static jfieldID _FID_Event_kbd_keycode; @@ -87,13 +94,12 @@ private: static jmethodID _MID_displayMessageOnOSD; static jmethodID _MID_setWindowCaption; - static jmethodID _MID_initBackend; static jmethodID _MID_showVirtualKeyboard; static jmethodID _MID_getSysArchives; static jmethodID _MID_getPluginDirectories; - static jmethodID _MID_setupScummVMSurface; - static jmethodID _MID_destroyScummVMSurface; static jmethodID _MID_swapBuffers; + static jmethodID _MID_initSurface; + static jmethodID _MID_deinitSurface; static jmethodID _MID_AudioTrack_flush; static jmethodID _MID_AudioTrack_pause; @@ -104,40 +110,24 @@ private: static const JNINativeMethod _natives[]; static void throwByName(JNIEnv *env, const char *name, const char *msg); + static void throwRuntimeException(JNIEnv *env, const char *msg); // natives for the dark side static void create(JNIEnv *env, jobject self, jobject am, jobject at, jint sample_rate, jint buffer_size); static void destroy(JNIEnv *env, jobject self); + + static void setSurface(JNIEnv *env, jobject self, jint width, jint height); static jint main(JNIEnv *env, jobject self, jobjectArray args); + static void pushEvent(JNIEnv *env, jobject self, jobject java_event); - static void setConfManInt(JNIEnv *env, jclass cls, jstring key_obj, - jint value); - static void setConfManString(JNIEnv *env, jclass cls, jstring key_obj, - jstring value_obj); static void enableZoning(JNIEnv *env, jobject self, jboolean enable); - static void setSurfaceSize(JNIEnv *env, jobject self, jint width, - jint height); }; -inline bool JNI::setupSurface() { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj, _MID_setupScummVMSurface); - - return !env->ExceptionCheck(); -} - -inline void JNI::destroySurface() { - JNIEnv *env = JNI::getEnv(); - - env->CallVoidMethod(_jobj, _MID_destroyScummVMSurface); -} - -inline bool JNI::swapBuffers() { +inline int JNI::swapBuffers() { JNIEnv *env = JNI::getEnv(); - return env->CallBooleanMethod(_jobj, _MID_swapBuffers); + return env->CallIntMethod(_jobj, _MID_swapBuffers); } inline int JNI::writeAudio(JNIEnv *env, jbyteArray &data, int offset, int size) { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index ae7204f752..db83303c7d 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -1,18 +1,12 @@ package org.inodes.gus.scummvm; -import android.content.Context; +import android.util.Log; import android.content.res.AssetManager; +import android.view.SurfaceHolder; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Process; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import javax.microedition.khronos.opengles.GL; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGL11; @@ -22,28 +16,242 @@ import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import java.io.File; -import java.util.concurrent.Semaphore; import java.util.Map; import java.util.LinkedHashMap; +public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { + final protected static String LOG_TAG = "ScummVM"; + final private AssetManager asset_manager; + final private Object sem_surface; + + private EGL10 egl; + private EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY; + private EGLConfig eglConfig; + private EGLContext eglContext = EGL10.EGL_NO_CONTEXT; + private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; + + private SurfaceHolder surface_holder; + private AudioTrack audio_track; + private int sample_rate = 0; + private int buffer_size = 0; + + private String[] args; + + final private native void create(AssetManager asset_manager, + AudioTrack audio_track, + int sample_rate, int buffer_size); + final private native void destroy(); + final private native void setSurface(int width, int height); + final private native int main(String[] args); + + // Set scummvm config options + final public native void enableZoning(boolean enable); + // Feed an event to ScummVM. Safe to call from other threads. + final public native void pushEvent(Event e); + + // Callbacks from C++ peer instance + abstract protected void displayMessageOnOSD(String msg); + abstract protected void setWindowCaption(String caption); + abstract protected String[] getPluginDirectories(); + abstract protected void showVirtualKeyboard(boolean enable); + abstract protected String[] getSysArchives(); + + final protected int swapBuffers() { + if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) + return egl.eglGetError(); + + return 0; + } + + public ScummVM(AssetManager asset_manager, SurfaceHolder holder) { + this.asset_manager = asset_manager; + sem_surface = new Object(); + + holder.addCallback(this); + } + + // SurfaceHolder callback + final public void surfaceCreated(SurfaceHolder holder) { + Log.d(LOG_TAG, "surfaceCreated"); + + // no need to do anything, surfaceChanged() will be called in any case + } + + // SurfaceHolder callback + final public void surfaceChanged(SurfaceHolder holder, int format, + int width, int height) { + Log.d(LOG_TAG, String.format("surfaceChanged: %dx%d (%d)", + width, height, format)); + + synchronized(sem_surface) { + surface_holder = holder; + sem_surface.notifyAll(); + } + + // store values for the native code + setSurface(width, height); + } + + // SurfaceHolder callback + final public void surfaceDestroyed(SurfaceHolder holder) { + Log.d(LOG_TAG, "surfaceDestroyed"); + + synchronized(sem_surface) { + surface_holder = null; + sem_surface.notifyAll(); + } + + // clear values for the native code + setSurface(0, 0); + } + + final public void setArgs(String[] args) { + this.args = args; + } + + final public void run() { + try { + initAudio(); + initEGL(); + + // wait for the surfaceChanged callback + synchronized(sem_surface) { + while (surface_holder == null) + sem_surface.wait(); + } + } catch (Exception e) { + deinitEGL(); + deinitAudio(); + + throw new RuntimeException("Error preparing the ScummVM thread", e); + } + + create(asset_manager, audio_track, sample_rate, buffer_size); + + int res = main(args); + + destroy(); + + deinitEGL(); + deinitAudio(); + + // On exit, tear everything down for a fresh restart next time. + System.exit(res); + } + + public void pause() { + // TODO + } + + public void resume() { + // TODO + } + + final private void initEGL() throws Exception { + egl = (EGL10)EGLContext.getEGL(); + eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + int[] version = new int[2]; + egl.eglInitialize(eglDisplay, version); + + int[] num_config = new int[1]; + egl.eglChooseConfig(eglDisplay, configSpec, null, 0, num_config); + + final int numConfigs = num_config[0]; + + if (numConfigs <= 0) + throw new IllegalArgumentException("No configs match configSpec"); + + EGLConfig[] configs = new EGLConfig[numConfigs]; + egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs, + num_config); + + if (false) { + Log.d(LOG_TAG, String.format("Found %d EGL configurations.", + numConfigs)); + for (EGLConfig config : configs) + dumpEglConfig(config); + } + + // Android's eglChooseConfig is busted in several versions and + // devices so we have to filter/rank the configs again ourselves. + eglConfig = chooseEglConfig(configs); + + if (false) { + Log.d(LOG_TAG, String.format("Chose from %d EGL configs", + numConfigs)); + dumpEglConfig(eglConfig); + } + + eglContext = egl.eglCreateContext(eglDisplay, eglConfig, + EGL10.EGL_NO_CONTEXT, null); + + if (eglContext == EGL10.EGL_NO_CONTEXT) + throw new Exception(String.format("Failed to create context: 0x%x", + egl.eglGetError())); + } + + // Callback from C++ peer instance + final protected void initSurface() throws Exception { + eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, + surface_holder, null); + + if (eglSurface == EGL10.EGL_NO_SURFACE) + throw new Exception(String.format( + "eglCreateWindowSurface failed: 0x%x", egl.eglGetError())); + + egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + + GL10 gl = (GL10)eglContext.getGL(); + + Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)", + egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION), + egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR), + gl.glGetString(GL10.GL_VERSION), + gl.glGetString(GL10.GL_RENDERER), + gl.glGetString(GL10.GL_VENDOR))); + } + + // Callback from C++ peer instance + final protected void deinitSurface() { + if (eglDisplay != EGL10.EGL_NO_DISPLAY) { + egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + + if (eglSurface != EGL10.EGL_NO_SURFACE) + egl.eglDestroySurface(eglDisplay, eglSurface); + } + + eglSurface = EGL10.EGL_NO_SURFACE; + } -// At least in Android 2.1, eglCreateWindowSurface() requires an -// EGLNativeWindowSurface object, which is hidden deep in the bowels -// of libui. Until EGL is properly exposed, it's probably safer to -// use the Java versions of most EGL functions :( + final private void deinitEGL() { + if (eglDisplay != EGL10.EGL_NO_DISPLAY) { + egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); -public class ScummVM implements SurfaceHolder.Callback { - protected final static String LOG_TAG = "ScummVM"; + if (eglSurface != EGL10.EGL_NO_SURFACE) + egl.eglDestroySurface(eglDisplay, eglSurface); + + if (eglContext != EGL10.EGL_NO_CONTEXT) + egl.eglDestroyContext(eglDisplay, eglContext); + + egl.eglTerminate(eglDisplay); + } - private native void create(AssetManager am, AudioTrack audio_track, - int sample_rate, int buffer_size); + eglSurface = EGL10.EGL_NO_SURFACE; + eglContext = EGL10.EGL_NO_CONTEXT; + eglConfig = null; + eglDisplay = EGL10.EGL_NO_DISPLAY; + egl = null; + } - public ScummVM(Context context) throws Exception { - int sample_rate = AudioTrack.getNativeOutputSampleRate( - AudioManager.STREAM_MUSIC); - int buffer_size = AudioTrack.getMinBufferSize(sample_rate, - AudioFormat.CHANNEL_CONFIGURATION_STEREO, - AudioFormat.ENCODING_PCM_16BIT); + final private void initAudio() throws Exception { + sample_rate = AudioTrack.getNativeOutputSampleRate( + AudioManager.STREAM_MUSIC); + buffer_size = AudioTrack.getMinBufferSize(sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT); // ~100ms int buffer_size_want = (sample_rate * 2 * 2 / 10) & ~1023; @@ -58,48 +266,28 @@ public class ScummVM implements SurfaceHolder.Callback { Log.i(LOG_TAG, String.format("Using %d bytes buffer for %dHz audio", buffer_size, sample_rate)); - AudioTrack audio_track = - new AudioTrack(AudioManager.STREAM_MUSIC, - sample_rate, - AudioFormat.CHANNEL_CONFIGURATION_STEREO, - AudioFormat.ENCODING_PCM_16BIT, - buffer_size, - AudioTrack.MODE_STREAM); + audio_track = new AudioTrack(AudioManager.STREAM_MUSIC, + sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT, + buffer_size, + AudioTrack.MODE_STREAM); if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) throw new Exception( String.format("Error initialising AudioTrack: %d", audio_track.getState())); - - // Init C++ code - create(context.getAssets(), audio_track, sample_rate, buffer_size); } - private native void nativeDestroy(); + final private void deinitAudio() { + if (audio_track != null) + audio_track.stop(); - public synchronized void destroy() { - nativeDestroy(); + audio_track = null; + buffer_size = 0; + sample_rate = 0; } - protected void finalize() { - destroy(); - } - - // Surface creation: - // GUI thread: create surface, release lock - // ScummVM thread: acquire lock (block), read surface - - // Surface deletion: - // GUI thread: post event, acquire lock (block), return - // ScummVM thread: read event, free surface, release lock - - // In other words, ScummVM thread does this: - // acquire lock - // setup surface - // when SCREEN_CHANGED arrives: - // destroy surface - // release lock - // back to acquire lock static final int configSpec[] = { EGL10.EGL_RED_SIZE, 5, EGL10.EGL_GREEN_SIZE, 5, @@ -109,33 +297,6 @@ public class ScummVM implements SurfaceHolder.Callback { EGL10.EGL_NONE, }; - EGL10 egl; - EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY; - EGLConfig eglConfig; - EGLContext eglContext = EGL10.EGL_NO_CONTEXT; - EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; - Semaphore surfaceLock = new Semaphore(0, true); - SurfaceHolder nativeSurface; - - public void surfaceCreated(SurfaceHolder holder) { - nativeSurface = holder; - surfaceLock.release(); - } - - public void surfaceChanged(SurfaceHolder holder, int format, - int width, int height) { - // Disabled while I debug GL problems - pushEvent(new Event(Event.EVENT_SCREEN_CHANGED)); - } - - public void surfaceDestroyed(SurfaceHolder holder) { - try { - surfaceLock.acquire(); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e); - } - } - // For debugging private static final Map attribs; @@ -170,7 +331,7 @@ public class ScummVM implements SurfaceHolder.Callback { attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE); } - private void dumpEglConfig(EGLConfig config) { + final private void dumpEglConfig(EGLConfig config) { int[] value = new int[1]; for (Map.Entry entry : attribs.entrySet()) { @@ -184,49 +345,7 @@ public class ScummVM implements SurfaceHolder.Callback { } } - // Called by ScummVM thread (from initBackend) - private void createScummVMGLContext() { - egl = (EGL10)EGLContext.getEGL(); - eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - - int[] version = new int[2]; - egl.eglInitialize(eglDisplay, version); - - int[] num_config = new int[1]; - egl.eglChooseConfig(eglDisplay, configSpec, null, 0, num_config); - - final int numConfigs = num_config[0]; - - if (numConfigs <= 0) - throw new IllegalArgumentException("No configs match configSpec"); - - EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs, - num_config); - - if (false) { - Log.d(LOG_TAG, String.format("Found %d EGL configurations.", numConfigs)); - for (EGLConfig config : configs) - dumpEglConfig(config); - } - - // Android's eglChooseConfig is busted in several versions and - // devices so we have to filter/rank the configs again ourselves. - eglConfig = chooseEglConfig(configs); - - if (false) { - Log.d(LOG_TAG, String.format("Chose EGL config from %d possibilities.", numConfigs)); - dumpEglConfig(eglConfig); - } - - eglContext = egl.eglCreateContext(eglDisplay, eglConfig, - EGL10.EGL_NO_CONTEXT, null); - - if (eglContext == EGL10.EGL_NO_CONTEXT) - throw new RuntimeException("Failed to create context"); - } - - private EGLConfig chooseEglConfig(EGLConfig[] configs) { + final private EGLConfig chooseEglConfig(EGLConfig[] configs) { int best = 0; int bestScore = -1; int[] value = new int[1]; @@ -286,111 +405,6 @@ public class ScummVM implements SurfaceHolder.Callback { return configs[best]; } - // Called by ScummVM thread - static private boolean _log_version = true; - - protected void setupScummVMSurface() { - try { - surfaceLock.acquire(); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e); - return; - } - - eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, - nativeSurface, null); - - if (eglSurface == EGL10.EGL_NO_SURFACE) - Log.e(LOG_TAG, "CreateWindowSurface failed!"); - - egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); - - GL10 gl = (GL10)eglContext.getGL(); - - if (_log_version) { - Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)", - egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION), - egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR), - gl.glGetString(GL10.GL_VERSION), - gl.glGetString(GL10.GL_RENDERER), - gl.glGetString(GL10.GL_VENDOR))); - - // only log this once - _log_version = false; - } - - int[] value = new int[1]; - egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, value); - - int width = value[0]; - egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, value); - - int height = value[0]; - Log.i(LOG_TAG, String.format("New surface is %dx%d", width, height)); - setSurfaceSize(width, height); - } - - // Called by ScummVM thread - protected void destroyScummVMSurface() { - if (eglSurface != null) { - egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - - egl.eglDestroySurface(eglDisplay, eglSurface); - eglSurface = EGL10.EGL_NO_SURFACE; - } - - surfaceLock.release(); - } - - public void setSurface(SurfaceHolder holder) { - holder.addCallback(this); - } - - final public boolean swapBuffers() { - if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) { - int error = egl.eglGetError(); - Log.w(LOG_TAG, String.format("eglSwapBuffers exited with error 0x%x", error)); - if (error == EGL11.EGL_CONTEXT_LOST) - return false; - } - - return true; - } - - // Set scummvm config options - final public native void enableZoning(boolean enable); - final public native void setSurfaceSize(int width, int height); - - // Feed an event to ScummVM. Safe to call from other threads. - final public native void pushEvent(Event e); - - // Runs the actual ScummVM program and returns when it does. - // This should not be called from multiple threads simultaneously... - final public native int scummVMMain(String[] argv); - - // Callbacks from C++ peer instance - //protected GraphicsMode[] getSupportedGraphicsModes() {} - protected void displayMessageOnOSD(String msg) {} - protected void setWindowCaption(String caption) {} - protected void showVirtualKeyboard(boolean enable) {} - protected String[] getSysArchives() { return new String[0]; } - protected String[] getPluginDirectories() { return new String[0]; } - - protected void initBackend() { - createScummVMGLContext(); - } - - public void pause() { - // TODO: need to pause audio - // TODO: need to pause engine - } - - public void resume() { - // TODO: need to resume audio - // TODO: need to resume engine - } - static { // For grabbing with gdb... final boolean sleep_for_debugger = false; @@ -401,10 +415,10 @@ public class ScummVM implements SurfaceHolder.Callback { } } - //System.loadLibrary("scummvm"); File cache_dir = ScummVMApplication.getLastCacheDir(); String libname = System.mapLibraryName("scummvm"); File libpath = new File(cache_dir, libname); + System.load(libpath.getPath()); } } diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index fb6020cf1c..92247dea96 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -3,6 +3,7 @@ package org.inodes.gus.scummvm; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; +import android.content.res.AssetManager; import android.content.res.Configuration; import android.media.AudioManager; import android.os.Bundle; @@ -14,6 +15,7 @@ import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceView; +import android.view.SurfaceHolder; import android.view.View; import android.view.ViewConfiguration; import android.view.inputmethod.InputMethodManager; @@ -30,8 +32,6 @@ public class ScummVMActivity extends Activity { private final static int TRACKBALL_SCALE = 2; private class MyScummVM extends ScummVM { - private boolean scummvmRunning = false; - private boolean usingSmallScreen() { // Multiple screen sizes came in with Android 1.6. Have // to use reflection in order to continue supporting 1.5 @@ -49,8 +49,8 @@ public class ScummVMActivity extends Activity { } } - public MyScummVM() throws Exception { - super(ScummVMActivity.this); + public MyScummVM(SurfaceHolder holder) { + super(ScummVMActivity.this.getAssets(), holder); // Enable ScummVM zoning on 'small' screens. // FIXME make this optional for the user @@ -58,23 +58,6 @@ public class ScummVMActivity extends Activity { //enableZoning(usingSmallScreen()); } - @Override - protected void initBackend() { - synchronized (this) { - scummvmRunning = true; - notifyAll(); - } - - super.initBackend(); - } - - public void waitUntilRunning() throws InterruptedException { - synchronized (this) { - while (!scummvmRunning) - wait(); - } - } - @Override protected void displayMessageOnOSD(String msg) { Log.i(LOG_TAG, "OSD: " + msg); @@ -105,6 +88,12 @@ public class ScummVMActivity extends Activity { } }); } + + @Override + protected String[] getSysArchives() { + return new String[0]; + } + } private MyScummVM scummvm; @@ -140,74 +129,36 @@ public class ScummVMActivity extends Activity { } SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); + main_surface.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { return onTouchEvent(event); } }); + main_surface.setOnKeyListener(new View.OnKeyListener() { public boolean onKey(View v, int code, KeyEvent ev) { return onKeyDown(code, ev); } }); - main_surface.requestFocus(); - // Start ScummVM - try { - scummvm = new MyScummVM(); - } catch (Exception e) { - Log.e(ScummVM.LOG_TAG, "Fatal error", e); - finish(); - return; - } - - scummvm_thread = new Thread(new Runnable() { - public void run() { - try { - runScummVM(); - } catch (Exception e) { - Log.e(ScummVM.LOG_TAG, "Fatal error in ScummVM thread", e); - new AlertDialog.Builder(ScummVMActivity.this) - .setTitle("Error") - .setMessage(e.toString()) - .setIcon(android.R.drawable.ic_dialog_alert) - .show(); - finish(); - } - } - }, "ScummVM"); - - scummvm_thread.start(); + main_surface.requestFocus(); - // Block UI thread until ScummVM has started. In particular, - // this means that surface and event callbacks should be safe - // after this point. - try { - scummvm.waitUntilRunning(); - } catch (InterruptedException e) { - Log.e(ScummVM.LOG_TAG, "Interrupted while waiting for ScummVM.initBackend", e); - finish(); - } + getFilesDir().mkdirs(); - scummvm.setSurface(main_surface.getHolder()); - } + // Start ScummVM + scummvm = new MyScummVM(main_surface.getHolder()); - // Runs in another thread - private void runScummVM() throws IOException { - getFilesDir().mkdirs(); - String[] args = { - "ScummVM-lib", + scummvm.setArgs(new String[] { + "ScummVM", "--config=" + getFileStreamPath("scummvmrc").getPath(), "--path=" + Environment.getExternalStorageDirectory().getPath(), "--gui-theme=scummmodern", "--savepath=" + getDir("saves", 0).getPath() - }; + }); - int ret = scummvm.scummVMMain(args); - - // On exit, tear everything down for a fresh - // restart next time. - System.exit(ret); + scummvm_thread = new Thread(scummvm, "ScummVM"); + scummvm_thread.start(); } private boolean was_paused = false; -- cgit v1.2.3 From bd7e3e9bb20dada6d40143557c473fabd373b5ed Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 1 Mar 2011 22:16:10 +0100 Subject: ANDROID: cleanup --- backends/platform/android/android.cpp | 9 ++++++--- backends/platform/android/gfx.cpp | 11 +++-------- backends/platform/android/texture.cpp | 2 +- backends/platform/android/texture.h | 4 ---- 4 files changed, 10 insertions(+), 16 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 2af367e903..a61f7daee3 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -442,9 +442,12 @@ bool OSystem_Android::pollEvent(Common::Event &event) { } else { // Touchscreen events need to be converted // from device to game coords first. - const GLESTexture *tex = _show_overlay - ? static_cast(_overlay_texture) - : static_cast(_game_texture); + const GLESTexture *tex; + if (_show_overlay) + tex = _overlay_texture; + else + tex = _game_texture; + event.mouse.x = scalef(event.mouse.x, tex->width(), _egl_surface_width); event.mouse.y = scalef(event.mouse.y, tex->height(), diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 49f3d40e39..7fbe896d82 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -128,8 +128,8 @@ void OSystem_Android::initSize(uint width, uint height, _game_texture->allocBuffer(width, height); - GLuint overlay_width = _egl_surface_width; - GLuint overlay_height = _egl_surface_height; + int overlay_width = _egl_surface_width; + int overlay_height = _egl_surface_height; // 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 @@ -290,13 +290,8 @@ void OSystem_Android::updateScreen() { int res = JNI::swapBuffers(); - if (res) { + if (res) warning("swapBuffers returned 0x%x", res); -#if 0 - JNI::initSurface(); - setupSurface(); -#endif - } } Graphics::Surface *OSystem_Android::lockScreen() { diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index c5cba97dcd..9840e7d5c5 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -154,7 +154,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); - setDirtyRect(Common::Rect(x, y, x+w, y+h)); + setDirtyRect(Common::Rect(x, y, x + w, y + h)); if (static_cast(w) * bytesPerPixel() == pitch) { GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 050eafa073..12274621a1 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -59,10 +59,6 @@ public: return _surface.h; } - inline GLuint texture_name() const { - return _texture_name; - } - inline const Graphics::Surface *surface_const() const { return &_surface; } -- cgit v1.2.3 From 82a9beff2b52b2dd3eb7368dd46d8d50cb9f2d9f Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 2 Mar 2011 19:38:40 +0100 Subject: ANDROID: Move swapBuffers to the native side --- backends/platform/android/gfx.cpp | 6 +-- backends/platform/android/jni.cpp | 54 ++++++++++++++++++---- backends/platform/android/jni.h | 21 ++++++--- .../android/org/inodes/gus/scummvm/ScummVM.java | 15 +++--- 4 files changed, 67 insertions(+), 29 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 7fbe896d82..96ba5e729a 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -288,10 +288,8 @@ void OSystem_Android::updateScreen() { GLCALL(glPopMatrix()); - int res = JNI::swapBuffers(); - - if (res) - warning("swapBuffers returned 0x%x", res); + if (!JNI::swapBuffers()) + LOGW("swapBuffers failed: 0x%x", glGetError()); } Graphics::Surface *OSystem_Android::lockScreen() { diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 28a03d0555..3c2324dea1 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -40,6 +40,9 @@ jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { JavaVM *JNI::_vm = 0; jobject JNI::_jobj = 0; jobject JNI::_jobj_audio_track = 0; +jobject JNI::_jobj_egl = 0; +jobject JNI::_jobj_egl_display = 0; +jobject JNI::_jobj_egl_surface = 0; Common::Archive *JNI::_asset_archive = 0; OSystem_Android *JNI::_system = 0; @@ -63,10 +66,11 @@ jmethodID JNI::_MID_setWindowCaption = 0; jmethodID JNI::_MID_showVirtualKeyboard = 0; jmethodID JNI::_MID_getSysArchives = 0; jmethodID JNI::_MID_getPluginDirectories = 0; -jmethodID JNI::_MID_swapBuffers = 0; jmethodID JNI::_MID_initSurface = 0; jmethodID JNI::_MID_deinitSurface = 0; +jmethodID JNI::_MID_EGL10_eglSwapBuffers = 0; + jmethodID JNI::_MID_AudioTrack_flush = 0; jmethodID JNI::_MID_AudioTrack_pause = 0; jmethodID JNI::_MID_AudioTrack_play = 0; @@ -75,6 +79,8 @@ jmethodID JNI::_MID_AudioTrack_write = 0; const JNINativeMethod JNI::_natives[] = { { "create", "(Landroid/content/res/AssetManager;" + "Ljavax/microedition/khronos/egl/EGL10;" + "Ljavax/microedition/khronos/egl/EGLDisplay;" "Landroid/media/AudioTrack;II)V", (void *)JNI::create }, { "destroy", "()V", @@ -318,17 +324,23 @@ void JNI::getPluginDirectories(Common::FSList &dirs) { } } -void JNI::initSurface() { +bool JNI::initSurface() { JNIEnv *env = JNI::getEnv(); - env->CallVoidMethod(_jobj, _MID_initSurface); + jobject obj = env->CallObjectMethod(_jobj, _MID_initSurface); - if (env->ExceptionCheck()) { + if (!obj || env->ExceptionCheck()) { LOGE("initSurface failed"); env->ExceptionDescribe(); env->ExceptionClear(); + + return false; } + + _jobj_egl_surface = env->NewGlobalRef(obj); + + return true; } void JNI::deinitSurface() { @@ -342,6 +354,9 @@ void JNI::deinitSurface() { env->ExceptionDescribe(); env->ExceptionClear(); } + + env->DeleteGlobalRef(_jobj_egl_surface); + _jobj_egl_surface = 0; } void JNI::setAudioPause() { @@ -394,11 +409,12 @@ void JNI::setAudioStop() { // natives for the dark side -void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, - jint audio_sample_rate, jint audio_buffer_size) { +void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, + jobject egl, jobject egl_display, + jobject at, jint audio_sample_rate, jint audio_buffer_size) { assert(!_system); - _asset_archive = new AndroidAssetArchive(am); + _asset_archive = new AndroidAssetArchive(asset_manager); assert(_asset_archive); _system = new OSystem_Android(audio_sample_rate, audio_buffer_size); @@ -407,6 +423,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, // weak global ref to allow class to be unloaded // ... except dalvik implements NewWeakGlobalRef only on froyo //_jobj = env->NewWeakGlobalRef(self); + _jobj = env->NewGlobalRef(self); jclass cls = env->GetObjectClass(_jobj); @@ -422,10 +439,26 @@ void JNI::create(JNIEnv *env, jobject self, jobject am, jobject at, FIND_METHOD(showVirtualKeyboard, "(Z)V"); FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); - FIND_METHOD(swapBuffers, "()I"); - FIND_METHOD(initSurface, "()V"); + FIND_METHOD(initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;"); FIND_METHOD(deinitSurface, "()V"); +#undef FIND_METHOD + + _jobj_egl = env->NewGlobalRef(egl); + _jobj_egl_display = env->NewGlobalRef(egl_display); + + cls = env->GetObjectClass(_jobj_egl); + +#define FIND_METHOD(name, signature) do { \ + _MID_EGL10_ ## name = env->GetMethodID(cls, #name, signature); \ + if (_MID_EGL10_ ## name == 0) \ + return; \ + } while (0) + + FIND_METHOD(eglSwapBuffers, "(Ljavax/microedition/khronos/egl/EGLDisplay;" + "Ljavax/microedition/khronos/egl/EGLSurface;" + ")Z"); + #undef FIND_METHOD _jobj_audio_track = env->NewGlobalRef(at); @@ -459,6 +492,9 @@ void JNI::destroy(JNIEnv *env, jobject self) { // see above //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); + + JNI::getEnv()->DeleteGlobalRef(_jobj_egl_display); + JNI::getEnv()->DeleteGlobalRef(_jobj_egl); JNI::getEnv()->DeleteGlobalRef(_jobj_audio_track); JNI::getEnv()->DeleteGlobalRef(_jobj); } diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 0005136966..2a1405dfcc 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -60,8 +60,8 @@ public: static void showVirtualKeyboard(bool enable); static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); - static inline int swapBuffers(); - static void initSurface(); + static inline bool swapBuffers(); + static bool initSurface(); static void deinitSurface(); static void setAudioPause(); @@ -76,6 +76,9 @@ private: // back pointer to (java) peer instance static jobject _jobj; static jobject _jobj_audio_track; + static jobject _jobj_egl; + static jobject _jobj_egl_display; + static jobject _jobj_egl_surface; static Common::Archive *_asset_archive; static OSystem_Android *_system; @@ -97,10 +100,11 @@ private: static jmethodID _MID_showVirtualKeyboard; static jmethodID _MID_getSysArchives; static jmethodID _MID_getPluginDirectories; - static jmethodID _MID_swapBuffers; static jmethodID _MID_initSurface; static jmethodID _MID_deinitSurface; + static jmethodID _MID_EGL10_eglSwapBuffers; + static jmethodID _MID_AudioTrack_flush; static jmethodID _MID_AudioTrack_pause; static jmethodID _MID_AudioTrack_play; @@ -113,8 +117,10 @@ private: static void throwRuntimeException(JNIEnv *env, const char *msg); // natives for the dark side - static void create(JNIEnv *env, jobject self, jobject am, jobject at, - jint sample_rate, jint buffer_size); + static void create(JNIEnv *env, jobject self, jobject asset_manager, + jobject egl, jobject egl_display, + jobject at, jint audio_sample_rate, + jint audio_buffer_size); static void destroy(JNIEnv *env, jobject self); static void setSurface(JNIEnv *env, jobject self, jint width, jint height); @@ -124,10 +130,11 @@ private: static void enableZoning(JNIEnv *env, jobject self, jboolean enable); }; -inline int JNI::swapBuffers() { +inline bool JNI::swapBuffers() { JNIEnv *env = JNI::getEnv(); - return env->CallIntMethod(_jobj, _MID_swapBuffers); + return env->CallBooleanMethod(_jobj_egl, _MID_EGL10_eglSwapBuffers, + _jobj_egl_display, _jobj_egl_surface); } inline int JNI::writeAudio(JNIEnv *env, jbyteArray &data, int offset, int size) { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index db83303c7d..75407c66cc 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -38,6 +38,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { private String[] args; final private native void create(AssetManager asset_manager, + EGL10 egl, EGLDisplay eglDisplay, AudioTrack audio_track, int sample_rate, int buffer_size); final private native void destroy(); @@ -56,13 +57,6 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { abstract protected void showVirtualKeyboard(boolean enable); abstract protected String[] getSysArchives(); - final protected int swapBuffers() { - if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) - return egl.eglGetError(); - - return 0; - } - public ScummVM(AssetManager asset_manager, SurfaceHolder holder) { this.asset_manager = asset_manager; sem_surface = new Object(); @@ -126,7 +120,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { throw new RuntimeException("Error preparing the ScummVM thread", e); } - create(asset_manager, audio_track, sample_rate, buffer_size); + create(asset_manager, egl, eglDisplay, + audio_track, sample_rate, buffer_size); int res = main(args); @@ -192,7 +187,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { } // Callback from C++ peer instance - final protected void initSurface() throws Exception { + final protected EGLSurface initSurface() throws Exception { eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, surface_holder, null); @@ -210,6 +205,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { gl.glGetString(GL10.GL_VERSION), gl.glGetString(GL10.GL_RENDERER), gl.glGetString(GL10.GL_VENDOR))); + + return eglSurface; } // Callback from C++ peer instance -- cgit v1.2.3 From d6e838e1b38a568869ffd655a9bebd225593ffad Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 2 Mar 2011 19:45:07 +0100 Subject: ANDROID: Merge FIND_METHODs --- backends/platform/android/jni.cpp | 54 ++++++++++++++------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 3c2324dea1..7fe23d0d19 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -428,54 +428,38 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, jclass cls = env->GetObjectClass(_jobj); -#define FIND_METHOD(name, signature) do { \ - _MID_ ## name = env->GetMethodID(cls, #name, signature); \ - if (_MID_ ## name == 0) \ - return; \ +#define FIND_METHOD(prefix, name, signature) do { \ + _MID_ ## prefix ## name = env->GetMethodID(cls, #name, signature); \ + if (_MID_ ## prefix ## name == 0) \ + return; \ } while (0) - FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V"); - FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V"); - FIND_METHOD(showVirtualKeyboard, "(Z)V"); - FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); - FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); - FIND_METHOD(initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;"); - FIND_METHOD(deinitSurface, "()V"); - -#undef FIND_METHOD + FIND_METHOD(, setWindowCaption, "(Ljava/lang/String;)V"); + FIND_METHOD(, displayMessageOnOSD, "(Ljava/lang/String;)V"); + FIND_METHOD(, showVirtualKeyboard, "(Z)V"); + FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;"); + FIND_METHOD(, getPluginDirectories, "()[Ljava/lang/String;"); + FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;"); + FIND_METHOD(, deinitSurface, "()V"); _jobj_egl = env->NewGlobalRef(egl); _jobj_egl_display = env->NewGlobalRef(egl_display); cls = env->GetObjectClass(_jobj_egl); -#define FIND_METHOD(name, signature) do { \ - _MID_EGL10_ ## name = env->GetMethodID(cls, #name, signature); \ - if (_MID_EGL10_ ## name == 0) \ - return; \ - } while (0) - - FIND_METHOD(eglSwapBuffers, "(Ljavax/microedition/khronos/egl/EGLDisplay;" - "Ljavax/microedition/khronos/egl/EGLSurface;" - ")Z"); - -#undef FIND_METHOD + FIND_METHOD(EGL10_, eglSwapBuffers, + "(Ljavax/microedition/khronos/egl/EGLDisplay;" + "Ljavax/microedition/khronos/egl/EGLSurface;)Z"); _jobj_audio_track = env->NewGlobalRef(at); cls = env->GetObjectClass(_jobj_audio_track); -#define FIND_METHOD(name, signature) do { \ - _MID_AudioTrack_ ## name = env->GetMethodID(cls, #name, signature); \ - if (_MID_AudioTrack_ ## name == 0) \ - return; \ - } while (0) - - FIND_METHOD(flush, "()V"); - FIND_METHOD(pause, "()V"); - FIND_METHOD(play, "()V"); - FIND_METHOD(stop, "()V"); - FIND_METHOD(write, "([BII)I"); + FIND_METHOD(AudioTrack_, flush, "()V"); + FIND_METHOD(AudioTrack_, pause, "()V"); + FIND_METHOD(AudioTrack_, play, "()V"); + FIND_METHOD(AudioTrack_, stop, "()V"); + FIND_METHOD(AudioTrack_, write, "([BII)I"); #undef FIND_METHOD -- cgit v1.2.3 From ccfe427eb542235070e8576b4cc47217d92046fd Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 2 Mar 2011 19:48:29 +0100 Subject: ANDROID: Check for a surface in updateScreen() --- backends/platform/android/android.cpp | 2 -- backends/platform/android/gfx.cpp | 3 +++ backends/platform/android/jni.h | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index a61f7daee3..484f6886ec 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -400,8 +400,6 @@ bool OSystem_Android::pollEvent(Common::Event &event) { _screen_changeid = JNI::surface_changeid; JNI::deinitSurface(); - - // TODO prevent swapBuffers } } diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 96ba5e729a..15e517a07f 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -198,6 +198,9 @@ void OSystem_Android::updateScreen() { GLTHREADCHECK; + if (!JNI::haveSurface()) + return; + if (!_force_redraw && !_game_texture->dirty() && !_overlay_texture->dirty() && diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 2a1405dfcc..d2bc89e3d1 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -60,6 +60,7 @@ public: static void showVirtualKeyboard(bool enable); static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); + static inline bool haveSurface(); static inline bool swapBuffers(); static bool initSurface(); static void deinitSurface(); @@ -130,6 +131,10 @@ private: static void enableZoning(JNIEnv *env, jobject self, jboolean enable); }; +inline bool JNI::haveSurface() { + return _jobj_egl_surface != 0; +} + inline bool JNI::swapBuffers() { JNIEnv *env = JNI::getEnv(); -- cgit v1.2.3 From 25ef065a4172443eebdd1031c8a387f30f930ec4 Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 2 Mar 2011 20:25:47 +0100 Subject: ANDROID: Implement pause/resume Don't just kill the whole process when the Activity is stopped. Instead, use its events to pause or resume audio and the running engine (if any). Of course not every engines implements that... but at least an incoming call doesn't kill the game now (lol). --- backends/platform/android/jni.cpp | 13 +++++++ backends/platform/android/jni.h | 2 ++ .../android/org/inodes/gus/scummvm/ScummVM.java | 13 ++++--- .../org/inodes/gus/scummvm/ScummVMActivity.java | 42 +++++++++++++++------- 4 files changed, 52 insertions(+), 18 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 7fe23d0d19..1e28b065b4 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -27,6 +27,7 @@ #include "base/main.h" #include "common/config-manager.h" +#include "engines/engine.h" #include "backends/platform/android/android.h" #include "backends/platform/android/asset-archive.h" @@ -93,6 +94,8 @@ const JNINativeMethod JNI::_natives[] = { (void *)JNI::pushEvent }, { "enableZoning", "(Z)V", (void *)JNI::enableZoning }, + { "pauseEngine", "(Z)V", + (void *)JNI::pauseEngine } }; JNI::JNI() { @@ -613,5 +616,15 @@ void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { _system->enableZoning(enable); } +void JNI::pauseEngine(JNIEnv *env, jobject self, jboolean pause) { + if (!_system || !g_engine) + return; + + if ((pause && !g_engine->isPaused()) || (!pause && g_engine->isPaused())) { + LOGD("pauseEngine: %d", pause); + g_engine->pauseEngine(pause); + } +} + #endif diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index d2bc89e3d1..7eb10791aa 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -129,6 +129,8 @@ private: static void pushEvent(JNIEnv *env, jobject self, jobject java_event); static void enableZoning(JNIEnv *env, jobject self, jboolean enable); + + static void pauseEngine(JNIEnv *env, jobject self, jboolean pause); }; inline bool JNI::haveSurface() { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 75407c66cc..ffb0109e6c 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -44,6 +44,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { final private native void destroy(); final private native void setSurface(int width, int height); final private native int main(String[] args); + final private native void pauseEngine(boolean pause); // Set scummvm config options final public native void enableZoning(boolean enable); @@ -134,12 +135,14 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { System.exit(res); } - public void pause() { - // TODO - } + public void pause(boolean pause) { + if (audio_track != null && !pause) + audio_track.play(); + + pauseEngine(pause); - public void resume() { - // TODO + if (audio_track != null && pause) + audio_track.stop(); } final private void initEGL() throws Exception { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 92247dea96..22ccaf0b62 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -161,30 +161,46 @@ public class ScummVMActivity extends Activity { scummvm_thread.start(); } - private boolean was_paused = false; - @Override - public void onPause() { - if (scummvm != null) { - was_paused = true; - scummvm.pause(); - } + public void onStart() { + Log.d(ScummVM.LOG_TAG, "onStart"); - super.onPause(); + super.onStart(); } @Override public void onResume() { + Log.d(ScummVM.LOG_TAG, "onResume"); + super.onResume(); - if (scummvm != null && was_paused) - scummvm.resume(); + if (scummvm != null) + scummvm.pause(false); + } + + @Override + public void onPause() { + Log.d(ScummVM.LOG_TAG, "onPause"); + + super.onPause(); - was_paused = false; + if (scummvm != null) + scummvm.pause(true); } @Override public void onStop() { + Log.d(ScummVM.LOG_TAG, "onStop"); + + super.onStop(); + } + + @Override + public void onDestroy() { + Log.d(ScummVM.LOG_TAG, "onDestroy"); + + super.onDestroy(); + if (scummvm != null) { scummvm.pushEvent(new Event(Event.EVENT_QUIT)); @@ -194,9 +210,9 @@ public class ScummVMActivity extends Activity { } catch (InterruptedException e) { Log.i(ScummVM.LOG_TAG, "Error while joining ScummVM thread", e); } - } - super.onStop(); + scummvm = null; + } } static final int MSG_MENU_LONG_PRESS = 1; -- cgit v1.2.3 From c2d4cce429baa56b5a0962a854ece6163270995f Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 2 Mar 2011 22:26:15 +0100 Subject: ANDROID: On pause, put all threads in a coma Since not every engine respects pauseEngine(), or they're in a state where it simply gets ignored, put all threads in a group coma. Without this, code still kept looping and wasting cpu cycles, while the user might want to do use her/his droid for something else. --- backends/platform/android/android.cpp | 25 +++++++++++++++++++++++++ backends/platform/android/jni.cpp | 29 ++++++++++++++++++++++++----- backends/platform/android/jni.h | 4 ++++ 3 files changed, 53 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 484f6886ec..d4a2253c30 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -151,6 +151,12 @@ void *OSystem_Android::timerThreadFunc(void *arg) { tv.tv_nsec = 100 * 1000 * 1000; // 100ms while (!system->_timer_thread_exit) { + if (JNI::pause) { + LOGD("timer thread going to sleep"); + sem_wait(&JNI::pause_sem); + LOGD("timer thread woke up"); + } + timer->handler(); nanosleep(&tv, 0); } @@ -192,6 +198,12 @@ void *OSystem_Android::audioThreadFunc(void *arg) { uint silence_count = 33; while (!system->_audio_thread_exit) { + if (JNI::pause) { + LOGD("audio thread going to sleep"); + sem_wait(&JNI::pause_sem); + LOGD("audio thread woke up"); + } + buf = (byte *)env->GetPrimitiveArrayCritical(bufa, 0); assert(buf); @@ -401,6 +413,19 @@ bool OSystem_Android::pollEvent(Common::Event &event) { _screen_changeid = JNI::surface_changeid; JNI::deinitSurface(); } + + if (JNI::pause) { + // release some resources + // TODO + // free textures? they're garbled anyway since no engine + // respects EVENT_SCREEN_CHANGED + LOGD("deinitialiting surface"); + JNI::deinitSurface(); + + LOGD("main thread going to sleep"); + sem_wait(&JNI::pause_sem); + LOGD("main thread woke up"); + } } lockMutex(_event_queue_lock); diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 1e28b065b4..9ecd9577e7 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -48,6 +48,9 @@ jobject JNI::_jobj_egl_surface = 0; Common::Archive *JNI::_asset_archive = 0; OSystem_Android *JNI::_system = 0; +bool JNI::pause = false; +sem_t JNI::pause_sem = { 0 }; + int JNI::surface_changeid = 0; int JNI::egl_surface_width = 0; int JNI::egl_surface_height = 0; @@ -417,6 +420,10 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, jobject at, jint audio_sample_rate, jint audio_buffer_size) { assert(!_system); + pause = false; + // initial value of zero! + sem_init(&pause_sem, 0, 0); + _asset_archive = new AndroidAssetArchive(asset_manager); assert(_asset_archive); @@ -477,6 +484,8 @@ void JNI::destroy(JNIEnv *env, jobject self) { g_system = 0; _system = 0; + sem_destroy(&pause_sem); + // see above //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); @@ -616,13 +625,23 @@ void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { _system->enableZoning(enable); } -void JNI::pauseEngine(JNIEnv *env, jobject self, jboolean pause) { - if (!_system || !g_engine) +void JNI::pauseEngine(JNIEnv *env, jobject self, jboolean value) { + if (!_system) return; - if ((pause && !g_engine->isPaused()) || (!pause && g_engine->isPaused())) { - LOGD("pauseEngine: %d", pause); - g_engine->pauseEngine(pause); + if (g_engine) + if ((value && !g_engine->isPaused()) || + (!value && g_engine->isPaused())) { + LOGD("pauseEngine: %d", value); + g_engine->pauseEngine(value); + } + + pause = value; + + if (!pause) { + // wake up all threads + for (uint i = 0; i < 3; ++i) + sem_post(&pause_sem); } } diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 7eb10791aa..569a3dd79b 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -29,6 +29,7 @@ #if defined(__ANDROID__) #include +#include #include "common/fs.h" #include "common/archive.h" @@ -41,6 +42,9 @@ private: virtual ~JNI(); public: + static bool pause; + static sem_t pause_sem; + static int surface_changeid; static int egl_surface_width; static int egl_surface_height; -- cgit v1.2.3 From 2d4a64d18493b142b1899a822202015339733cfa Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 2 Mar 2011 23:00:48 +0100 Subject: ANDROID: Properly release texture resources When calling glDeleteTextures() we need a valid surface. --- backends/platform/android/android.cpp | 31 ++++++++++++++++++++++++------- backends/platform/android/gfx.cpp | 15 --------------- backends/platform/android/texture.cpp | 7 +++++-- backends/platform/android/texture.h | 4 +++- 4 files changed, 32 insertions(+), 25 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index d4a2253c30..491e5fbc72 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -124,10 +124,6 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : OSystem_Android::~OSystem_Android() { ENTER(); - delete _game_texture; - delete _overlay_texture; - delete _mouse_texture; - delete _savefile; delete _timer; delete _mixer; @@ -323,6 +319,10 @@ void OSystem_Android::initBackend() { setupSurface(); + _game_texture = new GLESPaletteTexture(); + _overlay_texture = new GLES4444Texture(); + _mouse_texture = new GLESPaletteATexture(); + // renice this thread to boost the audio thread if (setpriority(PRIO_PROCESS, 0, 19) < 0) warning("couldn't renice the main thread"); @@ -400,9 +400,17 @@ bool OSystem_Android::pollEvent(Common::Event &event) { if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { LOGD("initializing surface"); + _game_texture->release(); + _overlay_texture->release(); + _mouse_texture->release(); + JNI::deinitSurface(); setupSurface(); + _game_texture->reinit(); + _overlay_texture->reinit(); + _mouse_texture->reinit(); + event.type = Common::EVENT_SCREEN_CHANGED; return true; @@ -410,15 +418,20 @@ bool OSystem_Android::pollEvent(Common::Event &event) { LOGD("deinitialiting surface"); + _game_texture->release(); + _overlay_texture->release(); + _mouse_texture->release(); + _screen_changeid = JNI::surface_changeid; JNI::deinitSurface(); } if (JNI::pause) { // release some resources - // TODO - // free textures? they're garbled anyway since no engine - // respects EVENT_SCREEN_CHANGED + _game_texture->release(); + _overlay_texture->release(); + _mouse_texture->release(); + LOGD("deinitialiting surface"); JNI::deinitSurface(); @@ -573,6 +586,10 @@ void OSystem_Android::quit() { _timer_thread_exit = true; pthread_join(_timer_thread, 0); + delete _game_texture; + delete _overlay_texture; + delete _mouse_texture; + JNI::deinitSurface(); } diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 15e517a07f..e2cc854a1d 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -94,21 +94,6 @@ void OSystem_Android::setupSurface() { 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)); diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 9840e7d5c5..ea8a89df78 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -98,12 +98,15 @@ GLESTexture::GLESTexture() : } GLESTexture::~GLESTexture() { + release(); +} + +void GLESTexture::release() { debug("Destroying texture %u", _texture_name); GLCALL(glDeleteTextures(1, &_texture_name)); } -void GLESTexture::reinitGL() { - GLCALL(glDeleteTextures(1, &_texture_name)); +void GLESTexture::reinit() { GLCALL(glGenTextures(1, &_texture_name)); // bypass allocBuffer() shortcut to reinit the texture properly diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 12274621a1..f1d5cad6e9 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -42,7 +42,9 @@ public: GLESTexture(); virtual ~GLESTexture(); - virtual void reinitGL(); + void release(); + void reinit(); + virtual void allocBuffer(GLuint width, GLuint height); virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, -- cgit v1.2.3 From 719d22918d8058cba68923b4c11b792dbe76f22f Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 2 Mar 2011 23:41:59 +0100 Subject: ANDROID: Respect the pause level. --- backends/platform/android/jni.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 9ecd9577e7..175973079f 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -629,12 +629,10 @@ void JNI::pauseEngine(JNIEnv *env, jobject self, jboolean value) { if (!_system) return; - if (g_engine) - if ((value && !g_engine->isPaused()) || - (!value && g_engine->isPaused())) { - LOGD("pauseEngine: %d", value); - g_engine->pauseEngine(value); - } + if (g_engine) { + LOGD("pauseEngine: %d", value); + g_engine->pauseEngine(value); + } pause = value; -- cgit v1.2.3 From 1e3c96b3efaea537dfe82b1d535d1d46cc82a8a0 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 3 Mar 2011 11:20:37 +0100 Subject: ANDROID: Formatting/whitespaces --- backends/platform/android/android.cpp | 10 ++++++---- backends/platform/android/android.h | 14 ++++++++++---- backends/platform/android/asset-archive.cpp | 14 ++++++++------ backends/platform/android/jni.cpp | 4 ++-- backends/platform/android/jni.h | 3 ++- .../platform/android/org/inodes/gus/scummvm/Unpacker.java | 1 + backends/platform/android/texture.cpp | 3 ++- 7 files changed, 31 insertions(+), 18 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 491e5fbc72..2d396f2c48 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -55,7 +55,8 @@ extern "C" { expr, file, line); } - void __assert2(const char *file, int line, const char *func, const char *expr) { + void __assert2(const char *file, int line, const char *func, + const char *expr) { __android_log_assert(expr, android_log_tag, "Assertion failure: '%s' in %s:%d (%s)", expr, file, line, func); @@ -152,7 +153,7 @@ void *OSystem_Android::timerThreadFunc(void *arg) { sem_wait(&JNI::pause_sem); LOGD("timer thread woke up"); } - + timer->handler(); nanosleep(&tv, 0); } @@ -199,7 +200,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { sem_wait(&JNI::pause_sem); LOGD("audio thread woke up"); } - + buf = (byte *)env->GetPrimitiveArrayCritical(bufa, 0); assert(buf); @@ -650,7 +651,8 @@ void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, JNI::addSysArchivesToSearchSet(s, priority); } -void OSystem_Android::logMessage(LogMessageType::Type type, const char *message) { +void OSystem_Android::logMessage(LogMessageType::Type type, + const char *message) { switch (type) { case LogMessageType::kDebug: __android_log_write(ANDROID_LOG_DEBUG, android_log_tag, message); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index aa6016e3d2..5db10fb180 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -177,7 +177,8 @@ protected: 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 copyRectToScreen(const byte *buf, int pitch, int x, int y, + int w, int h); virtual void updateScreen(); virtual Graphics::Surface *lockScreen(); virtual void unlockScreen(); @@ -190,7 +191,8 @@ public: 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 void copyRectToOverlay(const OverlayColor *buf, int pitch, + int x, int y, int w, int h); virtual int16 getOverlayHeight(); virtual int16 getOverlayWidth(); @@ -214,7 +216,10 @@ public: 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 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); @@ -240,7 +245,8 @@ public: 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); + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, + int priority = 0); }; #endif diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index eb2530823d..26b1a6ad39 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -99,7 +99,7 @@ JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) : { _input_stream = env->NewGlobalRef(is); _buflen = 8192; - _buf = static_cast(env->NewGlobalRef(env->NewByteArray(_buflen))); + _buf = (jbyteArray)env->NewGlobalRef(env->NewByteArray(_buflen)); jclass cls = env->GetObjectClass(_input_stream); MID_mark = env->GetMethodID(cls, "mark", "(I)V"); @@ -142,7 +142,7 @@ uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { if (_buflen < jint(dataSize)) { _buflen = dataSize; - + env->DeleteGlobalRef(_buf); _buf = static_cast(env->NewGlobalRef(env->NewByteArray(_buflen))); } @@ -304,7 +304,8 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) : _declared_len = env->CallLongMethod(_assetfd, MID_getDeclaredLength); jmethodID MID_getFileDescriptor = - env->GetMethodID(cls, "getFileDescriptor", "()Ljava/io/FileDescriptor;"); + env->GetMethodID(cls, "getFileDescriptor", + "()Ljava/io/FileDescriptor;"); assert(MID_getFileDescriptor); jobject javafd = env->CallObjectMethod(_assetfd, MID_getFileDescriptor); assert(javafd); @@ -376,8 +377,8 @@ AndroidAssetArchive::AndroidAssetArchive(jobject am) { "(Ljava/lang/String;I)Ljava/io/InputStream;"); assert(MID_open); - MID_openFd = env->GetMethodID(cls, "openFd", - "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); + MID_openFd = env->GetMethodID(cls, "openFd", "(Ljava/lang/String;)" + "Landroid/content/res/AssetFileDescriptor;"); assert(MID_openFd); MID_list = env->GetMethodID(cls, "list", @@ -421,7 +422,8 @@ int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { dirlist.pop_back(); jstring jpath = env->NewStringUTF(dir.c_str()); - jobjectArray jpathlist = static_cast(env->CallObjectMethod(_am, MID_list, jpath)); + jobjectArray jpathlist = + (jobjectArray)env->CallObjectMethod(_am, MID_list, jpath); if (env->ExceptionCheck()) { warning("Error while calling AssetManager->list(%s). Ignoring.", diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 175973079f..e1acabd6d3 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -90,9 +90,9 @@ const JNINativeMethod JNI::_natives[] = { { "destroy", "()V", (void *)JNI::destroy }, { "setSurface", "(II)V", - (void *)JNI::setSurface }, + (void *)JNI::setSurface }, { "main", "([Ljava/lang/String;)I", - (void *)JNI::main }, + (void *)JNI::main }, { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", (void *)JNI::pushEvent }, { "enableZoning", "(Z)V", diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 569a3dd79b..84688137df 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -149,7 +149,8 @@ inline bool JNI::swapBuffers() { } inline int JNI::writeAudio(JNIEnv *env, jbyteArray &data, int offset, int size) { - return env->CallIntMethod(_jobj_audio_track, _MID_AudioTrack_write, data, offset, size); + return env->CallIntMethod(_jobj_audio_track, _MID_AudioTrack_write, data, + offset, size); } #endif diff --git a/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java index 8811b1f3ae..c4b2ad7f5d 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java +++ b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java @@ -370,3 +370,4 @@ public class Unpacker extends Activity { } } } + diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index ea8a89df78..cb12d264b8 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -332,7 +332,8 @@ void GLESPaletteTexture::uploadTexture() const { 0, texture_size, _texture)); } -void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { +void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, + GLshort h) { if (_all_dirty) { GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, -- cgit v1.2.3 From a7a7542d1de3f6bb8d076b04cf63a761f01472e1 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 3 Mar 2011 11:35:21 +0100 Subject: ANDROID: Remove an indirection when pausing --- backends/platform/android/android.cpp | 5 +++++ backends/platform/android/jni.cpp | 6 +++--- backends/platform/android/jni.h | 2 +- .../platform/android/org/inodes/gus/scummvm/ScummVM.java | 14 ++------------ .../android/org/inodes/gus/scummvm/ScummVMActivity.java | 4 ++-- 5 files changed, 13 insertions(+), 18 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 2d396f2c48..35a6421ede 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -196,6 +196,11 @@ void *OSystem_Android::audioThreadFunc(void *arg) { while (!system->_audio_thread_exit) { if (JNI::pause) { + JNI::setAudioStop(); + + paused = true; + silence_count = 33; + LOGD("audio thread going to sleep"); sem_wait(&JNI::pause_sem); LOGD("audio thread woke up"); diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index e1acabd6d3..73b74394c0 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -97,8 +97,8 @@ const JNINativeMethod JNI::_natives[] = { (void *)JNI::pushEvent }, { "enableZoning", "(Z)V", (void *)JNI::enableZoning }, - { "pauseEngine", "(Z)V", - (void *)JNI::pauseEngine } + { "setPause", "(Z)V", + (void *)JNI::setPause } }; JNI::JNI() { @@ -625,7 +625,7 @@ void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { _system->enableZoning(enable); } -void JNI::pauseEngine(JNIEnv *env, jobject self, jboolean value) { +void JNI::setPause(JNIEnv *env, jobject self, jboolean value) { if (!_system) return; diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 84688137df..146938636d 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -134,7 +134,7 @@ private: static void pushEvent(JNIEnv *env, jobject self, jobject java_event); static void enableZoning(JNIEnv *env, jobject self, jboolean enable); - static void pauseEngine(JNIEnv *env, jobject self, jboolean pause); + static void setPause(JNIEnv *env, jobject self, jboolean value); }; inline bool JNI::haveSurface() { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index ffb0109e6c..20e0382c00 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -44,9 +44,9 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { final private native void destroy(); final private native void setSurface(int width, int height); final private native int main(String[] args); - final private native void pauseEngine(boolean pause); - // Set scummvm config options + // pause the engine and all native threads + final public native void setPause(boolean pause); final public native void enableZoning(boolean enable); // Feed an event to ScummVM. Safe to call from other threads. final public native void pushEvent(Event e); @@ -135,16 +135,6 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { System.exit(res); } - public void pause(boolean pause) { - if (audio_track != null && !pause) - audio_track.play(); - - pauseEngine(pause); - - if (audio_track != null && pause) - audio_track.stop(); - } - final private void initEGL() throws Exception { egl = (EGL10)EGLContext.getEGL(); eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 22ccaf0b62..921e248211 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -175,7 +175,7 @@ public class ScummVMActivity extends Activity { super.onResume(); if (scummvm != null) - scummvm.pause(false); + scummvm.setPause(false); } @Override @@ -185,7 +185,7 @@ public class ScummVMActivity extends Activity { super.onPause(); if (scummvm != null) - scummvm.pause(true); + scummvm.setPause(true); } @Override -- cgit v1.2.3 From 3df060b6567d37a1a3bee314a686bb2435e482f6 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 3 Mar 2011 11:55:51 +0100 Subject: ANDROID: Rename member vars according to our style --- .../android/org/inodes/gus/scummvm/ScummVM.java | 177 +++++++++++---------- .../org/inodes/gus/scummvm/ScummVMActivity.java | 42 ++--- .../org/inodes/gus/scummvm/ScummVMApplication.java | 6 +- 3 files changed, 113 insertions(+), 112 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 20e0382c00..f263b89015 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -21,24 +21,24 @@ import java.util.LinkedHashMap; public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { final protected static String LOG_TAG = "ScummVM"; - final private AssetManager asset_manager; - final private Object sem_surface; + final private AssetManager _asset_manager; + final private Object _sem_surface; - private EGL10 egl; - private EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY; - private EGLConfig eglConfig; - private EGLContext eglContext = EGL10.EGL_NO_CONTEXT; - private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; + private EGL10 _egl; + private EGLDisplay _egl_display = EGL10.EGL_NO_DISPLAY; + private EGLConfig _egl_config; + private EGLContext _egl_context = EGL10.EGL_NO_CONTEXT; + private EGLSurface _egl_surface = EGL10.EGL_NO_SURFACE; - private SurfaceHolder surface_holder; - private AudioTrack audio_track; - private int sample_rate = 0; - private int buffer_size = 0; + private SurfaceHolder _surface_holder; + private AudioTrack _audio_track; + private int _sample_rate = 0; + private int _buffer_size = 0; - private String[] args; + private String[] _args; - final private native void create(AssetManager asset_manager, - EGL10 egl, EGLDisplay eglDisplay, + final private native void create(AssetManager _asset_manager, + EGL10 egl, EGLDisplay egl_display, AudioTrack audio_track, int sample_rate, int buffer_size); final private native void destroy(); @@ -59,8 +59,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { abstract protected String[] getSysArchives(); public ScummVM(AssetManager asset_manager, SurfaceHolder holder) { - this.asset_manager = asset_manager; - sem_surface = new Object(); + _asset_manager = asset_manager; + _sem_surface = new Object(); holder.addCallback(this); } @@ -78,9 +78,9 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { Log.d(LOG_TAG, String.format("surfaceChanged: %dx%d (%d)", width, height, format)); - synchronized(sem_surface) { - surface_holder = holder; - sem_surface.notifyAll(); + synchronized(_sem_surface) { + _surface_holder = holder; + _sem_surface.notifyAll(); } // store values for the native code @@ -91,9 +91,9 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { final public void surfaceDestroyed(SurfaceHolder holder) { Log.d(LOG_TAG, "surfaceDestroyed"); - synchronized(sem_surface) { - surface_holder = null; - sem_surface.notifyAll(); + synchronized(_sem_surface) { + _surface_holder = null; + _sem_surface.notifyAll(); } // clear values for the native code @@ -101,7 +101,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { } final public void setArgs(String[] args) { - this.args = args; + _args = args; } final public void run() { @@ -110,9 +110,9 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { initEGL(); // wait for the surfaceChanged callback - synchronized(sem_surface) { - while (surface_holder == null) - sem_surface.wait(); + synchronized(_sem_surface) { + while (_surface_holder == null) + _sem_surface.wait(); } } catch (Exception e) { deinitEGL(); @@ -121,10 +121,10 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { throw new RuntimeException("Error preparing the ScummVM thread", e); } - create(asset_manager, egl, eglDisplay, - audio_track, sample_rate, buffer_size); + create(_asset_manager, _egl, _egl_display, + _audio_track, _sample_rate, _buffer_size); - int res = main(args); + int res = main(_args); destroy(); @@ -136,14 +136,14 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { } final private void initEGL() throws Exception { - egl = (EGL10)EGLContext.getEGL(); - eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + _egl = (EGL10)EGLContext.getEGL(); + _egl_display = _egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] version = new int[2]; - egl.eglInitialize(eglDisplay, version); + _egl.eglInitialize(_egl_display, version); int[] num_config = new int[1]; - egl.eglChooseConfig(eglDisplay, configSpec, null, 0, num_config); + _egl.eglChooseConfig(_egl_display, configSpec, null, 0, num_config); final int numConfigs = num_config[0]; @@ -151,8 +151,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { throw new IllegalArgumentException("No configs match configSpec"); EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs, - num_config); + _egl.eglChooseConfig(_egl_display, configSpec, configs, numConfigs, + num_config); if (false) { Log.d(LOG_TAG, String.format("Found %d EGL configurations.", @@ -163,119 +163,120 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { // Android's eglChooseConfig is busted in several versions and // devices so we have to filter/rank the configs again ourselves. - eglConfig = chooseEglConfig(configs); + _egl_config = chooseEglConfig(configs); if (false) { Log.d(LOG_TAG, String.format("Chose from %d EGL configs", numConfigs)); - dumpEglConfig(eglConfig); + dumpEglConfig(_egl_config); } - eglContext = egl.eglCreateContext(eglDisplay, eglConfig, + _egl_context = _egl.eglCreateContext(_egl_display, _egl_config, EGL10.EGL_NO_CONTEXT, null); - if (eglContext == EGL10.EGL_NO_CONTEXT) + if (_egl_context == EGL10.EGL_NO_CONTEXT) throw new Exception(String.format("Failed to create context: 0x%x", - egl.eglGetError())); + _egl.eglGetError())); } // Callback from C++ peer instance final protected EGLSurface initSurface() throws Exception { - eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, - surface_holder, null); + _egl_surface = _egl.eglCreateWindowSurface(_egl_display, _egl_config, + _surface_holder, null); - if (eglSurface == EGL10.EGL_NO_SURFACE) + if (_egl_surface == EGL10.EGL_NO_SURFACE) throw new Exception(String.format( - "eglCreateWindowSurface failed: 0x%x", egl.eglGetError())); + "eglCreateWindowSurface failed: 0x%x", _egl.eglGetError())); - egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + _egl.eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, + _egl_context); - GL10 gl = (GL10)eglContext.getGL(); + GL10 gl = (GL10)_egl_context.getGL(); Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)", - egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION), - egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR), + _egl.eglQueryString(_egl_display, EGL10.EGL_VERSION), + _egl.eglQueryString(_egl_display, EGL10.EGL_VENDOR), gl.glGetString(GL10.GL_VERSION), gl.glGetString(GL10.GL_RENDERER), gl.glGetString(GL10.GL_VENDOR))); - return eglSurface; + return _egl_surface; } // Callback from C++ peer instance final protected void deinitSurface() { - if (eglDisplay != EGL10.EGL_NO_DISPLAY) { - egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, + if (_egl_display != EGL10.EGL_NO_DISPLAY) { + _egl.eglMakeCurrent(_egl_display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - if (eglSurface != EGL10.EGL_NO_SURFACE) - egl.eglDestroySurface(eglDisplay, eglSurface); + if (_egl_surface != EGL10.EGL_NO_SURFACE) + _egl.eglDestroySurface(_egl_display, _egl_surface); } - eglSurface = EGL10.EGL_NO_SURFACE; + _egl_surface = EGL10.EGL_NO_SURFACE; } final private void deinitEGL() { - if (eglDisplay != EGL10.EGL_NO_DISPLAY) { - egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, + if (_egl_display != EGL10.EGL_NO_DISPLAY) { + _egl.eglMakeCurrent(_egl_display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - if (eglSurface != EGL10.EGL_NO_SURFACE) - egl.eglDestroySurface(eglDisplay, eglSurface); + if (_egl_surface != EGL10.EGL_NO_SURFACE) + _egl.eglDestroySurface(_egl_display, _egl_surface); - if (eglContext != EGL10.EGL_NO_CONTEXT) - egl.eglDestroyContext(eglDisplay, eglContext); + if (_egl_context != EGL10.EGL_NO_CONTEXT) + _egl.eglDestroyContext(_egl_display, _egl_context); - egl.eglTerminate(eglDisplay); + _egl.eglTerminate(_egl_display); } - eglSurface = EGL10.EGL_NO_SURFACE; - eglContext = EGL10.EGL_NO_CONTEXT; - eglConfig = null; - eglDisplay = EGL10.EGL_NO_DISPLAY; - egl = null; + _egl_surface = EGL10.EGL_NO_SURFACE; + _egl_context = EGL10.EGL_NO_CONTEXT; + _egl_config = null; + _egl_display = EGL10.EGL_NO_DISPLAY; + _egl = null; } final private void initAudio() throws Exception { - sample_rate = AudioTrack.getNativeOutputSampleRate( + _sample_rate = AudioTrack.getNativeOutputSampleRate( AudioManager.STREAM_MUSIC); - buffer_size = AudioTrack.getMinBufferSize(sample_rate, + _buffer_size = AudioTrack.getMinBufferSize(_sample_rate, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT); // ~100ms - int buffer_size_want = (sample_rate * 2 * 2 / 10) & ~1023; + int buffer_size_want = (_sample_rate * 2 * 2 / 10) & ~1023; - if (buffer_size < buffer_size_want) { + if (_buffer_size < buffer_size_want) { Log.w(LOG_TAG, String.format( - "adjusting audio buffer size (was: %d)", buffer_size)); + "adjusting audio buffer size (was: %d)", _buffer_size)); - buffer_size = buffer_size_want; + _buffer_size = buffer_size_want; } Log.i(LOG_TAG, String.format("Using %d bytes buffer for %dHz audio", - buffer_size, sample_rate)); + _buffer_size, _sample_rate)); - audio_track = new AudioTrack(AudioManager.STREAM_MUSIC, - sample_rate, + _audio_track = new AudioTrack(AudioManager.STREAM_MUSIC, + _sample_rate, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, - buffer_size, + _buffer_size, AudioTrack.MODE_STREAM); - if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) + if (_audio_track.getState() != AudioTrack.STATE_INITIALIZED) throw new Exception( String.format("Error initialising AudioTrack: %d", - audio_track.getState())); + _audio_track.getState())); } final private void deinitAudio() { - if (audio_track != null) - audio_track.stop(); + if (_audio_track != null) + _audio_track.stop(); - audio_track = null; - buffer_size = 0; - sample_rate = 0; + _audio_track = null; + _buffer_size = 0; + _sample_rate = 0; } static final int configSpec[] = { @@ -325,7 +326,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { int[] value = new int[1]; for (Map.Entry entry : attribs.entrySet()) { - egl.eglGetConfigAttrib(eglDisplay, config, + _egl.eglGetConfigAttrib(_egl_display, config, entry.getValue(), value); if (value[0] == EGL10.EGL_NONE) @@ -344,14 +345,14 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { EGLConfig config = configs[i]; int score = 10000; - egl.eglGetConfigAttrib(eglDisplay, config, + _egl.eglGetConfigAttrib(_egl_display, config, EGL10.EGL_SURFACE_TYPE, value); // must have if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0) continue; - egl.eglGetConfigAttrib(eglDisplay, config, + _egl.eglGetConfigAttrib(_egl_display, config, EGL10.EGL_CONFIG_CAVEAT, value); if (value[0] != EGL10.EGL_NONE) @@ -365,7 +366,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { }; for (int component : colorBits) { - egl.eglGetConfigAttrib(eglDisplay, config, component, value); + _egl.eglGetConfigAttrib(_egl_display, config, component, value); // boost if >5 bits accuracy if (value[0] >= 5) @@ -375,7 +376,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { score -= value[0]; } - egl.eglGetConfigAttrib(eglDisplay, config, + _egl.eglGetConfigAttrib(_egl_display, config, EGL10.EGL_DEPTH_SIZE, value); // penalize for wasted bits diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 921e248211..8cb3d80063 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -96,8 +96,8 @@ public class ScummVMActivity extends Activity { } - private MyScummVM scummvm; - private Thread scummvm_thread; + private MyScummVM _scummvm; + private Thread _scummvm_thread; @Override public void onCreate(Bundle savedInstanceState) { @@ -147,9 +147,9 @@ public class ScummVMActivity extends Activity { getFilesDir().mkdirs(); // Start ScummVM - scummvm = new MyScummVM(main_surface.getHolder()); + _scummvm = new MyScummVM(main_surface.getHolder()); - scummvm.setArgs(new String[] { + _scummvm.setArgs(new String[] { "ScummVM", "--config=" + getFileStreamPath("scummvmrc").getPath(), "--path=" + Environment.getExternalStorageDirectory().getPath(), @@ -157,8 +157,8 @@ public class ScummVMActivity extends Activity { "--savepath=" + getDir("saves", 0).getPath() }); - scummvm_thread = new Thread(scummvm, "ScummVM"); - scummvm_thread.start(); + _scummvm_thread = new Thread(_scummvm, "ScummVM"); + _scummvm_thread.start(); } @Override @@ -174,8 +174,8 @@ public class ScummVMActivity extends Activity { super.onResume(); - if (scummvm != null) - scummvm.setPause(false); + if (_scummvm != null) + _scummvm.setPause(false); } @Override @@ -184,8 +184,8 @@ public class ScummVMActivity extends Activity { super.onPause(); - if (scummvm != null) - scummvm.setPause(true); + if (_scummvm != null) + _scummvm.setPause(true); } @Override @@ -201,17 +201,17 @@ public class ScummVMActivity extends Activity { super.onDestroy(); - if (scummvm != null) { - scummvm.pushEvent(new Event(Event.EVENT_QUIT)); + if (_scummvm != null) { + _scummvm.pushEvent(new Event(Event.EVENT_QUIT)); try { // 1s timeout - scummvm_thread.join(1000); + _scummvm_thread.join(1000); } catch (InterruptedException e) { Log.i(ScummVM.LOG_TAG, "Error while joining ScummVM thread", e); } - scummvm = null; + _scummvm = null; } } @@ -265,7 +265,7 @@ public class ScummVMActivity extends Activity { if (kevent.getAction() == KeyEvent.ACTION_UP) { if (!timeout_fired) - scummvm.pushEvent(new Event(Event.EVENT_MAINMENU)); + _scummvm.pushEvent(new Event(Event.EVENT_MAINMENU)); return true; } @@ -332,7 +332,7 @@ public class ScummVMActivity extends Activity { break; } - scummvm.pushEvent(e); + _scummvm.pushEvent(e); return true; } @@ -404,13 +404,13 @@ public class ScummVMActivity extends Activity { if (kevent.getAction() == KeyEvent.ACTION_MULTIPLE) { for (int i = 0; i <= kevent.getRepeatCount(); i++) { e.type = Event.EVENT_KEYDOWN; - scummvm.pushEvent(e); + _scummvm.pushEvent(e); e.type = Event.EVENT_KEYUP; - scummvm.pushEvent(e); + _scummvm.pushEvent(e); } } else { - scummvm.pushEvent(e); + _scummvm.pushEvent(e); } return true; @@ -448,7 +448,7 @@ public class ScummVMActivity extends Activity { (int)(event.getY() * event.getYPrecision()) * TRACKBALL_SCALE; e.mouse_relative = true; - scummvm.pushEvent(e); + _scummvm.pushEvent(e); return true; } @@ -465,7 +465,7 @@ public class ScummVMActivity extends Activity { e.mouse_y = (int)event.getY(); e.mouse_relative = false; - scummvm.pushEvent(e); + _scummvm.pushEvent(e); return true; } diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java index 80735e2c2a..f9eec72eac 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java @@ -8,14 +8,14 @@ public class ScummVMApplication extends Application { public final static String ACTION_PLUGIN_QUERY = "org.inodes.gus.scummvm.action.PLUGIN_QUERY"; public final static String EXTRA_UNPACK_LIBS = "org.inodes.gus.scummvm.extra.UNPACK_LIBS"; - private static File cache_dir; + private static File _cache_dir; @Override public void onCreate() { super.onCreate(); // This is still on /data :( - cache_dir = getCacheDir(); + _cache_dir = getCacheDir(); // This is mounted noexec :( //cache_dir = new File(Environment.getExternalStorageDirectory(), // "/.ScummVM.tmp"); @@ -25,7 +25,7 @@ public class ScummVMApplication extends Application { } public static File getLastCacheDir() { - return cache_dir; + return _cache_dir; } } -- cgit v1.2.3 From 7157454e9b30db91462cb684dd20a61204a7fa43 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 3 Mar 2011 19:11:42 +0100 Subject: ANDROID: Implement surface resizes Split surface code into helper functions to avoid code duplication, and distinguish between screen resizes and surface recreation. The former happens when toggling the softkeyb, where we just have to reset the viewport. Fixes garbled textures in those cases. --- backends/platform/android/android.cpp | 55 +++++++++++++++--------------- backends/platform/android/android.h | 5 ++- backends/platform/android/gfx.cpp | 63 ++++++++++++++++++++++++++++------- 3 files changed, 81 insertions(+), 42 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 35a6421ede..239ecd4138 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -323,7 +323,8 @@ void OSystem_Android::initBackend() { _audio_thread_exit = false; pthread_create(&_audio_thread, 0, audioThreadFunc, this); - setupSurface(); + initSurface(); + initViewport(); _game_texture = new GLESPaletteTexture(); _overlay_texture = new GLES4444Texture(); @@ -404,42 +405,38 @@ bool OSystem_Android::pollEvent(Common::Event &event) { if (pthread_self() == _main_thread) { if (_screen_changeid != JNI::surface_changeid) { if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { - LOGD("initializing surface"); + if (_egl_surface_width > 0 && _egl_surface_height > 0) { + // surface still alive but changed + _screen_changeid = JNI::surface_changeid; + _egl_surface_width = JNI::egl_surface_width; + _egl_surface_height = JNI::egl_surface_height; - _game_texture->release(); - _overlay_texture->release(); - _mouse_texture->release(); + initViewport(); + // double buffered, flip twice + _force_redraw = true; + updateScreen(); + _force_redraw = true; - JNI::deinitSurface(); - setupSurface(); + event.type = Common::EVENT_SCREEN_CHANGED; - _game_texture->reinit(); - _overlay_texture->reinit(); - _mouse_texture->reinit(); + return true; + } else { + // new surface + initSurface(); + _force_redraw = true; - event.type = Common::EVENT_SCREEN_CHANGED; + event.type = Common::EVENT_SCREEN_CHANGED; - return true; + return true; + } + } else { + // surface lost + deinitSurface(); } - - LOGD("deinitialiting surface"); - - _game_texture->release(); - _overlay_texture->release(); - _mouse_texture->release(); - - _screen_changeid = JNI::surface_changeid; - JNI::deinitSurface(); } if (JNI::pause) { - // release some resources - _game_texture->release(); - _overlay_texture->release(); - _mouse_texture->release(); - - LOGD("deinitialiting surface"); - JNI::deinitSurface(); + deinitSurface(); LOGD("main thread going to sleep"); sem_wait(&JNI::pause_sem); @@ -596,7 +593,7 @@ void OSystem_Android::quit() { delete _overlay_texture; delete _mouse_texture; - JNI::deinitSurface(); + deinitSurface(); } void OSystem_Android::setWindowCaption(const char *caption) { diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 5db10fb180..bf72f98b01 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -140,7 +140,10 @@ private: FilesystemFactory *_fsFactory; timeval _startTime; - void setupSurface(); + void initSurface(); + void deinitSurface(); + void initViewport(); + void setupKeymapper(); void _setCursorPalette(const byte *colors, uint start, uint num); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index e2cc854a1d..31e8c4be18 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -62,20 +62,60 @@ int OSystem_Android::getGraphicsMode() const { return 1; } -void OSystem_Android::setupSurface() { - ENTER(); +void OSystem_Android::initSurface() { + LOGD("initializing surface"); - _screen_changeid = JNI::surface_changeid; - JNI::initSurface(); + assert(!JNI::haveSurface()); + _screen_changeid = JNI::surface_changeid; _egl_surface_width = JNI::egl_surface_width; _egl_surface_height = JNI::egl_surface_height; assert(_egl_surface_width > 0 && _egl_surface_height > 0); - // EGL set up with a new surface. Initialise OpenGLES context. + JNI::initSurface(); + + // Initialise OpenGLES context. GLESTexture::initGLExtensions(); + if (_game_texture) + _game_texture->reinit(); + + if (_overlay_texture) + _overlay_texture->reinit(); + + if (_mouse_texture) + _mouse_texture->reinit(); +} + +void OSystem_Android::deinitSurface() { + if (!JNI::haveSurface()) + return; + + LOGD("deinitializing surface"); + + _screen_changeid = JNI::surface_changeid; + _egl_surface_width = 0; + _egl_surface_height = 0; + + // release texture resources + if (_game_texture) + _game_texture->release(); + + if (_overlay_texture) + _overlay_texture->release(); + + if (_mouse_texture) + _mouse_texture->release(); + + JNI::deinitSurface(); +} + +void OSystem_Android::initViewport() { + LOGD("initializing viewport"); + + assert(JNI::haveSurface()); + // Turn off anything that looks like 3D ;) GLCALL(glDisable(GL_CULL_FACE)); GLCALL(glDisable(GL_DEPTH_TEST)); @@ -210,8 +250,8 @@ void OSystem_Android::updateScreen() { } if (_focus_rect.isEmpty()) { - _game_texture->drawTexture(0, 0, - _egl_surface_width, _egl_surface_height); + _game_texture->drawTexture(0, 0, _egl_surface_width, + _egl_surface_height); } else { GLCALL(glPushMatrix()); GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()), @@ -223,8 +263,8 @@ void OSystem_Android::updateScreen() { xdiv(_game_texture->height(), _egl_surface_height), 1 << 16)); - _game_texture->drawTexture(0, 0, - _egl_surface_width, _egl_surface_height); + _game_texture->drawTexture(0, 0, _egl_surface_width, + _egl_surface_height); GLCALL(glPopMatrix()); } @@ -234,9 +274,8 @@ void OSystem_Android::updateScreen() { // 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)); + GLCALL(_overlay_texture->drawTexture(0, 0, _egl_surface_width, + _egl_surface_height)); } if (_show_mouse) { -- cgit v1.2.3 From ce9796baa3185417af53969e1258350648c2fc5a Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 3 Mar 2011 20:41:04 +0100 Subject: ANDROID: Don't wipe paletted textures on reinit The content of a paletted texture is in _surface.pixels. When recreating the surface, don't wipe its data unnecessarily. This fixes gfx garbage on CLUT8 games/cursors when leaving and going back to ScummVM --- backends/platform/android/texture.cpp | 40 ++++++++++++++++++++++------------- backends/platform/android/texture.h | 1 + 2 files changed, 26 insertions(+), 15 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index cb12d264b8..fb9f3bb913 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -109,14 +109,34 @@ void GLESTexture::release() { void GLESTexture::reinit() { GLCALL(glGenTextures(1, &_texture_name)); - // bypass allocBuffer() shortcut to reinit the texture properly - _texture_width = 0; - _texture_height = 0; + if (paletteSize()) { + // paletted textures are in a local buffer, don't wipe it + initSize(); + } else { + // bypass allocBuffer() shortcut to reinit the texture properly + _texture_width = 0; + _texture_height = 0; + + allocBuffer(_surface.w, _surface.h); + } - allocBuffer(_surface.w, _surface.h); setDirty(); } +void GLESTexture::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, GL_NEAREST)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + 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 GLESTexture::allocBuffer(GLuint w, GLuint h) { int bpp = bytesPerPixel(); _surface.w = w; @@ -137,17 +157,7 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _surface.pitch = _texture_width * bpp; - // 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, GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - 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)); + initSize(); } void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index f1d5cad6e9..cc1f4e3dae 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -44,6 +44,7 @@ public: void release(); void reinit(); + void initSize(); virtual void allocBuffer(GLuint width, GLuint height); -- cgit v1.2.3 From 1b0d4724f4526e1fccec3d457be72eb911908a90 Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 4 Mar 2011 21:22:16 +0100 Subject: ANDROID: Fix slightly off while loop CursorMan allows to push cursors with a width/height of zero. If such a cursor is restored, we don't need to call glTexSubImage2D() 0xffffffff times... This fixes delays of multiple minutes when closing GMM on groovie and sword. Also, I want that last hour of my life back. --- backends/platform/android/gfx.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 31e8c4be18..e0994b1d60 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -485,6 +485,9 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, palette = _mouse_texture->palette(); palette[keycolor * 4 + 3] = 0x00; + if (w == 0 || h == 0) + return; + _mouse_texture->updateBuffer(0, 0, w, h, buf, w); _mouse_hotspot = Common::Point(hotspotX, hotspotY); -- cgit v1.2.3 From f639466ab2417cb8b6052b362b7d624ea739fc8b Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 4 Mar 2011 21:30:53 +0100 Subject: ANDROID: Cleanup --- backends/platform/android/gfx.cpp | 4 ++-- backends/platform/android/texture.cpp | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index e0994b1d60..6c2208fd6f 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -411,7 +411,7 @@ void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { const Graphics::Surface *surface = _overlay_texture->surface_const(); assert(surface->bytesPerPixel == sizeof(buf[0])); - int h = surface->h; + uint h = surface->h; do { memset(buf, 0, surface->w * sizeof(buf[0])); @@ -475,7 +475,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, // Update palette alpha based on keycolor byte *palette = _mouse_texture->palette(); - int i = 256; + uint i = 256; do { palette[3] = 0xff; diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index fb9f3bb913..7d87c144c9 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -175,9 +175,6 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, } else { // GLES removed the ability to specify pitch, so we // have to do this ourselves. - if (h == 0) - return; - #if TEXSUBIMAGE_IS_EXPENSIVE byte *tmp = new byte[w * h * bytesPerPixel()]; assert(tmp); -- cgit v1.2.3 From a913d360f27f300633a8da5997686343e95e56a3 Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 4 Mar 2011 21:41:55 +0100 Subject: ANDROID: Clear game texture on initSize() Gets rid of leftovers --- backends/platform/android/gfx.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 6c2208fd6f..c71ee178ee 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -152,6 +152,7 @@ void OSystem_Android::initSize(uint width, uint height, GLTHREADCHECK; _game_texture->allocBuffer(width, height); + _game_texture->fillBuffer(0); int overlay_width = _egl_surface_width; int overlay_height = _egl_surface_height; -- cgit v1.2.3 From 68378150beb96159db7d959d9625107b721eef57 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 10:02:56 +0100 Subject: ANDROID: Remove some vtable overhead on textures --- backends/platform/android/android.cpp | 4 +- backends/platform/android/android.h | 4 +- backends/platform/android/texture.cpp | 90 ++++++++++++++++++++++----------- backends/platform/android/texture.h | 95 +++++++++++------------------------ 4 files changed, 95 insertions(+), 98 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 239ecd4138..43b618d37b 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -326,9 +326,9 @@ void OSystem_Android::initBackend() { initSurface(); initViewport(); - _game_texture = new GLESPaletteTexture(); + _game_texture = new GLESPalette888Texture(); _overlay_texture = new GLES4444Texture(); - _mouse_texture = new GLESPaletteATexture(); + _mouse_texture = new GLESPalette8888Texture(); // renice this thread to boost the audio thread if (setpriority(PRIO_PROCESS, 0, 19) < 0) diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index bf72f98b01..3ccc84bc7e 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -103,7 +103,7 @@ private: bool _force_redraw; // Game layer - GLESPaletteTexture *_game_texture; + GLESPalette888Texture *_game_texture; int _shake_offset; Common::Rect _focus_rect; @@ -112,7 +112,7 @@ private: bool _show_overlay; // Mouse layer - GLESPaletteATexture *_mouse_texture; + GLESPalette8888Texture *_mouse_texture; Common::Point _mouse_hotspot; int _mouse_targetscale; bool _show_mouse; diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 7d87c144c9..f715f7bc66 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -82,7 +82,12 @@ void GLESTexture::initGLExtensions() { } } -GLESTexture::GLESTexture() : +GLESTexture::GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, + size_t paletteSize) : + _bytesPerPixel(bytesPerPixel), + _glFormat(glFormat), + _glType(glType), + _paletteSize(paletteSize), _texture_width(0), _texture_height(0), _all_dirty(true) @@ -92,7 +97,7 @@ GLESTexture::GLESTexture() : // This all gets reset later in allocBuffer: _surface.w = 0; _surface.h = 0; - _surface.pitch = _texture_width; + _surface.pitch = 0; _surface.pixels = 0; _surface.bytesPerPixel = 0; } @@ -109,7 +114,7 @@ void GLESTexture::release() { void GLESTexture::reinit() { GLCALL(glGenTextures(1, &_texture_name)); - if (paletteSize()) { + if (_paletteSize) { // paletted textures are in a local buffer, don't wipe it initSize(); } else { @@ -132,16 +137,15 @@ void GLESTexture::initSize() { GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 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(), + GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glFormat, _texture_width, _texture_height, - 0, glFormat(), glType(), 0)); + 0, _glFormat, _glType, 0)); } void GLESTexture::allocBuffer(GLuint w, GLuint h) { - int bpp = bytesPerPixel(); _surface.w = w; _surface.h = h; - _surface.bytesPerPixel = bpp; + _surface.bytesPerPixel = _bytesPerPixel; // Already allocated a sufficiently large buffer? if (w <= _texture_width && h <= _texture_height) @@ -155,7 +159,7 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _texture_height = nextHigher2(_surface.h); } - _surface.pitch = _texture_width * bpp; + _surface.pitch = _texture_width * _bytesPerPixel; initSize(); } @@ -169,14 +173,14 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, setDirtyRect(Common::Rect(x, y, x + w, y + h)); - if (static_cast(w) * bytesPerPixel() == pitch) { + if (static_cast(w) * _bytesPerPixel == pitch) { GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - glFormat(), glType(), buf)); + _glFormat, _glType, buf)); } else { // GLES removed the ability to specify pitch, so we // have to do this ourselves. #if TEXSUBIMAGE_IS_EXPENSIVE - byte *tmp = new byte[w * h * bytesPerPixel()]; + byte *tmp = new byte[w * h * _bytesPerPixel]; assert(tmp); const byte *src = static_cast(buf); @@ -184,13 +188,13 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, GLuint count = h; do { - memcpy(dst, src, w * bytesPerPixel()); - dst += w * bytesPerPixel(); + memcpy(dst, src, w * _bytesPerPixel); + dst += w * _bytesPerPixel; src += pitch; } while (--count); GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - glFormat(), glType(), tmp)); + _glFormat, _glType, tmp)); delete[] tmp; #else @@ -199,7 +203,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const byte *src = static_cast(buf); do { GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, - w, 1, glFormat(), glType(), src)); + w, 1, _glFormat, _glType, src)); ++y; src += pitch; } while (--h); @@ -208,7 +212,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, } void GLESTexture::fillBuffer(byte x) { - uint rowbytes = _surface.w * bytesPerPixel(); + uint rowbytes = _surface.w * _bytesPerPixel; byte *tmp = new byte[_surface.h * rowbytes]; assert(tmp); @@ -225,7 +229,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { #ifdef GL_OES_draw_texture // Great extension, but only works under specific conditions. // Still a work-in-progress - disabled for now. - if (false && draw_tex_supported && paletteSize() == 0) { + if (false && draw_tex_supported && _paletteSize == 0) { //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; @@ -266,8 +270,23 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { _dirty_rect = Common::Rect(); } -GLESPaletteTexture::GLESPaletteTexture() : - GLESTexture(), +GLES4444Texture::GLES4444Texture() : + GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0) { +} + +GLES4444Texture::~GLES4444Texture() { +} + +GLES565Texture::GLES565Texture() : + GLESTexture(2, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0) { +} + +GLES565Texture::~GLES565Texture() { +} + +GLESPaletteTexture::GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, + GLenum glType, size_t paletteSize) : + GLESTexture(bytesPerPixel, glFormat, glType, paletteSize), _texture(0) { } @@ -277,10 +296,9 @@ GLESPaletteTexture::~GLESPaletteTexture() { } void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { - int bpp = bytesPerPixel(); _surface.w = w; _surface.h = h; - _surface.bytesPerPixel = bpp; + _surface.bytesPerPixel = _bytesPerPixel; // Already allocated a sufficiently large buffer? if (w <= _texture_width && h <= _texture_height) @@ -293,20 +311,20 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { _texture_width = nextHigher2(_surface.w); _texture_height = nextHigher2(_surface.h); } - _surface.pitch = _texture_width * bpp; + _surface.pitch = _texture_width * _bytesPerPixel; // Texture gets uploaded later (from drawTexture()) - byte *new_buffer = new byte[paletteSize() + - _texture_width * _texture_height * bytesPerPixel()]; + byte *new_buffer = new byte[_paletteSize + + _texture_width * _texture_height * _bytesPerPixel]; if (_texture) { // preserve palette - memcpy(new_buffer, _texture, paletteSize()); + memcpy(new_buffer, _texture, _paletteSize); delete[] _texture; } _texture = new_buffer; - _surface.pixels = _texture + paletteSize(); + _surface.pixels = _texture + _paletteSize; } void GLESPaletteTexture::fillBuffer(byte x) { @@ -324,7 +342,7 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, byte *dst = static_cast(_surface.getBasePtr(x, y)); do { - memcpy(dst, src, w * bytesPerPixel()); + memcpy(dst, src, w * _bytesPerPixel); dst += _surface.pitch; src += pitch; } while (--h); @@ -332,9 +350,9 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, void GLESPaletteTexture::uploadTexture() const { const size_t texture_size = - paletteSize() + _texture_width * _texture_height * bytesPerPixel(); + _paletteSize + _texture_width * _texture_height * _bytesPerPixel; - GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, glType(), + GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType, _texture_width, _texture_height, 0, texture_size, _texture)); } @@ -358,5 +376,19 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLESTexture::drawTexture(x, y, w, h); } +GLESPalette888Texture::GLESPalette888Texture() : + GLESPaletteTexture(1, GL_RGB, GL_PALETTE8_RGB8_OES, 256 * 3) { +} + +GLESPalette888Texture::~GLESPalette888Texture() { +} + +GLESPalette8888Texture::GLESPalette8888Texture() : + GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGBA8_OES, 256 * 4) { +} + +GLESPalette8888Texture::~GLESPalette8888Texture() { +} + #endif diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index cc1f4e3dae..f1bc46e997 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -39,9 +39,12 @@ class GLESTexture { public: static void initGLExtensions(); - GLESTexture(); +protected: + GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, + size_t paletteSize); virtual ~GLESTexture(); +public: void release(); void reinit(); void initSize(); @@ -80,14 +83,6 @@ public: } protected: - virtual byte bytesPerPixel() const = 0; - virtual GLenum glFormat() const = 0; - virtual GLenum glType() const = 0; - - virtual size_t paletteSize() const { - return 0; - } - inline void setDirty() { _all_dirty = true; _dirty_rect = Common::Rect(); @@ -102,6 +97,11 @@ protected: } } + byte _bytesPerPixel; + GLenum _glFormat; + GLenum _glType; + size_t _paletteSize; + GLuint _texture_name; Graphics::Surface _surface; GLuint _texture_width; @@ -114,42 +114,25 @@ protected: // RGBA4444 texture class GLES4444Texture : public GLESTexture { -protected: - virtual byte bytesPerPixel() const { - return 2; - } - - virtual GLenum glFormat() const { - return GL_RGBA; - } - - virtual GLenum glType() const { - return GL_UNSIGNED_SHORT_4_4_4_4; - } +public: + GLES4444Texture(); + virtual ~GLES4444Texture(); }; // RGB565 texture class GLES565Texture : public GLESTexture { -protected: - virtual byte bytesPerPixel() const { - return 2; - } - - virtual GLenum glFormat() const { - return GL_RGB; - } - - virtual GLenum glType() const { - return GL_UNSIGNED_SHORT_5_6_5; - } +public: + GLES565Texture(); + virtual ~GLES565Texture(); }; -// RGB888 256-entry paletted texture class GLESPaletteTexture : public GLESTexture { -public: - GLESPaletteTexture(); +protected: + GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, + size_t paletteSize); virtual ~GLESPaletteTexture(); +public: virtual void allocBuffer(GLuint width, GLuint height); virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch); @@ -171,41 +154,23 @@ public: }; protected: - virtual byte bytesPerPixel() const { - return 1; - } - - virtual GLenum glFormat() const { - return GL_RGB; - } - - virtual GLenum glType() const { - return GL_PALETTE8_RGB8_OES; - } - - virtual size_t paletteSize() const { - return 256 * 3; - } - void uploadTexture() const; byte *_texture; }; -// RGBA8888 256-entry paletted texture -class GLESPaletteATexture : public GLESPaletteTexture { -protected: - virtual GLenum glFormat() const { - return GL_RGBA; - } - - virtual GLenum glType() const { - return GL_PALETTE8_RGBA8_OES; - } +// RGB888 256-entry paletted texture +class GLESPalette888Texture : public GLESPaletteTexture { +public: + GLESPalette888Texture(); + virtual ~GLESPalette888Texture(); +}; - virtual size_t paletteSize() const { - return 256 * 4; - } +// RGBA8888 256-entry paletted texture +class GLESPalette8888Texture : public GLESPaletteTexture { +public: + GLESPalette8888Texture(); + virtual ~GLESPalette8888Texture(); }; #endif -- cgit v1.2.3 From 4ee0a9f43a3ccb70872b059a753485349529166d Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 10:05:35 +0100 Subject: ANDROID: Merge updateTexture() --- backends/platform/android/texture.cpp | 18 ++++++++---------- backends/platform/android/texture.h | 10 ++++------ 2 files changed, 12 insertions(+), 16 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index f715f7bc66..6e31bc0c59 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -348,15 +348,6 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, } while (--h); } -void GLESPaletteTexture::uploadTexture() const { - const size_t texture_size = - _paletteSize + _texture_width * _texture_height * _bytesPerPixel; - - GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType, - _texture_width, _texture_height, - 0, texture_size, _texture)); -} - void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { if (_all_dirty) { @@ -369,7 +360,14 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GL_CLAMP_TO_EDGE)); GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - uploadTexture(); + + const size_t texture_size = + _paletteSize + _texture_width * _texture_height * _bytesPerPixel; + + GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType, + _texture_width, _texture_height, + 0, texture_size, _texture)); + _all_dirty = false; } diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index f1bc46e997..38a6228076 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -57,6 +57,10 @@ public: virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); + inline void drawTexture() { + drawTexture(0, 0, _surface.w, _surface.h); + } + inline GLuint width() const { return _surface.w; } @@ -78,10 +82,6 @@ public: return _all_dirty || !_dirty_rect.isEmpty(); } - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - protected: inline void setDirty() { _all_dirty = true; @@ -154,8 +154,6 @@ public: }; protected: - void uploadTexture() const; - byte *_texture; }; -- cgit v1.2.3 From 83b00526d0da2265eef8d59767cafd16190ec092 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 10:10:50 +0100 Subject: ANDROID: Reduce mem usage of fillBuffer() --- backends/platform/android/texture.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 6e31bc0c59..05c551803b 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -214,13 +214,21 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, void GLESTexture::fillBuffer(byte x) { uint rowbytes = _surface.w * _bytesPerPixel; - byte *tmp = new byte[_surface.h * rowbytes]; + byte *tmp = new byte[rowbytes]; assert(tmp); - memset(tmp, x, _surface.h * rowbytes); - updateBuffer(0, 0, _surface.w, _surface.h, tmp, rowbytes); + memset(tmp, x, rowbytes); + + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + + for (GLuint y = 0; y < _surface.h; ++y) + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, _surface.w, 1, + _glFormat, _glType, tmp)); delete[] tmp; + + setDirty(); } void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { @@ -311,12 +319,14 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { _texture_width = nextHigher2(_surface.w); _texture_height = nextHigher2(_surface.h); } + _surface.pitch = _texture_width * _bytesPerPixel; // Texture gets uploaded later (from drawTexture()) byte *new_buffer = new byte[_paletteSize + _texture_width * _texture_height * _bytesPerPixel]; + if (_texture) { // preserve palette memcpy(new_buffer, _texture, _paletteSize); @@ -367,8 +377,6 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType, _texture_width, _texture_height, 0, texture_size, _texture)); - - _all_dirty = false; } GLESTexture::drawTexture(x, y, w, h); -- cgit v1.2.3 From 94db3403a3fbe228aa25cdde310e2a8daa5c33eb Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 18:21:35 +0100 Subject: ANDROID: Add initial 16bit gfx support Supported pixel formats: 565, 5551, 4444 Missing: 555 (doesn't exist on GLES) --- backends/platform/android/android.cpp | 8 +- backends/platform/android/android.h | 19 +++- backends/platform/android/gfx.cpp | 193 +++++++++++++++++++++++++++++----- backends/platform/android/texture.cpp | 17 ++- backends/platform/android/texture.h | 34 +++++- 5 files changed, 234 insertions(+), 37 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 43b618d37b..0cfe7c9a22 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -110,6 +110,8 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _game_texture(0), _overlay_texture(0), _mouse_texture(0), + _mouse_texture_palette(0), + _mouse_texture_rgb(0), _use_mouse_palette(false), _show_mouse(false), _show_overlay(false), @@ -328,7 +330,8 @@ void OSystem_Android::initBackend() { _game_texture = new GLESPalette888Texture(); _overlay_texture = new GLES4444Texture(); - _mouse_texture = new GLESPalette8888Texture(); + _mouse_texture_palette = new GLESPalette8888Texture(); + _mouse_texture = _mouse_texture_palette; // renice this thread to boost the audio thread if (setpriority(PRIO_PROCESS, 0, 19) < 0) @@ -591,7 +594,8 @@ void OSystem_Android::quit() { delete _game_texture; delete _overlay_texture; - delete _mouse_texture; + delete _mouse_texture_palette; + delete _mouse_texture_rgb; deinitSurface(); } diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 3ccc84bc7e..2c0641f789 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -103,7 +103,7 @@ private: bool _force_redraw; // Game layer - GLESPalette888Texture *_game_texture; + GLESTexture *_game_texture; int _shake_offset; Common::Rect _focus_rect; @@ -112,7 +112,9 @@ private: bool _show_overlay; // Mouse layer - GLESPalette8888Texture *_mouse_texture; + GLESTexture *_mouse_texture; + GLESPaletteTexture *_mouse_texture_palette; + GLESTexture *_mouse_texture_rgb; Common::Point _mouse_hotspot; int _mouse_targetscale; bool _show_mouse; @@ -144,6 +146,12 @@ private: void deinitSurface(); void initViewport(); +#ifdef USE_RGB_COLOR + Common::String getPixelFormatName(const Graphics::PixelFormat &format) const; + void initTexture(GLESTexture **texture, uint width, uint height, + const Graphics::PixelFormat *format, bool alphaPalette); +#endif + void setupKeymapper(); void _setCursorPalette(const byte *colors, uint start, uint num); @@ -158,11 +166,18 @@ public: 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; + +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const; + virtual Common::List getSupportedFormats() const; +#endif + virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); virtual int getScreenChangeID() const; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index c71ee178ee..1b7679d0e5 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -62,6 +62,92 @@ int OSystem_Android::getGraphicsMode() const { return 1; } +#ifdef USE_RGB_COLOR +Graphics::PixelFormat OSystem_Android::getScreenFormat() const { + return _game_texture->getPixelFormat(); +} + +Common::List OSystem_Android::getSupportedFormats() const { + Common::List res; + res.push_back(GLES565Texture::getPixelFormat()); + res.push_back(GLES5551Texture::getPixelFormat()); + res.push_back(GLES4444Texture::getPixelFormat()); + res.push_back(Graphics::PixelFormat::createFormatCLUT8()); + + return res; +} + +Common::String OSystem_Android::getPixelFormatName(const Graphics::PixelFormat &format) const { + if (format.bytesPerPixel == 1) + return "CLUT8"; + + if (format.aLoss == 8) + return Common::String::format("RGB%u%u%u", + 8 - format.rLoss, + 8 - format.gLoss, + 8 - format.bLoss); + + return Common::String::format("RGBA%u%u%u%u", + 8 - format.rLoss, + 8 - format.gLoss, + 8 - format.bLoss, + 8 - format.aLoss); +} + +void OSystem_Android::initTexture(GLESTexture **texture, + uint width, uint height, + const Graphics::PixelFormat *format, + bool alphaPalette) { + 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", + getPixelFormatName((*texture)->getPixelFormat()).c_str()); + + delete *texture; + + if (format_new == GLES565Texture::getPixelFormat()) + *texture = new GLES565Texture(); + else if (format_new == GLES5551Texture::getPixelFormat()) + *texture = new GLES5551Texture(); + else if (format_new == GLES4444Texture::getPixelFormat()) + *texture = new GLES4444Texture(); + else { + // TODO what now? + if (format_new != format_clut8) + LOGE("unsupported pixel format: %s", + getPixelFormatName(format_new).c_str()); + + if (alphaPalette) + *texture = new GLESPalette8888Texture; + else + *texture = new GLESPalette888Texture; + } + + LOGD("new pixel format: %s", + getPixelFormatName((*texture)->getPixelFormat()).c_str()); + } + + (*texture)->allocBuffer(width, height); + (*texture)->fillBuffer(0); +} +#endif + void OSystem_Android::initSurface() { LOGD("initializing surface"); @@ -151,9 +237,6 @@ void OSystem_Android::initSize(uint width, uint height, GLTHREADCHECK; - _game_texture->allocBuffer(width, height); - _game_texture->fillBuffer(0); - int overlay_width = _egl_surface_width; int overlay_height = _egl_surface_height; @@ -172,11 +255,17 @@ void OSystem_Android::initSize(uint width, uint height, _overlay_texture->allocBuffer(overlay_width, overlay_height); +#ifdef USE_RGB_COLOR + initTexture(&_game_texture, width, height, format, false); +#else + _game_texture->allocBuffer(width, height); + _game_texture->fillBuffer(0); +#endif // 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); + _mouse_texture_palette->allocBuffer(20, 20); } int OSystem_Android::getScreenChangeID() const { @@ -194,20 +283,30 @@ int16 OSystem_Android::getWidth() { void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { ENTER("%p, %u, %u", colors, start, num); +#ifdef USE_RGB_COLOR + assert(_game_texture->getPixelFormat().bytesPerPixel == 1); +#endif + GLTHREADCHECK; + memcpy(((GLESPaletteTexture *)_game_texture)->palette() + start * 3, + colors, num * 3); + 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); +#ifdef USE_RGB_COLOR + assert(_game_texture->getPixelFormat().bytesPerPixel == 1); +#endif + GLTHREADCHECK; - memcpy(colors, _game_texture->palette_const() + start * 3, num * 3); + memcpy(colors, ((GLESPaletteTexture *)_game_texture)->palette() + start * 3, + num * 3); } void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, @@ -325,6 +424,7 @@ Graphics::Surface *OSystem_Android::lockScreen() { GLTHREADCHECK; + // TODO this doesn't return any pixel data for non CLUT8 Graphics::Surface *surface = _game_texture->surface(); assert(surface->pixels); @@ -353,6 +453,7 @@ void OSystem_Android::fillScreen(uint32 col) { GLTHREADCHECK; + // TODO FIXME rgb colors assert(col < 256); _game_texture->fillBuffer(col); } @@ -472,19 +573,39 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, assert(keycolor < 256); - _mouse_texture->allocBuffer(w, h); +#ifdef USE_RGB_COLOR + if (format && format->bytesPerPixel > 1) { + if (_mouse_texture != _mouse_texture_rgb) + LOGD("switching to rgb mouse cursor"); - // Update palette alpha based on keycolor - byte *palette = _mouse_texture->palette(); - uint i = 256; + initTexture(&_mouse_texture_rgb, w, h, format, true); - do { - palette[3] = 0xff; - palette += 4; - } while (--i); + _mouse_texture = _mouse_texture_rgb; + } else { + if (_mouse_texture != _mouse_texture_palette) + LOGD("switching to paletted mouse cursor"); + + initTexture((GLESTexture **)&_mouse_texture_palette, w, h, format, + true); + + _mouse_texture = _mouse_texture_palette; + + delete _mouse_texture_rgb; + _mouse_texture_rgb = 0; + } +#else + _mouse_texture_palette->allocBuffer(w, h); +#endif + + if (_mouse_texture->getPixelFormat().bytesPerPixel == 1) { + // Update palette alpha based on keycolor + byte *palette = _mouse_texture_palette->palette(); - palette = _mouse_texture->palette(); - palette[keycolor * 4 + 3] = 0x00; + for (uint i = 0; i < 256; ++i, palette += 4) + palette[3] = 0xff; + + _mouse_texture_palette->palette()[keycolor * 4 + 3] = 0x00; + } if (w == 0 || h == 0) return; @@ -497,17 +618,14 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, 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]; + byte *palette = _mouse_texture_palette->palette() + start * 4; + for (uint i = 0; i < num; ++i, palette += 4, colors += 3) { + palette[0] = colors[0]; + palette[1] = colors[1]; + palette[2] = colors[2]; // Leave alpha untouched to preserve keycolor - - palette += 4; - colors += 3; - } while (--num); + } } void OSystem_Android::setCursorPalette(const byte *colors, @@ -516,6 +634,15 @@ void OSystem_Android::setCursorPalette(const byte *colors, GLTHREADCHECK; + if (_mouse_texture->getPixelFormat().bytesPerPixel != 1) { + LOGD("switching to paletted mouse cursor"); + + _mouse_texture = _mouse_texture_palette; + + delete _mouse_texture_rgb; + _mouse_texture_rgb = 0; + } + _setCursorPalette(colors, start, num); _use_mouse_palette = true; } @@ -523,6 +650,20 @@ void OSystem_Android::setCursorPalette(const byte *colors, void OSystem_Android::disableCursorPalette(bool disable) { ENTER("%d", disable); + // when disabling the cursor palette, and we're running a clut8 game, + // it expects the game palette to be used for the cursor + if (disable && _game_texture->getPixelFormat().bytesPerPixel == 1) { + byte *src = ((GLESPaletteTexture *)_game_texture)->palette(); + byte *dst = _mouse_texture_palette->palette(); + + for (uint i = 0; i < 256; ++i, src += 3, dst += 4) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + // Leave alpha untouched to preserve keycolor + } + } + _use_mouse_palette = !disable; } diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 05c551803b..e4c98e3ce0 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -83,11 +83,12 @@ void GLESTexture::initGLExtensions() { } GLESTexture::GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, - size_t paletteSize) : + size_t paletteSize, Graphics::PixelFormat pixelFormat) : _bytesPerPixel(bytesPerPixel), _glFormat(glFormat), _glType(glType), _paletteSize(paletteSize), + _pixelFormat(pixelFormat), _texture_width(0), _texture_height(0), _all_dirty(true) @@ -279,14 +280,21 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { } GLES4444Texture::GLES4444Texture() : - GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0) { + GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0, getPixelFormat()) { } GLES4444Texture::~GLES4444Texture() { } +GLES5551Texture::GLES5551Texture() : + GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 0, getPixelFormat()) { +} + +GLES5551Texture::~GLES5551Texture() { +} + GLES565Texture::GLES565Texture() : - GLESTexture(2, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0) { + GLESTexture(2, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0, getPixelFormat()) { } GLES565Texture::~GLES565Texture() { @@ -294,7 +302,8 @@ GLES565Texture::~GLES565Texture() { GLESPaletteTexture::GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, size_t paletteSize) : - GLESTexture(bytesPerPixel, glFormat, glType, paletteSize), + GLESTexture(bytesPerPixel, glFormat, glType, paletteSize, + Graphics::PixelFormat::createFormatCLUT8()), _texture(0) { } diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 38a6228076..14eea44914 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -31,6 +31,7 @@ #include #include "graphics/surface.h" +#include "graphics/pixelformat.h" #include "common/rect.h" #include "common/array.h" @@ -41,10 +42,11 @@ public: protected: GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, - size_t paletteSize); - virtual ~GLESTexture(); + size_t paletteSize, Graphics::PixelFormat pixelFormat); public: + virtual ~GLESTexture(); + void release(); void reinit(); void initSize(); @@ -82,6 +84,10 @@ public: return _all_dirty || !_dirty_rect.isEmpty(); } + inline Graphics::PixelFormat getPixelFormat() const { + return _pixelFormat; + } + protected: inline void setDirty() { _all_dirty = true; @@ -110,6 +116,8 @@ protected: // Covers dirty area Common::Rect _dirty_rect; + + Graphics::PixelFormat _pixelFormat; }; // RGBA4444 texture @@ -117,6 +125,21 @@ class GLES4444Texture : public GLESTexture { public: GLES4444Texture(); virtual ~GLES4444Texture(); + + static inline Graphics::PixelFormat getPixelFormat() { + 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 getPixelFormat() { + return Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0); + } }; // RGB565 texture @@ -124,15 +147,20 @@ class GLES565Texture : public GLESTexture { public: GLES565Texture(); virtual ~GLES565Texture(); + + static inline Graphics::PixelFormat getPixelFormat() { + return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + } }; class GLESPaletteTexture : public GLESTexture { protected: GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, size_t paletteSize); - virtual ~GLESPaletteTexture(); public: + virtual ~GLESPaletteTexture(); + virtual void allocBuffer(GLuint width, GLuint height); virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch); -- cgit v1.2.3 From d2dd614996452f653d8a2710b55b9b3799350688 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 18:38:00 +0100 Subject: ANDROID: Clear screen on initSize() --- backends/platform/android/gfx.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 1b7679d0e5..d6dc71fcfb 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -266,6 +266,11 @@ void OSystem_Android::initSize(uint width, uint height, // setMouseCursor however, so just take a guess at the desired // size (it's small). _mouse_texture_palette->allocBuffer(20, 20); + + // clear screen + GLCALL(glClearColorx(0, 0, 0, 1 << 16)); + GLCALL(glClear(GL_COLOR_BUFFER_BIT)); + JNI::swapBuffers(); } int OSystem_Android::getScreenChangeID() const { @@ -529,9 +534,6 @@ void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, GLTHREADCHECK; - 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])); -- cgit v1.2.3 From a2c02367f7fe76a6a76fbd872908274f679e4b4d Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 19:39:46 +0100 Subject: ANDROID: Rename function for less confusion --- backends/platform/android/android.h | 2 +- backends/platform/android/gfx.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 2c0641f789..6eb43a390e 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -153,7 +153,7 @@ private: #endif void setupKeymapper(); - void _setCursorPalette(const byte *colors, uint start, uint num); + void setCursorPaletteInternal(const byte *colors, uint start, uint num); public: OSystem_Android(int audio_sample_rate, int audio_buffer_size); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index d6dc71fcfb..12262f851b 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -298,7 +298,7 @@ void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { colors, num * 3); if (!_use_mouse_palette) - _setCursorPalette(colors, start, num); + setCursorPaletteInternal(colors, start, num); } void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { @@ -618,8 +618,8 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, _mouse_targetscale = cursorTargetScale; } -void OSystem_Android::_setCursorPalette(const byte *colors, - uint start, uint num) { +void OSystem_Android::setCursorPaletteInternal(const byte *colors, + uint start, uint num) { byte *palette = _mouse_texture_palette->palette() + start * 4; for (uint i = 0; i < num; ++i, palette += 4, colors += 3) { @@ -645,7 +645,7 @@ void OSystem_Android::setCursorPalette(const byte *colors, _mouse_texture_rgb = 0; } - _setCursorPalette(colors, start, num); + setCursorPaletteInternal(colors, start, num); _use_mouse_palette = true; } -- cgit v1.2.3 From 53ee7c551369cf00b5073f10c21b836759b8c302 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 21:22:45 +0100 Subject: ANDROID: Proper fillBuffer() for non CLUT8 colors --- backends/platform/android/gfx.cpp | 2 -- backends/platform/android/texture.cpp | 13 +++++++++---- backends/platform/android/texture.h | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 12262f851b..10ffa3a7f6 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -458,8 +458,6 @@ void OSystem_Android::fillScreen(uint32 col) { GLTHREADCHECK; - // TODO FIXME rgb colors - assert(col < 256); _game_texture->fillBuffer(col); } diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index e4c98e3ce0..7f3db0574b 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -212,13 +212,18 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, } } -void GLESTexture::fillBuffer(byte x) { +void GLESTexture::fillBuffer(uint32 color) { uint rowbytes = _surface.w * _bytesPerPixel; byte *tmp = new byte[rowbytes]; assert(tmp); - memset(tmp, x, rowbytes); + if (_bytesPerPixel == 1 || ((color & 0xff) == ((color >> 8) & 0xff))) { + memset(tmp, color & 0xff, rowbytes); + } else { + uint16 *p = (uint16 *)tmp; + Common::set_to(p, p + _surface.w, (uint16)color); + } GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); @@ -346,9 +351,9 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { _surface.pixels = _texture + _paletteSize; } -void GLESPaletteTexture::fillBuffer(byte x) { +void GLESPaletteTexture::fillBuffer(uint32 color) { assert(_surface.pixels); - memset(_surface.pixels, x, _surface.pitch * _surface.h); + memset(_surface.pixels, color & 0xff, _surface.pitch * _surface.h); setDirty(); } diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 14eea44914..e3d4463716 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -55,7 +55,7 @@ public: virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch); - virtual void fillBuffer(byte x); + virtual void fillBuffer(uint32 color); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -164,7 +164,7 @@ public: virtual void allocBuffer(GLuint width, GLuint height); virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch); - virtual void fillBuffer(byte x); + virtual void fillBuffer(uint32 color); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); -- cgit v1.2.3 From 12fb8177519c6ba760b898a1f79bf770bfd6e6ac Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 21:31:03 +0100 Subject: ANDROID: Fix 16bit cursors I hate this code --- backends/platform/android/android.h | 2 +- backends/platform/android/gfx.cpp | 48 +++++++++++++++++++++++++++++-------- backends/platform/android/texture.h | 6 ++++- 3 files changed, 44 insertions(+), 12 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 6eb43a390e..5c7154a8e4 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -114,7 +114,7 @@ private: // Mouse layer GLESTexture *_mouse_texture; GLESPaletteTexture *_mouse_texture_palette; - GLESTexture *_mouse_texture_rgb; + GLES5551Texture *_mouse_texture_rgb; Common::Point _mouse_hotspot; int _mouse_targetscale; bool _show_mouse; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 10ffa3a7f6..90b1c3ec57 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -25,6 +25,8 @@ #if defined(__ANDROID__) +#include "graphics/conversion.h" + #include "backends/platform/android/android.h" #include "backends/platform/android/jni.h" @@ -578,39 +580,65 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, if (_mouse_texture != _mouse_texture_rgb) LOGD("switching to rgb mouse cursor"); - initTexture(&_mouse_texture_rgb, w, h, format, true); - + _mouse_texture_rgb = new GLES5551Texture(); _mouse_texture = _mouse_texture_rgb; } else { if (_mouse_texture != _mouse_texture_palette) LOGD("switching to paletted mouse cursor"); - initTexture((GLESTexture **)&_mouse_texture_palette, w, h, format, - true); - _mouse_texture = _mouse_texture_palette; delete _mouse_texture_rgb; _mouse_texture_rgb = 0; } -#else - _mouse_texture_palette->allocBuffer(w, h); #endif - if (_mouse_texture->getPixelFormat().bytesPerPixel == 1) { + _mouse_texture->allocBuffer(w, h); + + if (_mouse_texture == _mouse_texture_palette) { // Update palette alpha based on keycolor byte *palette = _mouse_texture_palette->palette(); for (uint i = 0; i < 256; ++i, palette += 4) palette[3] = 0xff; - _mouse_texture_palette->palette()[keycolor * 4 + 3] = 0x00; + _mouse_texture_palette->palette()[keycolor * 4 + 3] = 0; } if (w == 0 || h == 0) return; - _mouse_texture->updateBuffer(0, 0, w, h, buf, w); + 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 16bit cursor without alpha bits... this is so silly + if (!crossBlit(tmp, buf, pitch, w * 2, w, h, + _mouse_texture->getPixelFormat(), + *format)) { + LOGE("crossblit failed"); + + delete[] tmp; + + _mouse_texture->fillBuffer(0); + + return; + } + + uint16 *s = (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 |= 1; + + _mouse_texture->updateBuffer(0, 0, w, h, tmp, pitch); + + delete[] tmp; + } _mouse_hotspot = Common::Point(hotspotX, hotspotY); _mouse_targetscale = cursorTargetScale; diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index e3d4463716..c149253dd4 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -71,6 +71,10 @@ public: return _surface.h; } + inline uint16 pitch() const { + return _surface.pitch; + } + inline const Graphics::Surface *surface_const() const { return &_surface; } @@ -84,7 +88,7 @@ public: return _all_dirty || !_dirty_rect.isEmpty(); } - inline Graphics::PixelFormat getPixelFormat() const { + inline const Graphics::PixelFormat &getPixelFormat() const { return _pixelFormat; } -- cgit v1.2.3 From 433429dcf4075df7bc892e36d8a37680ad4f41d8 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 5 Mar 2011 23:55:16 +0100 Subject: ANDROID: Fix warning --- backends/platform/android/texture.cpp | 14 +++++++------- backends/platform/android/texture.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 7f3db0574b..ee41d3aeee 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -166,15 +166,15 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { } void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, - const void *buf, int pitch) { - ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch); + const void *buf, int pitch_buf) { + ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch_buf); GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); setDirtyRect(Common::Rect(x, y, x + w, y + h)); - if (static_cast(w) * _bytesPerPixel == pitch) { + if (static_cast(w) * _bytesPerPixel == pitch_buf) { GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, _glFormat, _glType, buf)); } else { @@ -191,7 +191,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, do { memcpy(dst, src, w * _bytesPerPixel); dst += w * _bytesPerPixel; - src += pitch; + src += pitch_buf; } while (--count); GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, @@ -206,7 +206,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, 1, _glFormat, _glType, src)); ++y; - src += pitch; + src += pitch_buf; } while (--h); #endif } @@ -359,7 +359,7 @@ void GLESPaletteTexture::fillBuffer(uint32 color) { void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, - const void *buf, int pitch) { + const void *buf, int pitch_buf) { _all_dirty = true; const byte * src = static_cast(buf); @@ -368,7 +368,7 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, do { memcpy(dst, src, w * _bytesPerPixel); dst += _surface.pitch; - src += pitch; + src += pitch_buf; } while (--h); } diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index c149253dd4..f2c79d4007 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -54,7 +54,7 @@ public: virtual void allocBuffer(GLuint width, GLuint height); virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, - const void *buf, int pitch); + const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -167,7 +167,7 @@ public: virtual void allocBuffer(GLuint width, GLuint height); virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, - const void *buf, int pitch); + const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); -- cgit v1.2.3 From 42c6a785c74c200b19ceef6db5003f334c3edf29 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 6 Mar 2011 21:27:34 +0100 Subject: ANDROID: Texture cleanup --- backends/platform/android/texture.cpp | 51 ++++++++--------------------------- backends/platform/android/texture.h | 11 ++++++-- 2 files changed, 20 insertions(+), 42 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index ee41d3aeee..24e6549b1a 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -88,19 +88,15 @@ GLESTexture::GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, _glFormat(glFormat), _glType(glType), _paletteSize(paletteSize), - _pixelFormat(pixelFormat), + _texture_name(0), + _surface(), _texture_width(0), _texture_height(0), - _all_dirty(true) + _all_dirty(false), + _dirty_rect(), + _pixelFormat(pixelFormat) { GLCALL(glGenTextures(1, &_texture_name)); - - // This all gets reset later in allocBuffer: - _surface.w = 0; - _surface.h = 0; - _surface.pitch = 0; - _surface.pixels = 0; - _surface.bytesPerPixel = 0; } GLESTexture::~GLESTexture() { @@ -280,8 +276,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); } - _all_dirty = false; - _dirty_rect = Common::Rect(); + clearDirty(); } GLES4444Texture::GLES4444Texture() : @@ -318,28 +313,13 @@ GLESPaletteTexture::~GLESPaletteTexture() { } void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { - _surface.w = w; - _surface.h = h; - _surface.bytesPerPixel = _bytesPerPixel; - - // Already allocated a sufficiently large buffer? - 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); - } - - _surface.pitch = _texture_width * _bytesPerPixel; + GLESTexture::allocBuffer(w, h); // Texture gets uploaded later (from drawTexture()) byte *new_buffer = new byte[_paletteSize + _texture_width * _texture_height * _bytesPerPixel]; + assert(new_buffer); if (_texture) { // preserve palette @@ -357,10 +337,9 @@ void GLESPaletteTexture::fillBuffer(uint32 color) { setDirty(); } -void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, - GLuint w, GLuint h, +void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const void *buf, int pitch_buf) { - _all_dirty = true; + setDirtyRect(Common::Rect(x, y, x + w, y + h)); const byte * src = static_cast(buf); byte *dst = static_cast(_surface.getBasePtr(x, y)); @@ -374,16 +353,8 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { - if (_all_dirty) { + if (dirty()) { GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_NEAREST)); - 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)); const size_t texture_size = _paletteSize + _texture_width * _texture_height * _bytesPerPixel; diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index f2c79d4007..78df43aea9 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -95,7 +95,14 @@ public: protected: inline void setDirty() { _all_dirty = true; - _dirty_rect = Common::Rect(); + } + + 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) { @@ -116,9 +123,9 @@ protected: Graphics::Surface _surface; GLuint _texture_width; GLuint _texture_height; - bool _all_dirty; // Covers dirty area + bool _all_dirty; Common::Rect _dirty_rect; Graphics::PixelFormat _pixelFormat; -- cgit v1.2.3 From 1f90d232e3b4911f725fe22489aaa2cc2253426d Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 7 Mar 2011 19:52:44 +0100 Subject: ANDROID: Save the game when the process is paused The OS can kill the activity at will after onPause() or onStop() to free up memory for other application. Provide a parachute when the engine allows it. --- backends/platform/android/jni.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 73b74394c0..6bfe9c2095 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -631,7 +631,13 @@ void JNI::setPause(JNIEnv *env, jobject self, jboolean value) { if (g_engine) { LOGD("pauseEngine: %d", value); + g_engine->pauseEngine(value); + + if (value && + g_engine->hasFeature(Engine::kSupportsSavingDuringRuntime) && + g_engine->canSaveGameStateCurrently()) + g_engine->saveGameState(0, "Android parachute"); } pause = value; -- cgit v1.2.3 From e71fb5b0eb9c9c68bf328d557f09a3191e0c8b8f Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 7 Mar 2011 21:49:51 +0100 Subject: ANDROID: Move the overlay initialization There's no point in doing that in initSize() every time --- backends/platform/android/android.cpp | 2 ++ backends/platform/android/android.h | 2 ++ backends/platform/android/gfx.cpp | 18 +++++++++++------- 3 files changed, 15 insertions(+), 7 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 0cfe7c9a22..2be435c701 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -333,6 +333,8 @@ void OSystem_Android::initBackend() { _mouse_texture_palette = new GLESPalette8888Texture(); _mouse_texture = _mouse_texture_palette; + initOverlay(); + // renice this thread to boost the audio thread if (setpriority(PRIO_PROCESS, 0, 19) < 0) warning("couldn't renice the main thread"); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 5c7154a8e4..f6406c4132 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -146,6 +146,8 @@ private: void deinitSurface(); void initViewport(); + void initOverlay(); + #ifdef USE_RGB_COLOR Common::String getPixelFormatName(const Graphics::PixelFormat &format) const; void initTexture(GLESTexture **texture, uint width, uint height, diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 90b1c3ec57..6422a28f7b 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -169,8 +169,10 @@ void OSystem_Android::initSurface() { if (_game_texture) _game_texture->reinit(); - if (_overlay_texture) + if (_overlay_texture) { _overlay_texture->reinit(); + initOverlay(); + } if (_mouse_texture) _mouse_texture->reinit(); @@ -233,12 +235,7 @@ void OSystem_Android::initViewport() { clearFocusRectangle(); } -void OSystem_Android::initSize(uint width, uint height, - const Graphics::PixelFormat *format) { - ENTER("%d, %d, %p", width, height, format); - - GLTHREADCHECK; - +void OSystem_Android::initOverlay() { int overlay_width = _egl_surface_width; int overlay_height = _egl_surface_height; @@ -256,6 +253,13 @@ void OSystem_Android::initSize(uint width, uint height, LOGI("overlay size is %ux%u", overlay_width, overlay_height); _overlay_texture->allocBuffer(overlay_width, overlay_height); +} + +void OSystem_Android::initSize(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, false); -- cgit v1.2.3 From 905d5e76b463870fba69d6683c96ac93d6fda623 Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 7 Mar 2011 23:41:34 +0100 Subject: ANDROID: Move misplaced assert Leftover from the recently introduced 16bit support --- backends/platform/android/gfx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 6422a28f7b..605f4eb744 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -577,8 +577,6 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, GLTHREADCHECK; - assert(keycolor < 256); - #ifdef USE_RGB_COLOR if (format && format->bytesPerPixel > 1) { if (_mouse_texture != _mouse_texture_rgb) @@ -600,6 +598,8 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, _mouse_texture->allocBuffer(w, h); if (_mouse_texture == _mouse_texture_palette) { + assert(keycolor < 256); + // Update palette alpha based on keycolor byte *palette = _mouse_texture_palette->palette(); -- cgit v1.2.3 From 4afa2c62b979251cb4d8ff7e5a97f5385a6287fe Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 12 Mar 2011 09:13:33 +0100 Subject: ANDROID: Get rid of ugly casts --- backends/platform/android/gfx.cpp | 8 +++----- backends/platform/android/texture.h | 12 ++++++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 605f4eb744..327ef06f38 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -300,8 +300,7 @@ void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { GLTHREADCHECK; - memcpy(((GLESPaletteTexture *)_game_texture)->palette() + start * 3, - colors, num * 3); + memcpy(_game_texture->palette() + start * 3, colors, num * 3); if (!_use_mouse_palette) setCursorPaletteInternal(colors, start, num); @@ -316,8 +315,7 @@ void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { GLTHREADCHECK; - memcpy(colors, ((GLESPaletteTexture *)_game_texture)->palette() + start * 3, - num * 3); + memcpy(colors, _game_texture->palette() + start * 3, num * 3); } void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, @@ -685,7 +683,7 @@ void OSystem_Android::disableCursorPalette(bool disable) { // when disabling the cursor palette, and we're running a clut8 game, // it expects the game palette to be used for the cursor if (disable && _game_texture->getPixelFormat().bytesPerPixel == 1) { - byte *src = ((GLESPaletteTexture *)_game_texture)->palette(); + byte *src = _game_texture->palette(); byte *dst = _mouse_texture_palette->palette(); for (uint i = 0; i < 256; ++i, src += 3, dst += 4) { diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 78df43aea9..1ed16cb390 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -84,6 +84,14 @@ public: return &_surface; } + virtual const byte *palette_const() const { + return 0; + }; + + virtual byte *palette() { + return 0; + }; + inline bool dirty() const { return _all_dirty || !_dirty_rect.isEmpty(); } @@ -183,11 +191,11 @@ public: drawTexture(0, 0, _surface.w, _surface.h); } - inline const byte *palette_const() const { + virtual const byte *palette_const() const { return _texture; }; - inline byte *palette() { + virtual byte *palette() { setDirty(); return _texture; }; -- cgit v1.2.3 From 99c0d825418de549c42f26532eb444cdfa82e507 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 12 Mar 2011 09:15:27 +0100 Subject: ANDROID: Cleanup paletted textures --- backends/platform/android/gfx.cpp | 8 ++++---- backends/platform/android/texture.cpp | 16 ++++++++-------- backends/platform/android/texture.h | 8 ++++++-- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 327ef06f38..d0fc392681 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -295,7 +295,7 @@ void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { ENTER("%p, %u, %u", colors, start, num); #ifdef USE_RGB_COLOR - assert(_game_texture->getPixelFormat().bytesPerPixel == 1); + assert(_game_texture->hasPalette()); #endif GLTHREADCHECK; @@ -310,7 +310,7 @@ void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { ENTER("%p, %u, %u", colors, start, num); #ifdef USE_RGB_COLOR - assert(_game_texture->getPixelFormat().bytesPerPixel == 1); + assert(_game_texture->hasPalette()); #endif GLTHREADCHECK; @@ -664,7 +664,7 @@ void OSystem_Android::setCursorPalette(const byte *colors, GLTHREADCHECK; - if (_mouse_texture->getPixelFormat().bytesPerPixel != 1) { + if (!_mouse_texture->hasPalette()) { LOGD("switching to paletted mouse cursor"); _mouse_texture = _mouse_texture_palette; @@ -682,7 +682,7 @@ void OSystem_Android::disableCursorPalette(bool disable) { // when disabling the cursor palette, and we're running a clut8 game, // it expects the game palette to be used for the cursor - if (disable && _game_texture->getPixelFormat().bytesPerPixel == 1) { + if (disable && _game_texture->hasPalette()) { byte *src = _game_texture->palette(); byte *dst = _mouse_texture_palette->palette(); diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 24e6549b1a..eb45de7468 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -83,11 +83,10 @@ void GLESTexture::initGLExtensions() { } GLESTexture::GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, - size_t paletteSize, Graphics::PixelFormat pixelFormat) : + Graphics::PixelFormat pixelFormat) : _bytesPerPixel(bytesPerPixel), _glFormat(glFormat), _glType(glType), - _paletteSize(paletteSize), _texture_name(0), _surface(), _texture_width(0), @@ -111,7 +110,7 @@ void GLESTexture::release() { void GLESTexture::reinit() { GLCALL(glGenTextures(1, &_texture_name)); - if (_paletteSize) { + if (hasPalette()) { // paletted textures are in a local buffer, don't wipe it initSize(); } else { @@ -239,7 +238,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { #ifdef GL_OES_draw_texture // Great extension, but only works under specific conditions. // Still a work-in-progress - disabled for now. - if (false && draw_tex_supported && _paletteSize == 0) { + if (false && draw_tex_supported && !hasPalette()) { //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; @@ -280,21 +279,21 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { } GLES4444Texture::GLES4444Texture() : - GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0, getPixelFormat()) { + GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, getPixelFormat()) { } GLES4444Texture::~GLES4444Texture() { } GLES5551Texture::GLES5551Texture() : - GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 0, getPixelFormat()) { + GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, getPixelFormat()) { } GLES5551Texture::~GLES5551Texture() { } GLES565Texture::GLES565Texture() : - GLESTexture(2, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0, getPixelFormat()) { + GLESTexture(2, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, getPixelFormat()) { } GLES565Texture::~GLES565Texture() { @@ -302,8 +301,9 @@ GLES565Texture::~GLES565Texture() { GLESPaletteTexture::GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, size_t paletteSize) : - GLESTexture(bytesPerPixel, glFormat, glType, paletteSize, + GLESTexture(bytesPerPixel, glFormat, glType, Graphics::PixelFormat::createFormatCLUT8()), + _paletteSize(paletteSize), _texture(0) { } diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 1ed16cb390..91ec9ff857 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -42,7 +42,7 @@ public: protected: GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, - size_t paletteSize, Graphics::PixelFormat pixelFormat); + Graphics::PixelFormat pixelFormat); public: virtual ~GLESTexture(); @@ -92,6 +92,10 @@ public: return 0; }; + inline bool hasPalette() const { + return palette_const() != 0; + } + inline bool dirty() const { return _all_dirty || !_dirty_rect.isEmpty(); } @@ -125,7 +129,6 @@ protected: byte _bytesPerPixel; GLenum _glFormat; GLenum _glType; - size_t _paletteSize; GLuint _texture_name; Graphics::Surface _surface; @@ -202,6 +205,7 @@ public: protected: byte *_texture; + size_t _paletteSize; }; // RGB888 256-entry paletted texture -- cgit v1.2.3 From 7fe487f9cc4cb4b7ee6a121f33b9d284bfc15ed7 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 12 Mar 2011 09:17:58 +0100 Subject: ANDROID: Add more paletted texture types --- backends/platform/android/texture.cpp | 39 ++++++++++++++++++++++++++++++----- backends/platform/android/texture.h | 30 +++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 7 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index eb45de7468..603ef3aa6f 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -93,7 +93,8 @@ GLESTexture::GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, _texture_height(0), _all_dirty(false), _dirty_rect(), - _pixelFormat(pixelFormat) + _pixelFormat(pixelFormat), + _palettePixelFormat() { GLCALL(glGenTextures(1, &_texture_name)); } @@ -300,12 +301,14 @@ GLES565Texture::~GLES565Texture() { } GLESPaletteTexture::GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, - GLenum glType, size_t paletteSize) : + GLenum glType, + Graphics::PixelFormat palettePixelFormat) : GLESTexture(bytesPerPixel, glFormat, glType, Graphics::PixelFormat::createFormatCLUT8()), - _paletteSize(paletteSize), _texture(0) { + _palettePixelFormat = palettePixelFormat; + _paletteSize = _palettePixelFormat.bytesPerPixel * 256; } GLESPaletteTexture::~GLESPaletteTexture() { @@ -368,18 +371,44 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, } GLESPalette888Texture::GLESPalette888Texture() : - GLESPaletteTexture(1, GL_RGB, GL_PALETTE8_RGB8_OES, 256 * 3) { + GLESPaletteTexture(1, GL_RGB, GL_PALETTE8_RGB8_OES, + Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)) { } GLESPalette888Texture::~GLESPalette888Texture() { } GLESPalette8888Texture::GLESPalette8888Texture() : - GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGBA8_OES, 256 * 4) { + GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGBA8_OES, + Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { } GLESPalette8888Texture::~GLESPalette8888Texture() { } +GLESPalette565Texture::GLESPalette565Texture() : + GLESPaletteTexture(1, GL_RGB, GL_PALETTE8_R5_G6_B5_OES, + Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { +} + +GLESPalette565Texture::~GLESPalette565Texture() { +} + +GLESPalette4444Texture::GLESPalette4444Texture() : + GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGBA4_OES, + Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { +} + +GLESPalette4444Texture::~GLESPalette4444Texture() { +} + +GLESPalette5551Texture::GLESPalette5551Texture() : + GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGB5_A1_OES, + Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) { +} + +GLESPalette5551Texture::~GLESPalette5551Texture() { +} + #endif diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 91ec9ff857..f00a589875 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -93,7 +93,7 @@ public: }; inline bool hasPalette() const { - return palette_const() != 0; + return _palettePixelFormat.bytesPerPixel > 0; } inline bool dirty() const { @@ -104,6 +104,10 @@ public: return _pixelFormat; } + inline const Graphics::PixelFormat &getPalettePixelFormat() const { + return _palettePixelFormat; + } + protected: inline void setDirty() { _all_dirty = true; @@ -140,6 +144,7 @@ protected: Common::Rect _dirty_rect; Graphics::PixelFormat _pixelFormat; + Graphics::PixelFormat _palettePixelFormat; }; // RGBA4444 texture @@ -178,7 +183,7 @@ public: class GLESPaletteTexture : public GLESTexture { protected: GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, - size_t paletteSize); + Graphics::PixelFormat palettePixelFormat); public: virtual ~GLESPaletteTexture(); @@ -222,6 +227,27 @@ public: virtual ~GLESPalette8888Texture(); }; +// RGB565 256-entry paletted texture +class GLESPalette565Texture : public GLESPaletteTexture { +public: + GLESPalette565Texture(); + virtual ~GLESPalette565Texture(); +}; + +// RGBA4444 256-entry paletted texture +class GLESPalette4444Texture : public GLESPaletteTexture { +public: + GLESPalette4444Texture(); + virtual ~GLESPalette4444Texture(); +}; + +// RGBA5551 256-entry paletted texture +class GLESPalette5551Texture : public GLESPaletteTexture { +public: + GLESPalette5551Texture(); + virtual ~GLESPalette5551Texture(); +}; + #endif #endif -- cgit v1.2.3 From 2259f922f8c2a7b2839edf8f4ae9bbe17c1016ab Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 12 Mar 2011 09:20:21 +0100 Subject: ANDROID: Remove redundant variable --- backends/platform/android/texture.cpp | 49 +++++++++++++++++------------------ backends/platform/android/texture.h | 5 ++-- 2 files changed, 26 insertions(+), 28 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 603ef3aa6f..dbba275790 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -82,9 +82,8 @@ void GLESTexture::initGLExtensions() { } } -GLESTexture::GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, +GLESTexture::GLESTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat pixelFormat) : - _bytesPerPixel(bytesPerPixel), _glFormat(glFormat), _glType(glType), _texture_name(0), @@ -142,7 +141,7 @@ void GLESTexture::initSize() { void GLESTexture::allocBuffer(GLuint w, GLuint h) { _surface.w = w; _surface.h = h; - _surface.bytesPerPixel = _bytesPerPixel; + _surface.bytesPerPixel = _pixelFormat.bytesPerPixel; // Already allocated a sufficiently large buffer? if (w <= _texture_width && h <= _texture_height) @@ -156,7 +155,7 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _texture_height = nextHigher2(_surface.h); } - _surface.pitch = _texture_width * _bytesPerPixel; + _surface.pitch = _texture_width * _pixelFormat.bytesPerPixel; initSize(); } @@ -170,14 +169,14 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, setDirtyRect(Common::Rect(x, y, x + w, y + h)); - if (static_cast(w) * _bytesPerPixel == pitch_buf) { + if (static_cast(w) * _pixelFormat.bytesPerPixel == pitch_buf) { GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, _glFormat, _glType, buf)); } else { // GLES removed the ability to specify pitch, so we // have to do this ourselves. #if TEXSUBIMAGE_IS_EXPENSIVE - byte *tmp = new byte[w * h * _bytesPerPixel]; + byte *tmp = new byte[w * h * _pixelFormat.bytesPerPixel]; assert(tmp); const byte *src = static_cast(buf); @@ -185,8 +184,8 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, GLuint count = h; do { - memcpy(dst, src, w * _bytesPerPixel); - dst += w * _bytesPerPixel; + memcpy(dst, src, w * _pixelFormat.bytesPerPixel); + dst += w * _pixelFormat.bytesPerPixel; src += pitch_buf; } while (--count); @@ -209,12 +208,13 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, } void GLESTexture::fillBuffer(uint32 color) { - uint rowbytes = _surface.w * _bytesPerPixel; + uint rowbytes = _surface.w * _pixelFormat.bytesPerPixel; byte *tmp = new byte[rowbytes]; assert(tmp); - if (_bytesPerPixel == 1 || ((color & 0xff) == ((color >> 8) & 0xff))) { + if (_pixelFormat.bytesPerPixel == 1 || + ((color & 0xff) == ((color >> 8) & 0xff))) { memset(tmp, color & 0xff, rowbytes); } else { uint16 *p = (uint16 *)tmp; @@ -280,30 +280,29 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { } GLES4444Texture::GLES4444Texture() : - GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, getPixelFormat()) { + GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, getPixelFormat()) { } GLES4444Texture::~GLES4444Texture() { } GLES5551Texture::GLES5551Texture() : - GLESTexture(2, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, getPixelFormat()) { + GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, getPixelFormat()) { } GLES5551Texture::~GLES5551Texture() { } GLES565Texture::GLES565Texture() : - GLESTexture(2, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, getPixelFormat()) { + GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, getPixelFormat()) { } GLES565Texture::~GLES565Texture() { } -GLESPaletteTexture::GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, - GLenum glType, +GLESPaletteTexture::GLESPaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat palettePixelFormat) : - GLESTexture(bytesPerPixel, glFormat, glType, + GLESTexture(glFormat, glType, Graphics::PixelFormat::createFormatCLUT8()), _texture(0) { @@ -321,7 +320,7 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { // Texture gets uploaded later (from drawTexture()) byte *new_buffer = new byte[_paletteSize + - _texture_width * _texture_height * _bytesPerPixel]; + _texture_width * _texture_height]; assert(new_buffer); if (_texture) { @@ -348,7 +347,7 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, byte *dst = static_cast(_surface.getBasePtr(x, y)); do { - memcpy(dst, src, w * _bytesPerPixel); + memcpy(dst, src, w); dst += _surface.pitch; src += pitch_buf; } while (--h); @@ -359,8 +358,8 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, if (dirty()) { GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - const size_t texture_size = - _paletteSize + _texture_width * _texture_height * _bytesPerPixel; + const size_t texture_size = _paletteSize + + _texture_width * _texture_height; GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType, _texture_width, _texture_height, @@ -371,7 +370,7 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, } GLESPalette888Texture::GLESPalette888Texture() : - GLESPaletteTexture(1, GL_RGB, GL_PALETTE8_RGB8_OES, + GLESPaletteTexture(GL_RGB, GL_PALETTE8_RGB8_OES, Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)) { } @@ -379,7 +378,7 @@ GLESPalette888Texture::~GLESPalette888Texture() { } GLESPalette8888Texture::GLESPalette8888Texture() : - GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGBA8_OES, + GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA8_OES, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { } @@ -387,7 +386,7 @@ GLESPalette8888Texture::~GLESPalette8888Texture() { } GLESPalette565Texture::GLESPalette565Texture() : - GLESPaletteTexture(1, GL_RGB, GL_PALETTE8_R5_G6_B5_OES, + GLESPaletteTexture(GL_RGB, GL_PALETTE8_R5_G6_B5_OES, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { } @@ -395,7 +394,7 @@ GLESPalette565Texture::~GLESPalette565Texture() { } GLESPalette4444Texture::GLESPalette4444Texture() : - GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGBA4_OES, + GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA4_OES, Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { } @@ -403,7 +402,7 @@ GLESPalette4444Texture::~GLESPalette4444Texture() { } GLESPalette5551Texture::GLESPalette5551Texture() : - GLESPaletteTexture(1, GL_RGBA, GL_PALETTE8_RGB5_A1_OES, + GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGB5_A1_OES, Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) { } diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index f00a589875..02cb0c71fb 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -41,7 +41,7 @@ public: static void initGLExtensions(); protected: - GLESTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, + GLESTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat pixelFormat); public: @@ -130,7 +130,6 @@ protected: } } - byte _bytesPerPixel; GLenum _glFormat; GLenum _glType; @@ -182,7 +181,7 @@ public: class GLESPaletteTexture : public GLESTexture { protected: - GLESPaletteTexture(byte bytesPerPixel, GLenum glFormat, GLenum glType, + GLESPaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat palettePixelFormat); public: -- cgit v1.2.3 From caf21a357bef24ced14d8b67c7f3f6687a767570 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 12 Mar 2011 09:22:11 +0100 Subject: ANDROID: Cleanup --- backends/platform/android/android.h | 2 +- backends/platform/android/gfx.cpp | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index f6406c4132..ba1a47a10f 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -151,7 +151,7 @@ private: #ifdef USE_RGB_COLOR Common::String getPixelFormatName(const Graphics::PixelFormat &format) const; void initTexture(GLESTexture **texture, uint width, uint height, - const Graphics::PixelFormat *format, bool alphaPalette); + const Graphics::PixelFormat *format); #endif void setupKeymapper(); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index d0fc392681..d7650fb00c 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -98,8 +98,7 @@ Common::String OSystem_Android::getPixelFormatName(const Graphics::PixelFormat & void OSystem_Android::initTexture(GLESTexture **texture, uint width, uint height, - const Graphics::PixelFormat *format, - bool alphaPalette) { + const Graphics::PixelFormat *format) { assert(texture); Graphics::PixelFormat format_clut8 = Graphics::PixelFormat::createFormatCLUT8(); @@ -135,10 +134,7 @@ void OSystem_Android::initTexture(GLESTexture **texture, LOGE("unsupported pixel format: %s", getPixelFormatName(format_new).c_str()); - if (alphaPalette) - *texture = new GLESPalette8888Texture; - else - *texture = new GLESPalette888Texture; + *texture = new GLESPalette888Texture; } LOGD("new pixel format: %s", @@ -262,7 +258,7 @@ void OSystem_Android::initSize(uint width, uint height, GLTHREADCHECK; #ifdef USE_RGB_COLOR - initTexture(&_game_texture, width, height, format, false); + initTexture(&_game_texture, width, height, format); #else _game_texture->allocBuffer(width, height); _game_texture->fillBuffer(0); -- cgit v1.2.3 From 0cdaff65c104f11954167048455d4258d053e1cd Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 12 Mar 2011 09:33:45 +0100 Subject: ANDROID: Use 16bit pixel formats on CLUT8 textures This reduces the CPU usage on 640x480 games by ~5% on my droid when reuploading the textures to the GPU --- backends/platform/android/android.cpp | 6 ++-- backends/platform/android/android.h | 1 + backends/platform/android/gfx.cpp | 60 +++++++++++++++++++++-------------- 3 files changed, 42 insertions(+), 25 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 2be435c701..ca65863fc9 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -112,6 +112,8 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _mouse_texture(0), _mouse_texture_palette(0), _mouse_texture_rgb(0), + _mouse_hotspot(), + _mouse_keycolor(0), _use_mouse_palette(false), _show_mouse(false), _show_overlay(false), @@ -328,9 +330,9 @@ void OSystem_Android::initBackend() { initSurface(); initViewport(); - _game_texture = new GLESPalette888Texture(); + _game_texture = new GLESPalette565Texture(); _overlay_texture = new GLES4444Texture(); - _mouse_texture_palette = new GLESPalette8888Texture(); + _mouse_texture_palette = new GLESPalette5551Texture(); _mouse_texture = _mouse_texture_palette; initOverlay(); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index ba1a47a10f..f73131b317 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -116,6 +116,7 @@ private: GLESPaletteTexture *_mouse_texture_palette; GLES5551Texture *_mouse_texture_rgb; Common::Point _mouse_hotspot; + uint32 _mouse_keycolor; int _mouse_targetscale; bool _show_mouse; bool _use_mouse_palette; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index d7650fb00c..6be7a03b22 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -25,6 +25,7 @@ #if defined(__ANDROID__) +#include "common/endian.h" #include "graphics/conversion.h" #include "backends/platform/android/android.h" @@ -134,7 +135,7 @@ void OSystem_Android::initTexture(GLESTexture **texture, LOGE("unsupported pixel format: %s", getPixelFormatName(format_new).c_str()); - *texture = new GLESPalette888Texture; + *texture = new GLESPalette565Texture; } LOGD("new pixel format: %s", @@ -296,10 +297,14 @@ void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { GLTHREADCHECK; - memcpy(_game_texture->palette() + start * 3, colors, num * 3); - 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 OSystem_Android::grabPalette(byte *colors, uint start, uint num) { @@ -311,7 +316,11 @@ void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { GLTHREADCHECK; - memcpy(colors, _game_texture->palette() + start * 3, num * 3); + 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]); } void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, @@ -594,13 +603,11 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, if (_mouse_texture == _mouse_texture_palette) { assert(keycolor < 256); - // Update palette alpha based on keycolor - byte *palette = _mouse_texture_palette->palette(); - - for (uint i = 0; i < 256; ++i, palette += 4) - palette[3] = 0xff; + byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2; - _mouse_texture_palette->palette()[keycolor * 4 + 3] = 0; + WRITE_UINT16(p, READ_UINT16(p) | 1); + _mouse_keycolor = keycolor; + WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0); } if (w == 0 || h == 0) @@ -644,14 +651,14 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, void OSystem_Android::setCursorPaletteInternal(const byte *colors, uint start, uint num) { - byte *palette = _mouse_texture_palette->palette() + start * 4; + const Graphics::PixelFormat &pf = + _mouse_texture_palette->getPalettePixelFormat(); + byte *p = _mouse_texture_palette->palette() + start * 2; - for (uint i = 0; i < num; ++i, palette += 4, colors += 3) { - palette[0] = colors[0]; - palette[1] = colors[1]; - palette[2] = colors[2]; - // Leave alpha untouched to preserve keycolor - } + for (uint i = 0; i < num; ++i, colors += 3, p += 2) + WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2])); + + WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0); } void OSystem_Android::setCursorPalette(const byte *colors, @@ -679,15 +686,22 @@ void OSystem_Android::disableCursorPalette(bool disable) { // when disabling the cursor palette, and we're running a clut8 game, // it expects the game palette to be used for the cursor if (disable && _game_texture->hasPalette()) { - byte *src = _game_texture->palette(); + const byte *src = _game_texture->palette_const(); byte *dst = _mouse_texture_palette->palette(); - for (uint i = 0; i < 256; ++i, src += 3, dst += 4) { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - // Leave alpha untouched to preserve keycolor + 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)); } + + WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0); } _use_mouse_palette = !disable; -- cgit v1.2.3 From 429b091ed1a4881bcc3d39686d764e72eb355b9e Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 12 Mar 2011 09:35:51 +0100 Subject: ANDROID: Convinience make target for testing --- backends/platform/android/android.mk | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index 1bc3c3d21a..eb58089376 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -163,6 +163,10 @@ release/%.apk: %.apk androidrelease: $(addprefix release/, $(APK_MAIN) $(APK_PLUGINS)) +androidtestmain: $(APK_MAIN) + $(ADB) install -r $(APK_MAIN) + $(ADB) shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n org.inodes.gus.scummvm/.Unpacker + androidtest: $(APK_MAIN) $(APK_PLUGINS) @set -e; for apk in $^; do \ $(ADB) install -r $$apk; \ -- cgit v1.2.3 From a93229cae53bd35b320e72bd5fe794e8dd79c318 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 14:16:39 +0100 Subject: ANDROID: Don't use compressed textures for the game screen Some GLES drivers suck so much that uploading data to the GPU takes ages. CLUT8 games now use a faked paletted texture, which internally uses a RGB565 hardware texture (Android's native pixel format). This seems to be the only way to efficiently implement constant changing textures with GLES1 - at the cost of extra buffers. Then again, we can now use glTexSubImage2D to only update the dirty rects, which wasn't possible before because glCompressedTexSubImage2D is only usable on GLES2. This commit does exactly that. Overall, the CPU usage is massively reduced for CLUT8 games. --- backends/platform/android/android.cpp | 2 +- backends/platform/android/gfx.cpp | 14 ++-- backends/platform/android/texture.cpp | 117 +++++++++++++++++++++++++++++++++- backends/platform/android/texture.h | 53 +++++++++++++-- 4 files changed, 169 insertions(+), 17 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index ca65863fc9..56e56fb3dd 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -330,7 +330,7 @@ void OSystem_Android::initBackend() { initSurface(); initViewport(); - _game_texture = new GLESPalette565Texture(); + _game_texture = new GLESFakePalette565Texture(); _overlay_texture = new GLES4444Texture(); _mouse_texture_palette = new GLESPalette5551Texture(); _mouse_texture = _mouse_texture_palette; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 6be7a03b22..62dbe644bf 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -72,9 +72,9 @@ Graphics::PixelFormat OSystem_Android::getScreenFormat() const { Common::List OSystem_Android::getSupportedFormats() const { Common::List res; - res.push_back(GLES565Texture::getPixelFormat()); - res.push_back(GLES5551Texture::getPixelFormat()); - res.push_back(GLES4444Texture::getPixelFormat()); + res.push_back(GLES565Texture::pixelFormat()); + res.push_back(GLES5551Texture::pixelFormat()); + res.push_back(GLES4444Texture::pixelFormat()); res.push_back(Graphics::PixelFormat::createFormatCLUT8()); return res; @@ -123,11 +123,11 @@ void OSystem_Android::initTexture(GLESTexture **texture, delete *texture; - if (format_new == GLES565Texture::getPixelFormat()) + if (format_new == GLES565Texture::pixelFormat()) *texture = new GLES565Texture(); - else if (format_new == GLES5551Texture::getPixelFormat()) + else if (format_new == GLES5551Texture::pixelFormat()) *texture = new GLES5551Texture(); - else if (format_new == GLES4444Texture::getPixelFormat()) + else if (format_new == GLES4444Texture::pixelFormat()) *texture = new GLES4444Texture(); else { // TODO what now? @@ -135,7 +135,7 @@ void OSystem_Android::initTexture(GLESTexture **texture, LOGE("unsupported pixel format: %s", getPixelFormatName(format_new).c_str()); - *texture = new GLESPalette565Texture; + *texture = new GLESFakePalette565Texture; } LOGD("new pixel format: %s", diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index dbba275790..54479a6ab4 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -279,22 +279,26 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { clearDirty(); } +const Graphics::PixelFormat &GLESTexture::getPixelFormat() const { + return _pixelFormat; +} + GLES4444Texture::GLES4444Texture() : - GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, getPixelFormat()) { + GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) { } GLES4444Texture::~GLES4444Texture() { } GLES5551Texture::GLES5551Texture() : - GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, getPixelFormat()) { + GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixelFormat()) { } GLES5551Texture::~GLES5551Texture() { } GLES565Texture::GLES565Texture() : - GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, getPixelFormat()) { + GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixelFormat()) { } GLES565Texture::~GLES565Texture() { @@ -409,5 +413,112 @@ GLESPalette5551Texture::GLESPalette5551Texture() : GLESPalette5551Texture::~GLESPalette5551Texture() { } +GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat) : + GLESTexture(glFormat, glType, pixelFormat), + _palette(0), + _pixels(0), + _buf(0) +{ + _palettePixelFormat = pixelFormat; + _fake_format = Graphics::PixelFormat::createFormatCLUT8(); + + _palette = new uint16[256]; + assert(_palette); +} + +GLESFakePaletteTexture::~GLESFakePaletteTexture() { + delete[] _buf; + delete[] _pixels; + delete[] _palette; +} + +void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { + GLESTexture::allocBuffer(w, h); + + delete[] _buf; + delete[] _pixels; + + _pixels = new byte[w * h]; + assert(_pixels); + + // fixup surface, for the outside this is a CLUT8 surface + _surface.pixels = _pixels; + _surface.bytesPerPixel = 1; + _surface.pitch = w; + + _buf = new uint16[w * h]; + assert(_buf); +} + +void GLESFakePaletteTexture::fillBuffer(uint32 color) { + assert(_surface.pixels); + memset(_surface.pixels, 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) { + 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)); + } + + GLESTexture::drawTexture(x, y, w, h); +} + +const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const { + return _fake_format; +} + +GLESFakePalette565Texture::GLESFakePalette565Texture() : + GLESFakePaletteTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, + GLES565Texture::pixelFormat()) { +} + +GLESFakePalette565Texture::~GLESFakePalette565Texture() { +} + #endif diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 02cb0c71fb..15ad2e78b6 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -100,9 +100,7 @@ public: return _all_dirty || !_dirty_rect.isEmpty(); } - inline const Graphics::PixelFormat &getPixelFormat() const { - return _pixelFormat; - } + virtual const Graphics::PixelFormat &getPixelFormat() const; inline const Graphics::PixelFormat &getPalettePixelFormat() const { return _palettePixelFormat; @@ -152,7 +150,7 @@ public: GLES4444Texture(); virtual ~GLES4444Texture(); - static inline Graphics::PixelFormat getPixelFormat() { + static Graphics::PixelFormat pixelFormat() { return Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0); } }; @@ -163,7 +161,7 @@ public: GLES5551Texture(); virtual ~GLES5551Texture(); - static inline Graphics::PixelFormat getPixelFormat() { + static inline Graphics::PixelFormat pixelFormat() { return Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0); } }; @@ -174,7 +172,7 @@ public: GLES565Texture(); virtual ~GLES565Texture(); - static inline Graphics::PixelFormat getPixelFormat() { + static inline Graphics::PixelFormat pixelFormat() { return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); } }; @@ -247,6 +245,49 @@ public: virtual ~GLESPalette5551Texture(); }; +class GLESFakePaletteTexture : public GLESTexture { +protected: + GLESFakePaletteTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat); + +public: + virtual ~GLESFakePaletteTexture(); + + virtual void allocBuffer(GLuint width, GLuint height); + 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); + + inline void drawTexture() { + drawTexture(0, 0, _surface.w, _surface.h); + } + + 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(); +}; + #endif #endif -- cgit v1.2.3 From 2721e287e5bcd1f4d524f869c26156e27f5ba187 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 15:51:37 +0100 Subject: ANDROID: Buffer 16bit texture contents Same issue as in the last commit: glTexSubImage2D is slow, so cache all copyRect*() calls in a buffer, and update the dirty rect once when drawing. Reduces CPU usage on 16bit games significantly. Also, lockScreen() returns now pixel data for non-CLUT8 games instead of asserting. --- backends/platform/android/android.cpp | 2 +- backends/platform/android/android.h | 6 +- backends/platform/android/gfx.cpp | 3 +- backends/platform/android/texture.cpp | 213 +++++++++++++++++++--------------- backends/platform/android/texture.h | 47 ++++++-- 5 files changed, 159 insertions(+), 112 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 56e56fb3dd..e2e3174877 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -488,7 +488,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) { } else { // Touchscreen events need to be converted // from device to game coords first. - const GLESTexture *tex; + const GLESBaseTexture *tex; if (_show_overlay) tex = _overlay_texture; else diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index f73131b317..11a24a5f57 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -103,7 +103,7 @@ private: bool _force_redraw; // Game layer - GLESTexture *_game_texture; + GLESBaseTexture *_game_texture; int _shake_offset; Common::Rect _focus_rect; @@ -112,7 +112,7 @@ private: bool _show_overlay; // Mouse layer - GLESTexture *_mouse_texture; + GLESBaseTexture *_mouse_texture; GLESPaletteTexture *_mouse_texture_palette; GLES5551Texture *_mouse_texture_rgb; Common::Point _mouse_hotspot; @@ -151,7 +151,7 @@ private: #ifdef USE_RGB_COLOR Common::String getPixelFormatName(const Graphics::PixelFormat &format) const; - void initTexture(GLESTexture **texture, uint width, uint height, + void initTexture(GLESBaseTexture **texture, uint width, uint height, const Graphics::PixelFormat *format); #endif diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 62dbe644bf..34981dddb8 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -97,7 +97,7 @@ Common::String OSystem_Android::getPixelFormatName(const Graphics::PixelFormat & 8 - format.aLoss); } -void OSystem_Android::initTexture(GLESTexture **texture, +void OSystem_Android::initTexture(GLESBaseTexture **texture, uint width, uint height, const Graphics::PixelFormat *format) { assert(texture); @@ -438,7 +438,6 @@ Graphics::Surface *OSystem_Android::lockScreen() { GLTHREADCHECK; - // TODO this doesn't return any pixel data for non CLUT8 Graphics::Surface *surface = _game_texture->surface(); assert(surface->pixels); diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 54479a6ab4..a20222ec64 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -36,9 +36,6 @@ #include "backends/platform/android/texture.h" #include "backends/platform/android/android.h" -// Unfortunately, Android devices are too varied to make broad assumptions :/ -#define TEXSUBIMAGE_IS_EXPENSIVE 0 - // Supported GL extensions static bool npot_supported = false; #ifdef GL_OES_draw_texture @@ -62,7 +59,7 @@ static T nextHigher2(T k) { return k + 1; } -void GLESTexture::initGLExtensions() { +void GLESBaseTexture::initGLExtensions() { const char *ext_string = reinterpret_cast(glGetString(GL_EXTENSIONS)); @@ -82,8 +79,8 @@ void GLESTexture::initGLExtensions() { } } -GLESTexture::GLESTexture(GLenum glFormat, GLenum glType, - Graphics::PixelFormat pixelFormat) : +GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat) : _glFormat(glFormat), _glType(glType), _texture_name(0), @@ -98,16 +95,16 @@ GLESTexture::GLESTexture(GLenum glFormat, GLenum glType, GLCALL(glGenTextures(1, &_texture_name)); } -GLESTexture::~GLESTexture() { +GLESBaseTexture::~GLESBaseTexture() { release(); } -void GLESTexture::release() { - debug("Destroying texture %u", _texture_name); +void GLESBaseTexture::release() { + LOGD("Destroying texture %u", _texture_name); GLCALL(glDeleteTextures(1, &_texture_name)); } -void GLESTexture::reinit() { +void GLESBaseTexture::reinit() { GLCALL(glGenTextures(1, &_texture_name)); if (hasPalette()) { @@ -124,7 +121,7 @@ void GLESTexture::reinit() { setDirty(); } -void GLESTexture::initSize() { +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)); @@ -138,7 +135,7 @@ void GLESTexture::initSize() { 0, _glFormat, _glType, 0)); } -void GLESTexture::allocBuffer(GLuint w, GLuint h) { +void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) { _surface.w = w; _surface.h = h; _surface.bytesPerPixel = _pixelFormat.bytesPerPixel; @@ -155,85 +152,10 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _texture_height = nextHigher2(_surface.h); } - _surface.pitch = _texture_width * _pixelFormat.bytesPerPixel; - initSize(); } -void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, - const void *buf, int pitch_buf) { - ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch_buf); - - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); - - setDirtyRect(Common::Rect(x, y, x + w, y + h)); - - if (static_cast(w) * _pixelFormat.bytesPerPixel == pitch_buf) { - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - _glFormat, _glType, buf)); - } else { - // GLES removed the ability to specify pitch, so we - // have to do this ourselves. -#if TEXSUBIMAGE_IS_EXPENSIVE - byte *tmp = new byte[w * h * _pixelFormat.bytesPerPixel]; - assert(tmp); - - const byte *src = static_cast(buf); - byte *dst = tmp; - GLuint count = h; - - do { - memcpy(dst, src, w * _pixelFormat.bytesPerPixel); - dst += w * _pixelFormat.bytesPerPixel; - src += pitch_buf; - } while (--count); - - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - _glFormat, _glType, tmp)); - - delete[] tmp; -#else - // This version avoids the intermediate copy at the expense of - // repeat glTexSubImage2D calls. On some devices this is worse. - const byte *src = static_cast(buf); - do { - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, - w, 1, _glFormat, _glType, src)); - ++y; - src += pitch_buf; - } while (--h); -#endif - } -} - -void GLESTexture::fillBuffer(uint32 color) { - uint rowbytes = _surface.w * _pixelFormat.bytesPerPixel; - - byte *tmp = new byte[rowbytes]; - assert(tmp); - - if (_pixelFormat.bytesPerPixel == 1 || - ((color & 0xff) == ((color >> 8) & 0xff))) { - memset(tmp, color & 0xff, rowbytes); - } else { - uint16 *p = (uint16 *)tmp; - Common::set_to(p, p + _surface.w, (uint16)color); - } - - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); - - for (GLuint y = 0; y < _surface.h; ++y) - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, _surface.w, 1, - _glFormat, _glType, tmp)); - - delete[] tmp; - - setDirty(); -} - -void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { +void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); #ifdef GL_OES_draw_texture @@ -279,10 +201,110 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { clearDirty(); } -const Graphics::PixelFormat &GLESTexture::getPixelFormat() const { +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) { + GLESBaseTexture::allocBuffer(w, h); + + delete[] _buf; + delete[] _pixels; + + _pixels = new byte[w * h * _surface.bytesPerPixel]; + assert(_pixels); + + _surface.pixels = _pixels; + _surface.pitch = w * _pixelFormat.bytesPerPixel; + + _buf = new byte[w * h * _surface.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.bytesPerPixel; + + do { + memcpy(dst, src, w * _surface.bytesPerPixel); + dst += _surface.pitch; + src += pitch_buf; + } while (--h); +} + +void GLESTexture::fillBuffer(uint32 color) { + assert(_surface.pixels); + + if (_pixelFormat.bytesPerPixel == 1 || + ((color & 0xff) == ((color >> 8) & 0xff))) + memset(_pixels, color & 0xff, _surface.pitch * _surface.h); + else + Common::set_to(_pixels, _pixels + _surface.pitch * _surface.h, + (uint16)color); + + setDirty(); +} + +void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { + 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.bytesPerPixel; + byte *dst = _buf; + + uint16 l = dwidth * _surface.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); +} + GLES4444Texture::GLES4444Texture() : GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) { } @@ -306,7 +328,7 @@ GLES565Texture::~GLES565Texture() { GLESPaletteTexture::GLESPaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat palettePixelFormat) : - GLESTexture(glFormat, glType, + GLESBaseTexture(glFormat, glType, Graphics::PixelFormat::createFormatCLUT8()), _texture(0) { @@ -319,7 +341,7 @@ GLESPaletteTexture::~GLESPaletteTexture() { } void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { - GLESTexture::allocBuffer(w, h); + GLESBaseTexture::allocBuffer(w, h); // Texture gets uploaded later (from drawTexture()) @@ -335,6 +357,7 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { _texture = new_buffer; _surface.pixels = _texture + _paletteSize; + _surface.pitch = _texture_width; } void GLESPaletteTexture::fillBuffer(uint32 color) { @@ -370,7 +393,7 @@ void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, 0, texture_size, _texture)); } - GLESTexture::drawTexture(x, y, w, h); + GLESBaseTexture::drawTexture(x, y, w, h); } GLESPalette888Texture::GLESPalette888Texture() : @@ -415,7 +438,7 @@ GLESPalette5551Texture::~GLESPalette5551Texture() { GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat pixelFormat) : - GLESTexture(glFormat, glType, pixelFormat), + GLESBaseTexture(glFormat, glType, pixelFormat), _palette(0), _pixels(0), _buf(0) @@ -434,7 +457,7 @@ GLESFakePaletteTexture::~GLESFakePaletteTexture() { } void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { - GLESTexture::allocBuffer(w, h); + GLESBaseTexture::allocBuffer(w, h); delete[] _buf; delete[] _pixels; @@ -505,7 +528,7 @@ void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, dwidth, dheight, _glFormat, _glType, _buf)); } - GLESTexture::drawTexture(x, y, w, h); + GLESBaseTexture::drawTexture(x, y, w, h); } const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const { diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 15ad2e78b6..e8f20132f8 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -36,26 +36,26 @@ #include "common/rect.h" #include "common/array.h" -class GLESTexture { +class GLESBaseTexture { public: static void initGLExtensions(); protected: - GLESTexture(GLenum glFormat, GLenum glType, - Graphics::PixelFormat pixelFormat); + GLESBaseTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat); public: - virtual ~GLESTexture(); + virtual ~GLESBaseTexture(); void release(); void reinit(); void initSize(); - virtual void allocBuffer(GLuint width, GLuint height); + 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); + const void *buf, int pitch_buf) = 0; + virtual void fillBuffer(uint32 color) = 0; virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -144,6 +144,31 @@ protected: Graphics::PixelFormat _palettePixelFormat; }; +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); + + inline void drawTexture() { + drawTexture(0, 0, _surface.w, _surface.h); + } + +protected: + byte *_pixels; + byte *_buf; +}; + // RGBA4444 texture class GLES4444Texture : public GLESTexture { public: @@ -177,7 +202,7 @@ public: } }; -class GLESPaletteTexture : public GLESTexture { +class GLESPaletteTexture : public GLESBaseTexture { protected: GLESPaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat palettePixelFormat); @@ -185,7 +210,7 @@ protected: public: virtual ~GLESPaletteTexture(); - virtual void allocBuffer(GLuint width, GLuint height); + 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); @@ -245,7 +270,7 @@ public: virtual ~GLESPalette5551Texture(); }; -class GLESFakePaletteTexture : public GLESTexture { +class GLESFakePaletteTexture : public GLESBaseTexture { protected: GLESFakePaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat pixelFormat); @@ -253,7 +278,7 @@ protected: public: virtual ~GLESFakePaletteTexture(); - virtual void allocBuffer(GLuint width, GLuint height); + 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); -- cgit v1.2.3 From fa51d82639a500939907fdc9d18497914c60fe2c Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 16:37:56 +0100 Subject: ANDROID: Prevent unnecessary reallocs --- backends/platform/android/texture.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index a20222ec64..c309bd51b4 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -218,8 +218,14 @@ GLESTexture::~GLESTexture() { } void GLESTexture::allocBuffer(GLuint w, GLuint h) { + GLuint oldw = _surface.w; + GLuint oldh = _surface.h; + GLESBaseTexture::allocBuffer(w, h); + if (_surface.w == oldw && _surface.h == oldh) + return; + delete[] _buf; delete[] _pixels; @@ -341,9 +347,13 @@ GLESPaletteTexture::~GLESPaletteTexture() { } void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { + GLuint oldw = _surface.w; + GLuint oldh = _surface.h; + GLESBaseTexture::allocBuffer(w, h); - // Texture gets uploaded later (from drawTexture()) + if (_surface.w == oldw && _surface.h == oldh) + return; byte *new_buffer = new byte[_paletteSize + _texture_width * _texture_height]; @@ -457,8 +467,14 @@ GLESFakePaletteTexture::~GLESFakePaletteTexture() { } void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { + GLuint oldw = _surface.w; + GLuint oldh = _surface.h; + GLESBaseTexture::allocBuffer(w, h); + if (_surface.w == oldw && _surface.h == oldh) + return; + delete[] _buf; delete[] _pixels; -- cgit v1.2.3 From 787b27a4b1cde2bd8e750b4eb477189565588e28 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 16:42:50 +0100 Subject: ANDROID: Add missing updateScreen() calls --- backends/platform/android/android.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index e2e3174877..4391cf50db 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -423,6 +423,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) { _force_redraw = true; updateScreen(); _force_redraw = true; + updateScreen(); event.type = Common::EVENT_SCREEN_CHANGED; @@ -431,6 +432,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) { // new surface initSurface(); _force_redraw = true; + updateScreen(); event.type = Common::EVENT_SCREEN_CHANGED; -- cgit v1.2.3 From 4267011e3a42b3f633f86e3df6af12c456aa0f60 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 22:08:19 +0100 Subject: ANDROID: Some texture convinience functions --- backends/platform/android/gfx.cpp | 16 ++++++++------ backends/platform/android/texture.cpp | 1 + backends/platform/android/texture.h | 40 ++++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 22 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 34981dddb8..2543ac7a3e 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -250,6 +250,8 @@ void OSystem_Android::initOverlay() { LOGI("overlay size is %ux%u", overlay_width, overlay_height); _overlay_texture->allocBuffer(overlay_width, overlay_height); + _overlay_texture->setDrawRect(0, 0, + _egl_surface_width, _egl_surface_height); } void OSystem_Android::initSize(uint width, uint height, @@ -264,6 +266,9 @@ void OSystem_Android::initSize(uint width, uint height, _game_texture->allocBuffer(width, height); _game_texture->fillBuffer(0); #endif + + _game_texture->setDrawRect(0, 0, _egl_surface_width, _egl_surface_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 @@ -364,8 +369,7 @@ void OSystem_Android::updateScreen() { } if (_focus_rect.isEmpty()) { - _game_texture->drawTexture(0, 0, _egl_surface_width, - _egl_surface_height); + _game_texture->drawTextureRect(); } else { GLCALL(glPushMatrix()); GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()), @@ -377,8 +381,7 @@ void OSystem_Android::updateScreen() { xdiv(_game_texture->height(), _egl_surface_height), 1 << 16)); - _game_texture->drawTexture(0, 0, _egl_surface_width, - _egl_surface_height); + _game_texture->drawTextureRect(); GLCALL(glPopMatrix()); } @@ -388,8 +391,7 @@ void OSystem_Android::updateScreen() { // 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)); + GLCALL(_overlay_texture->drawTextureRect()); } if (_show_mouse) { @@ -422,7 +424,7 @@ void OSystem_Android::updateScreen() { GLCALL(glScalex(cs << 16, cs << 16, 1 << 16)); - _mouse_texture->drawTexture(); + _mouse_texture->drawTextureOrigin(); GLCALL(glPopMatrix()); } diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index c309bd51b4..499de00f56 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -87,6 +87,7 @@ GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType, _surface(), _texture_width(0), _texture_height(0), + _draw_rect(), _all_dirty(false), _dirty_rect(), _pixelFormat(pixelFormat), diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index e8f20132f8..547051996b 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -59,8 +59,29 @@ public: virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); + 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() { + 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 { @@ -136,7 +157,8 @@ protected: GLuint _texture_width; GLuint _texture_height; - // Covers dirty area + Common::Rect _draw_rect; + bool _all_dirty; Common::Rect _dirty_rect; @@ -160,10 +182,6 @@ public: virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - protected: byte *_pixels; byte *_buf; @@ -217,10 +235,6 @@ public: virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - virtual const byte *palette_const() const { return _texture; }; @@ -285,10 +299,6 @@ public: virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - virtual const byte *palette_const() const { return (byte *)_palette; }; -- cgit v1.2.3 From 79d991081dbeaddd0294c6bbf01675d1ec1fbb72 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 22:31:28 +0100 Subject: ANDROID: Add support for video feature flags kFeatureFullscreenMode and kFeatureAspectRatioCorrection are supported now. The former prevents scaling to the full display - it scales one axis and keeps the game AR. --- backends/platform/android/android.cpp | 50 ++++++++++--- backends/platform/android/android.h | 5 ++ backends/platform/android/gfx.cpp | 87 ++++++++++++++++++---- backends/platform/android/jni.cpp | 31 ++++++++ backends/platform/android/jni.h | 2 + .../android/org/inodes/gus/scummvm/ScummVM.java | 1 + .../org/inodes/gus/scummvm/ScummVMActivity.java | 9 +++ 7 files changed, 158 insertions(+), 27 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 4391cf50db..ba574564b4 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -115,6 +115,8 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _mouse_hotspot(), _mouse_keycolor(0), _use_mouse_palette(false), + _fullscreen(false), + _ar_correction(false), _show_mouse(false), _show_overlay(false), _enable_zoning(false), @@ -302,6 +304,9 @@ void OSystem_Android::initBackend() { _main_thread = pthread_self(); + ConfMan.registerDefault("fullscreen", true); + ConfMan.registerDefault("aspect_ratio", true); + ConfMan.setInt("autosave_period", 0); ConfMan.setBool("FM_high_quality", false); ConfMan.setBool("FM_medium_quality", true); @@ -351,7 +356,9 @@ void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { } bool OSystem_Android::hasFeature(Feature f) { - return (f == kFeatureCursorHasPalette || + return (f == kFeatureFullscreenMode || + f == kFeatureAspectRatioCorrection || + f == kFeatureCursorHasPalette || f == kFeatureVirtualKeyboard || f == kFeatureOverlaySupportsAlpha); } @@ -360,6 +367,14 @@ void OSystem_Android::setFeatureState(Feature f, bool enable) { ENTER("%d, %d", f, enable); switch (f) { + case kFeatureFullscreenMode: + _fullscreen = enable; + updateScreenRect(); + break; + case kFeatureAspectRatioCorrection: + _ar_correction = enable; + updateScreenRect(); + break; case kFeatureVirtualKeyboard: _virtkeybd_on = enable; showVirtualKeyboard(enable); @@ -490,17 +505,28 @@ bool OSystem_Android::pollEvent(Common::Event &event) { } else { // Touchscreen events need to be converted // from device to game coords first. - const GLESBaseTexture *tex; - if (_show_overlay) - tex = _overlay_texture; - else - tex = _game_texture; - - event.mouse.x = scalef(event.mouse.x, tex->width(), - _egl_surface_width); - event.mouse.y = scalef(event.mouse.y, tex->height(), - _egl_surface_height); - event.mouse.x -= _shake_offset; + if (_show_overlay) { + event.mouse.x = scalef(event.mouse.x, + _overlay_texture->width(), + _egl_surface_width); + event.mouse.y = scalef(event.mouse.y, + _overlay_texture->height(), + _egl_surface_height); + } else { + const Common::Rect &r = _game_texture->getDrawRect(); + + event.mouse.x -= r.left; + event.mouse.y -= r.top; + + event.mouse.x = scalef(event.mouse.x, + _game_texture->width(), + r.width()); + event.mouse.y = scalef(event.mouse.y, + _game_texture->height(), + r.height()); + + event.mouse.x -= _shake_offset; + } } break; } diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 11a24a5f57..26245e6a50 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -121,6 +121,9 @@ private: bool _show_mouse; bool _use_mouse_palette; + bool _fullscreen; + bool _ar_correction; + Common::Queue _event_queue; MutexRef _event_queue_lock; @@ -183,6 +186,8 @@ public: virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); + void clearScreen(bool swapBuffers); + void updateScreenRect(); virtual int getScreenChangeID() const; virtual int16 getHeight(); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 2543ac7a3e..20534331bc 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -267,7 +267,7 @@ void OSystem_Android::initSize(uint width, uint height, _game_texture->fillBuffer(0); #endif - _game_texture->setDrawRect(0, 0, _egl_surface_width, _egl_surface_height); + updateScreenRect(); // Don't know mouse size yet - it gets reallocated in // setMouseCursor. We need the palette allocated before @@ -275,10 +275,54 @@ void OSystem_Android::initSize(uint width, uint height, // size (it's small). _mouse_texture_palette->allocBuffer(20, 20); + clearScreen(true); +} + +void OSystem_Android::clearScreen(bool swapBuffers) { // clear screen GLCALL(glClearColorx(0, 0, 0, 1 << 16)); GLCALL(glClear(GL_COLOR_BUFFER_BIT)); - JNI::swapBuffers(); + + if (swapBuffers) + JNI::swapBuffers(); +} + +void OSystem_Android::updateScreenRect() { + uint16 w = _game_texture->width(); + uint16 h = _game_texture->height(); + + Common::Rect rect(0, 0, _egl_surface_width, _egl_surface_height); + + if (!_fullscreen) { + if (_ar_correction && w == 320 && h == 200) + h = 240; + + float dpi[2]; + JNI::getDPI(dpi); + + float screen_ar; + if (dpi[0] != 0.0 && dpi[1] != 0.0) { + // horizontal orientation + screen_ar = (dpi[1] * _egl_surface_width) / + (dpi[0] * _egl_surface_height); + } else { + screen_ar = float(_egl_surface_width) / float(_egl_surface_height); + } + + float game_ar = float(w) / float(h); + + if (screen_ar > game_ar) { + rect.setWidth(round(_egl_surface_height * game_ar)); + rect.moveTo((_egl_surface_width - rect.width()) / 2, 0); + } else { + rect.setHeight(round(_egl_surface_width / game_ar)); + rect.moveTo((_egl_surface_height - rect.height()) / 2, 0); + } + } + + glScissor(rect.left, rect.top, rect.width(), rect.height()); + + _game_texture->setDrawRect(rect); } int OSystem_Android::getScreenChangeID() const { @@ -353,6 +397,10 @@ void OSystem_Android::updateScreen() { _force_redraw = false; + // clear pointer leftovers in dead areas + if (_show_overlay && !_fullscreen) + clearScreen(false); + GLCALL(glPushMatrix()); if (_shake_offset != 0 || @@ -361,8 +409,7 @@ void OSystem_Android::updateScreen() { _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)); + clearScreen(false); // Move everything up by _shake_offset (game) pixels GLCALL(glTranslatex(0, -_shake_offset << 16, 0)); @@ -397,28 +444,32 @@ void OSystem_Android::updateScreen() { if (_show_mouse) { GLCALL(glPushMatrix()); - // Scale up ScummVM -> OpenGL (pixel) coordinates - int texwidth, texheight; + Common::Point mouse = getEventManager()->getMousePos(); + // Scale up ScummVM -> OpenGL (pixel) coordinates if (_show_overlay) { - texwidth = getOverlayWidth(); - texheight = getOverlayHeight(); + GLCALL(glScalex(xdiv(_egl_surface_width, + _overlay_texture->width()), + xdiv(_egl_surface_height, + _overlay_texture->height()), + 1 << 16)); } else { - texwidth = getWidth(); - texheight = getHeight(); + const Common::Rect &r = _game_texture->getDrawRect(); + + GLCALL(glTranslatex(r.left << 16, + r.top << 16, + 0)); + GLCALL(glScalex(xdiv(r.width(), _game_texture->width()), + xdiv(r.height(), _game_texture->height()), + 1 << 16)); } - 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)); @@ -494,6 +545,8 @@ void OSystem_Android::showOverlay() { _show_overlay = true; _force_redraw = true; + + GLCALL(glDisable(GL_SCISSOR_TEST)); } void OSystem_Android::hideOverlay() { @@ -501,6 +554,10 @@ void OSystem_Android::hideOverlay() { _show_overlay = false; _force_redraw = true; + + clearScreen(false); + + GLCALL(glEnable(GL_SCISSOR_TEST)); } void OSystem_Android::clearOverlay() { diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 6bfe9c2095..0628d92a2f 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -65,6 +65,7 @@ jfieldID JNI::_FID_Event_mouse_x = 0; jfieldID JNI::_FID_Event_mouse_y = 0; jfieldID JNI::_FID_Event_mouse_relative = 0; +jmethodID JNI::_MID_getDPI = 0; jmethodID JNI::_MID_displayMessageOnOSD = 0; jmethodID JNI::_MID_setWindowCaption = 0; jmethodID JNI::_MID_showVirtualKeyboard = 0; @@ -214,6 +215,35 @@ void JNI::throwRuntimeException(JNIEnv *env, const char *msg) { // calls to the dark side +void JNI::getDPI(float *values) { + values[0] = 0.0; + values[1] = 0.0; + + JNIEnv *env = JNI::getEnv(); + + jfloatArray array = env->NewFloatArray(2); + + env->CallVoidMethod(_jobj, _MID_getDPI, array); + + if (env->ExceptionCheck()) { + LOGE("Failed to get DPIs"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } else { + jfloat *res = env->GetFloatArrayElements(array, 0); + + if (res) { + values[0] = res[0]; + values[1] = res[1]; + + env->ReleaseFloatArrayElements(array, res, 0); + } + } + + env->DeleteLocalRef(array); +} + void JNI::displayMessageOnOSD(const char *msg) { JNIEnv *env = JNI::getEnv(); jstring java_msg = env->NewStringUTF(msg); @@ -445,6 +475,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, } while (0) FIND_METHOD(, setWindowCaption, "(Ljava/lang/String;)V"); + FIND_METHOD(, getDPI, "([F)V"); FIND_METHOD(, displayMessageOnOSD, "(Ljava/lang/String;)V"); FIND_METHOD(, showVirtualKeyboard, "(Z)V"); FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;"); diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 146938636d..5746c01afd 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -60,6 +60,7 @@ public: static void getPluginDirectories(Common::FSList &dirs); static void setWindowCaption(const char *caption); + static void getDPI(float *values); static void displayMessageOnOSD(const char *msg); static void showVirtualKeyboard(bool enable); static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); @@ -100,6 +101,7 @@ private: static jfieldID _FID_Event_mouse_relative; static jfieldID _FID_ScummVM_nativeScummVM; + static jmethodID _MID_getDPI; static jmethodID _MID_displayMessageOnOSD; static jmethodID _MID_setWindowCaption; static jmethodID _MID_showVirtualKeyboard; diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index f263b89015..0bc5f3ce4c 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -52,6 +52,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { final public native void pushEvent(Event e); // Callbacks from C++ peer instance + abstract protected void getDPI(float[] values); abstract protected void displayMessageOnOSD(String msg); abstract protected void setWindowCaption(String caption); abstract protected String[] getPluginDirectories(); diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 8cb3d80063..2cf6f58941 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -58,6 +58,15 @@ public class ScummVMActivity extends Activity { //enableZoning(usingSmallScreen()); } + @Override + protected void getDPI(float[] values) { + DisplayMetrics metrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(metrics); + + values[0] = metrics.xdpi; + values[1] = metrics.ydpi; + } + @Override protected void displayMessageOnOSD(String msg) { Log.i(LOG_TAG, "OSD: " + msg); -- cgit v1.2.3 From 2dd669d808b89f0d3777d196091b404a4e9baf05 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 22:41:07 +0100 Subject: ANDROID: Remove leftover TODO Resolved with a93229c and 2721e28 --- backends/platform/android/android.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index ba574564b4..9f57eb3fb5 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -480,7 +480,6 @@ bool OSystem_Android::pollEvent(Common::Event &event) { switch (event.type) { case Common::EVENT_MOUSEMOVE: - // TODO: only dirty/redraw move bounds _force_redraw = true; // fallthrough case Common::EVENT_LBUTTONDOWN: -- cgit v1.2.3 From c63c2a9e59ab9f9013a5e0e1f6c443352ce4f20f Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 22:56:44 +0100 Subject: ANDROID: Fix texture clear color --- backends/platform/android/gfx.cpp | 6 +++--- backends/platform/android/texture.cpp | 12 ++++++++++++ backends/platform/android/texture.h | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 20534331bc..332442345c 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -143,7 +143,7 @@ void OSystem_Android::initTexture(GLESBaseTexture **texture, } (*texture)->allocBuffer(width, height); - (*texture)->fillBuffer(0); + (*texture)->clearBuffer(); } #endif @@ -264,7 +264,7 @@ void OSystem_Android::initSize(uint width, uint height, initTexture(&_game_texture, width, height, format); #else _game_texture->allocBuffer(width, height); - _game_texture->fillBuffer(0); + _game_texture->clearBuffer(); #endif updateScreenRect(); @@ -686,7 +686,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, delete[] tmp; - _mouse_texture->fillBuffer(0); + _mouse_texture->clearBuffer(); return; } diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 499de00f56..b129b5ed48 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -267,6 +267,10 @@ void GLESTexture::fillBuffer(uint32 color) { setDirty(); } +void GLESTexture::clearBuffer() { + fillBuffer(_pixelFormat.ARGBToColor(0xff, 0, 0, 0)); +} + void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { if (_all_dirty) { _dirty_rect.top = 0; @@ -377,6 +381,10 @@ void GLESPaletteTexture::fillBuffer(uint32 color) { setDirty(); } +void GLESPaletteTexture::clearBuffer() { + fillBuffer(0); +} + void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const void *buf, int pitch_buf) { setDirtyRect(Common::Rect(x, y, x + w, y + h)); @@ -497,6 +505,10 @@ void GLESFakePaletteTexture::fillBuffer(uint32 color) { setDirty(); } +void GLESFakePaletteTexture::clearBuffer() { + fillBuffer(_palettePixelFormat.ARGBToColor(0xff, 0, 0, 0)); +} + void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const void *buf, int pitch_buf) { diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 547051996b..9b41627893 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -56,6 +56,7 @@ public: 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 clearBuffer() = 0; virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -179,6 +180,7 @@ public: virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); + virtual void clearBuffer(); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -232,6 +234,7 @@ public: virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); + virtual void clearBuffer(); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -296,6 +299,7 @@ public: virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); + virtual void clearBuffer(); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); -- cgit v1.2.3 From df9167c6b33fbfcb259480c14b08be5c32de6fd3 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 23:14:42 +0100 Subject: ANDROID: Add graphics mode for linear filtering --- backends/platform/android/android.cpp | 1 + backends/platform/android/android.h | 2 +- backends/platform/android/gfx.cpp | 21 ++++++++++++--------- backends/platform/android/texture.cpp | 17 +++++++++++++++-- backends/platform/android/texture.h | 3 +++ 5 files changed, 32 insertions(+), 12 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 9f57eb3fb5..606b825a51 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -116,6 +116,7 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _mouse_keycolor(0), _use_mouse_palette(false), _fullscreen(false), + _graphicsMode(0), _ar_correction(false), _show_mouse(false), _show_overlay(false), diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 26245e6a50..8e6d72fad2 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -121,6 +121,7 @@ private: bool _show_mouse; bool _use_mouse_palette; + int _graphicsMode; bool _fullscreen; bool _ar_correction; @@ -175,7 +176,6 @@ public: virtual const GraphicsMode *getSupportedGraphicsModes() const; virtual int getDefaultGraphicsMode() const; - bool setGraphicsMode(const char *name); virtual bool setGraphicsMode(int mode); virtual int getGraphicsMode() const; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 332442345c..06387e09fe 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -38,7 +38,8 @@ static inline GLfixed xdiv(int numerator, int denominator) { const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const { static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { - { "default", "Default", 1 }, + { "default", "Default", 0 }, + { "filter", "Linear filtering", 1 }, { 0, 0, 0 }, }; @@ -46,23 +47,25 @@ const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const } int OSystem_Android::getDefaultGraphicsMode() const { - return 1; -} - -bool OSystem_Android::setGraphicsMode(const char *mode) { - ENTER("%s", mode); - - return true; + return 0; } bool OSystem_Android::setGraphicsMode(int mode) { ENTER("%d", mode); + if (_game_texture) + _game_texture->setLinearFilter(mode == 1); + + if (_overlay_texture) + _overlay_texture->setLinearFilter(mode == 1); + + _graphicsMode = mode; + return true; } int OSystem_Android::getGraphicsMode() const { - return 1; + return _graphicsMode; } #ifdef USE_RGB_COLOR diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index b129b5ed48..bbfd1f0c86 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -83,6 +83,7 @@ GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat pixelFormat) : _glFormat(glFormat), _glType(glType), + _glFilter(GL_NEAREST), _texture_name(0), _surface(), _texture_width(0), @@ -127,8 +128,8 @@ void GLESBaseTexture::initSize() { // 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, GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + 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, @@ -136,6 +137,18 @@ void GLESBaseTexture::initSize() { 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; diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 9b41627893..1fe18bfd72 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -51,6 +51,8 @@ public: 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, @@ -152,6 +154,7 @@ protected: GLenum _glFormat; GLenum _glType; + GLint _glFilter; GLuint _texture_name; Graphics::Surface _surface; -- cgit v1.2.3 From ecd265b539452cfbd5eee96b5e4817dbed397d72 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 23:23:29 +0100 Subject: ANDROID: Center mouse on overlay visibility changes --- backends/platform/android/gfx.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 06387e09fe..dc8acaca29 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -546,6 +546,13 @@ void OSystem_Android::clearFocusRectangle() { void OSystem_Android::showOverlay() { ENTER(); + Common::Event e; + e.type = Common::EVENT_MOUSEMOVE; + e.mouse.x = _egl_surface_width / 2; + e.mouse.y = _egl_surface_height / 2; + + pushEvent(e); + _show_overlay = true; _force_redraw = true; @@ -555,6 +562,13 @@ void OSystem_Android::showOverlay() { void OSystem_Android::hideOverlay() { ENTER(); + Common::Event e; + e.type = Common::EVENT_MOUSEMOVE; + e.mouse.x = _egl_surface_width / 2; + e.mouse.y = _egl_surface_height / 2; + + pushEvent(e); + _show_overlay = false; _force_redraw = true; -- cgit v1.2.3 From f82121d2a279693f47a25e30e36c34e1e0ff21bd Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 23:27:36 +0100 Subject: ANDROID: Don't merge mouse move events Breaks more than it solves --- backends/platform/android/android.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 606b825a51..9374a876d9 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -540,24 +540,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) { void OSystem_Android::pushEvent(const Common::Event& event) { lockMutex(_event_queue_lock); - // Try to combine multiple queued mouse move events - if (event.type == Common::EVENT_MOUSEMOVE && - !_event_queue.empty() && - _event_queue.back().type == Common::EVENT_MOUSEMOVE) { - Common::Event tail = _event_queue.back(); - if (event.kbd.flags) { - // relative movement hack - tail.mouse.x += event.mouse.x; - tail.mouse.y += event.mouse.y; - } else { - // absolute position, clear relative flag - tail.kbd.flags = 0; - tail.mouse.x = event.mouse.x; - tail.mouse.y = event.mouse.y; - } - } else { - _event_queue.push(event); - } + _event_queue.push(event); unlockMutex(_event_queue_lock); } -- cgit v1.2.3 From 4b6e5e7b06c758d2c6738efaff5dceaaacfed214 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 13 Mar 2011 23:45:52 +0100 Subject: ANDROID: Clip mouse coordinates --- backends/platform/android/android.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 9374a876d9..4d83dd789e 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -526,6 +526,11 @@ bool OSystem_Android::pollEvent(Common::Event &event) { r.height()); event.mouse.x -= _shake_offset; + + event.mouse.x = CLIP(event.mouse.x, int16(0), + int16(_game_texture->width())); + event.mouse.y = CLIP(event.mouse.y, int16(0), + int16(_game_texture->height())); } } break; -- cgit v1.2.3 From 57635fe75cdf01a654d760efa0528a2aa186a391 Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 17:24:12 +0100 Subject: ANDROID: Update screen rects on surface changes Fixes regression introduced with 4267011e --- backends/platform/android/android.cpp | 4 ++++ backends/platform/android/gfx.cpp | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 4d83dd789e..85d4817f29 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -435,6 +435,8 @@ bool OSystem_Android::pollEvent(Common::Event &event) { _egl_surface_height = JNI::egl_surface_height; initViewport(); + updateScreenRect(); + // double buffered, flip twice _force_redraw = true; updateScreen(); @@ -447,6 +449,8 @@ bool OSystem_Android::pollEvent(Common::Event &event) { } else { // new surface initSurface(); + updateScreenRect(); + _force_redraw = true; updateScreen(); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index dc8acaca29..83ee8ba0f0 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -296,7 +296,9 @@ void OSystem_Android::updateScreenRect() { Common::Rect rect(0, 0, _egl_surface_width, _egl_surface_height); - if (!_fullscreen) { + _overlay_texture->setDrawRect(rect); + + if (w && h && !_fullscreen) { if (_ar_correction && w == 320 && h == 200) h = 240; -- cgit v1.2.3 From e1575e57f818f57b022531f31161e521869d7483 Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 17:50:19 +0100 Subject: ANDROID: Extend clearScreen to take care of all cases Hopefully that'll help me to not forget about the double buffering. This fixes some gfx leftovers when not running games in fullscreen mode. --- backends/platform/android/android.cpp | 9 +++---- backends/platform/android/android.h | 10 +++++++- backends/platform/android/gfx.cpp | 48 +++++++++++++++++++++++++---------- 3 files changed, 47 insertions(+), 20 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 85d4817f29..7731c53873 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -438,10 +438,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) { updateScreenRect(); // double buffered, flip twice - _force_redraw = true; - updateScreen(); - _force_redraw = true; - updateScreen(); + clearScreen(kClearUpdate, 2); event.type = Common::EVENT_SCREEN_CHANGED; @@ -451,8 +448,8 @@ bool OSystem_Android::pollEvent(Common::Event &event) { initSurface(); updateScreenRect(); - _force_redraw = true; - updateScreen(); + // double buffered, flip twice + clearScreen(kClearUpdate, 2); event.type = Common::EVENT_SCREEN_CHANGED; diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 8e6d72fad2..db2cb95650 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -186,7 +186,15 @@ public: virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); - void clearScreen(bool swapBuffers); + + enum FixupType { + kClear = 0, // glClear + kClearSwap, // glClear + swapBuffers + kClearUpdate // glClear + updateScreen + }; + + void clearScreen(FixupType type, byte count = 1); + void updateScreenRect(); virtual int getScreenChangeID() const; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 83ee8ba0f0..191d82efad 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -278,26 +278,47 @@ void OSystem_Android::initSize(uint width, uint height, // size (it's small). _mouse_texture_palette->allocBuffer(20, 20); - clearScreen(true); + clearScreen(kClear); } -void OSystem_Android::clearScreen(bool swapBuffers) { - // clear screen - GLCALL(glClearColorx(0, 0, 0, 1 << 16)); - GLCALL(glClear(GL_COLOR_BUFFER_BIT)); +void OSystem_Android::clearScreen(FixupType type, byte count) { + assert(count > 0); - if (swapBuffers) - JNI::swapBuffers(); + for (byte i = 0; i < count; ++i) { + if (!_show_overlay) + GLCALL(glDisable(GL_SCISSOR_TEST)); + + // clear screen + GLCALL(glClearColorx(0, 0, 0, 1 << 16)); + GLCALL(glClear(GL_COLOR_BUFFER_BIT)); + + if (!_show_overlay) + GLCALL(glEnable(GL_SCISSOR_TEST)); + + switch (type) { + case kClear: + break; + + case kClearSwap: + JNI::swapBuffers(); + break; + + case kClearUpdate: + _force_redraw = true; + updateScreen(); + break; + } + } } void OSystem_Android::updateScreenRect() { - uint16 w = _game_texture->width(); - uint16 h = _game_texture->height(); - Common::Rect rect(0, 0, _egl_surface_width, _egl_surface_height); _overlay_texture->setDrawRect(rect); + uint16 w = _game_texture->width(); + uint16 h = _game_texture->height(); + if (w && h && !_fullscreen) { if (_ar_correction && w == 320 && h == 200) h = 240; @@ -404,7 +425,7 @@ void OSystem_Android::updateScreen() { // clear pointer leftovers in dead areas if (_show_overlay && !_fullscreen) - clearScreen(false); + clearScreen(kClear); GLCALL(glPushMatrix()); @@ -414,7 +435,7 @@ void OSystem_Android::updateScreen() { _game_texture->height()).contains(_focus_rect))) { // These are the only cases where _game_texture doesn't // cover the entire screen. - clearScreen(false); + clearScreen(kClear); // Move everything up by _shake_offset (game) pixels GLCALL(glTranslatex(0, -_shake_offset << 16, 0)); @@ -574,7 +595,8 @@ void OSystem_Android::hideOverlay() { _show_overlay = false; _force_redraw = true; - clearScreen(false); + // double buffered, flip twice + clearScreen(kClearUpdate, 2); GLCALL(glEnable(GL_SCISSOR_TEST)); } -- cgit v1.2.3 From f587b6ee04b18366205277f76c3f048313e971a6 Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 18:06:08 +0100 Subject: ANDROID: Implement grabOverlay() --- backends/platform/android/gfx.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 191d82efad..2a66fcf247 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -253,6 +253,7 @@ void OSystem_Android::initOverlay() { LOGI("overlay size is %ux%u", overlay_width, overlay_height); _overlay_texture->allocBuffer(overlay_width, overlay_height); + _overlay_texture->clearBuffer(); _overlay_texture->setDrawRect(0, 0, _egl_surface_width, _egl_surface_height); } @@ -618,17 +619,15 @@ void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { GLTHREADCHECK; - // 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])); + const byte *src = (const byte *)surface->pixels; uint h = surface->h; do { - memset(buf, 0, surface->w * sizeof(buf[0])); - + memcpy(buf, src, surface->w * surface->bytesPerPixel); + src += surface->pitch; // This 'pitch' is pixels not bytes buf += pitch; } while (--h); -- cgit v1.2.3 From 5b94159f40fba8edaf15bf8961c479898646eb2d Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 18:53:38 +0100 Subject: ANDROID: Clear fake palette after allocating Gets rid of funky gfx artifacts on the overlay --- backends/platform/android/texture.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index bbfd1f0c86..9501d94f48 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -480,6 +480,8 @@ GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType, _palette = new uint16[256]; assert(_palette); + + memset(_palette, 0, 256 * 2); } GLESFakePaletteTexture::~GLESFakePaletteTexture() { -- cgit v1.2.3 From 6389e70e45864aaec860481cc25208f1a9ca4a76 Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 18:58:33 +0100 Subject: ANDROID: Remove clearBuffer() Not required. Why did i add that again? --- backends/platform/android/gfx.cpp | 8 ++++---- backends/platform/android/texture.cpp | 12 ------------ backends/platform/android/texture.h | 4 ---- 3 files changed, 4 insertions(+), 20 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 2a66fcf247..dfab8255ae 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -146,7 +146,7 @@ void OSystem_Android::initTexture(GLESBaseTexture **texture, } (*texture)->allocBuffer(width, height); - (*texture)->clearBuffer(); + (*texture)->fillBuffer(0); } #endif @@ -253,7 +253,7 @@ void OSystem_Android::initOverlay() { LOGI("overlay size is %ux%u", overlay_width, overlay_height); _overlay_texture->allocBuffer(overlay_width, overlay_height); - _overlay_texture->clearBuffer(); + _overlay_texture->fillBuffer(0); _overlay_texture->setDrawRect(0, 0, _egl_surface_width, _egl_surface_height); } @@ -268,7 +268,7 @@ void OSystem_Android::initSize(uint width, uint height, initTexture(&_game_texture, width, height, format); #else _game_texture->allocBuffer(width, height); - _game_texture->clearBuffer(); + _game_texture->fillBuffer(0); #endif updateScreenRect(); @@ -726,7 +726,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, delete[] tmp; - _mouse_texture->clearBuffer(); + _mouse_texture->fillBuffer(0); return; } diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 9501d94f48..87a8c2e362 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -280,10 +280,6 @@ void GLESTexture::fillBuffer(uint32 color) { setDirty(); } -void GLESTexture::clearBuffer() { - fillBuffer(_pixelFormat.ARGBToColor(0xff, 0, 0, 0)); -} - void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { if (_all_dirty) { _dirty_rect.top = 0; @@ -394,10 +390,6 @@ void GLESPaletteTexture::fillBuffer(uint32 color) { setDirty(); } -void GLESPaletteTexture::clearBuffer() { - fillBuffer(0); -} - void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const void *buf, int pitch_buf) { setDirtyRect(Common::Rect(x, y, x + w, y + h)); @@ -520,10 +512,6 @@ void GLESFakePaletteTexture::fillBuffer(uint32 color) { setDirty(); } -void GLESFakePaletteTexture::clearBuffer() { - fillBuffer(_palettePixelFormat.ARGBToColor(0xff, 0, 0, 0)); -} - void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const void *buf, int pitch_buf) { diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 1fe18bfd72..4f2bfe4c4f 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -58,7 +58,6 @@ public: 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 clearBuffer() = 0; virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -183,7 +182,6 @@ public: virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); - virtual void clearBuffer(); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -237,7 +235,6 @@ public: virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); - virtual void clearBuffer(); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); @@ -302,7 +299,6 @@ public: virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, const void *buf, int pitch_buf); virtual void fillBuffer(uint32 color); - virtual void clearBuffer(); virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); -- cgit v1.2.3 From d060b597c38d6332ae4eb79d051427a2381bfc5c Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 19:27:10 +0100 Subject: ANDROID: Fade out the game screen when the overlay is visible --- backends/platform/android/gfx.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index dfab8255ae..d08cc631bf 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -442,6 +442,9 @@ void OSystem_Android::updateScreen() { GLCALL(glTranslatex(0, -_shake_offset << 16, 0)); } + if (_show_overlay) + GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f)); + if (_focus_rect.isEmpty()) { _game_texture->drawTextureRect(); } else { @@ -462,6 +465,8 @@ void OSystem_Android::updateScreen() { int cs = _mouse_targetscale; if (_show_overlay) { + GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); + // ugly, but the modern theme sets a wacko factor, only god knows why cs = 1; -- cgit v1.2.3 From f706b1568d286bb2c145046e4d3f04f6ee177314 Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 20:10:41 +0100 Subject: ANDROID: Cleanup Removed not required checks since we now buffer texture contents --- backends/platform/android/texture.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 87a8c2e362..691c384a18 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -103,22 +103,15 @@ GLESBaseTexture::~GLESBaseTexture() { void GLESBaseTexture::release() { LOGD("Destroying texture %u", _texture_name); + GLCALL(glDeleteTextures(1, &_texture_name)); + _texture_name = 0; } void GLESBaseTexture::reinit() { GLCALL(glGenTextures(1, &_texture_name)); - if (hasPalette()) { - // paletted textures are in a local buffer, don't wipe it - initSize(); - } else { - // bypass allocBuffer() shortcut to reinit the texture properly - _texture_width = 0; - _texture_height = 0; - - allocBuffer(_surface.w, _surface.h); - } + initSize(); setDirty(); } @@ -154,8 +147,7 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) { _surface.h = h; _surface.bytesPerPixel = _pixelFormat.bytesPerPixel; - // Already allocated a sufficiently large buffer? - if (w <= _texture_width && h <= _texture_height) + if (w == _texture_width && h == _texture_height) return; if (npot_supported) { -- cgit v1.2.3 From 9e7ee4953ec5ca41a30c178ce778149a86f07b8f Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 20:26:35 +0100 Subject: ANDROID: Halve the audio buffer size Also, run into the blocking audio write without sleep. This hopefully fixes audio hickups on slow devices. --- backends/platform/android/android.cpp | 4 +--- backends/platform/android/org/inodes/gus/scummvm/ScummVM.java | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 7731c53873..72810b6fb7 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -286,9 +286,7 @@ void *OSystem_Android::audioThreadFunc(void *arg) { if (written < 0) break; - // sleep a little, prepare the next buffer, and run into the - // blocking AudioTrack.write - nanosleep(&tv_delay, 0); + // prepare the next buffer, and run into the blocking AudioTrack.write } JNI::setAudioStop(); diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 0bc5f3ce4c..dfb585518a 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -245,8 +245,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT); - // ~100ms - int buffer_size_want = (_sample_rate * 2 * 2 / 10) & ~1023; + // ~50ms + int buffer_size_want = (_sample_rate * 2 * 2 / 20) & ~1023; if (_buffer_size < buffer_size_want) { Log.w(LOG_TAG, String.format( -- cgit v1.2.3 From 7b850c18c7303fa06ff357cf2295e868a16ed1cf Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 23:44:43 +0100 Subject: ANDROID: Cleanup --- backends/platform/android/android.cpp | 3 ++- backends/platform/android/android.h | 18 +----------------- backends/platform/android/gfx.cpp | 8 +++++++- 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 72810b6fb7..dc8dc9d9c0 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -534,6 +534,7 @@ bool OSystem_Android::pollEvent(Common::Event &event) { } break; } + default: break; } @@ -554,7 +555,7 @@ uint32 OSystem_Android::getMillis() { gettimeofday(&curTime, 0); - return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \ + return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + ((curTime.tv_usec - _startTime.tv_usec) / 1000)); } diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index db2cb95650..dc45f06cb6 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -229,23 +229,7 @@ public: 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 Graphics::PixelFormat getOverlayFormat() const; virtual bool showMouse(bool visible); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index d08cc631bf..65f98d5094 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -449,6 +449,7 @@ void OSystem_Android::updateScreen() { _game_texture->drawTextureRect(); } else { GLCALL(glPushMatrix()); + GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()), xdiv(_egl_surface_height, _focus_rect.height()), 1 << 16)); @@ -459,6 +460,7 @@ void OSystem_Android::updateScreen() { 1 << 16)); _game_texture->drawTextureRect(); + GLCALL(glPopMatrix()); } @@ -476,7 +478,7 @@ void OSystem_Android::updateScreen() { if (_show_mouse) { GLCALL(glPushMatrix()); - Common::Point mouse = getEventManager()->getMousePos(); + const Common::Point &mouse = getEventManager()->getMousePos(); // Scale up ScummVM -> OpenGL (pixel) coordinates if (_show_overlay) { @@ -659,6 +661,10 @@ int16 OSystem_Android::getOverlayWidth() { return _overlay_texture->width(); } +Graphics::PixelFormat OSystem_Android::getOverlayFormat() const { + return _overlay_texture->getPixelFormat(); +} + bool OSystem_Android::showMouse(bool visible) { ENTER("%d", visible); -- cgit v1.2.3 From 6e4af65be1bbb7abb88bd75f5fe2f0260530f6ad Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 14 Mar 2011 23:49:18 +0100 Subject: ANDROID: Add missing cases to getFeatureState() --- backends/platform/android/android.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index dc8dc9d9c0..ddef4275a4 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -385,6 +385,10 @@ void OSystem_Android::setFeatureState(Feature f, bool enable) { bool OSystem_Android::getFeatureState(Feature f) { switch (f) { + case kFeatureFullscreenMode: + return _fullscreen; + case kFeatureAspectRatioCorrection: + return _ar_correction; case kFeatureVirtualKeyboard: return _virtkeybd_on; default: -- cgit v1.2.3 From 6b346c1fe04a8e3ed770d6246532391591265ea2 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 15 Mar 2011 22:54:01 +0100 Subject: ANDROID: Cleanup and extend chooseEglConfig Add more checks and log all possible configs --- .../android/org/inodes/gus/scummvm/ScummVM.java | 240 ++++++++++++--------- 1 file changed, 134 insertions(+), 106 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index dfb585518a..ed4e00d769 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -144,34 +144,20 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { _egl.eglInitialize(_egl_display, version); int[] num_config = new int[1]; - _egl.eglChooseConfig(_egl_display, configSpec, null, 0, num_config); + _egl.eglGetConfigs(_egl_display, null, 0, num_config); final int numConfigs = num_config[0]; if (numConfigs <= 0) - throw new IllegalArgumentException("No configs match configSpec"); + throw new IllegalArgumentException("No EGL configs"); EGLConfig[] configs = new EGLConfig[numConfigs]; - _egl.eglChooseConfig(_egl_display, configSpec, configs, numConfigs, - num_config); - - if (false) { - Log.d(LOG_TAG, String.format("Found %d EGL configurations.", - numConfigs)); - for (EGLConfig config : configs) - dumpEglConfig(config); - } + _egl.eglGetConfigs(_egl_display, configs, numConfigs, num_config); // Android's eglChooseConfig is busted in several versions and - // devices so we have to filter/rank the configs again ourselves. + // devices so we have to filter/rank the configs ourselves. _egl_config = chooseEglConfig(configs); - if (false) { - Log.d(LOG_TAG, String.format("Chose from %d EGL configs", - numConfigs)); - dumpEglConfig(_egl_config); - } - _egl_context = _egl.eglCreateContext(_egl_display, _egl_config, EGL10.EGL_NO_CONTEXT, null); @@ -280,121 +266,163 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { _sample_rate = 0; } - static final int configSpec[] = { - EGL10.EGL_RED_SIZE, 5, - EGL10.EGL_GREEN_SIZE, 5, - EGL10.EGL_BLUE_SIZE, 5, - EGL10.EGL_DEPTH_SIZE, 0, - EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT, - EGL10.EGL_NONE, + private static final int[] s_eglAttribs = { + EGL10.EGL_CONFIG_ID, + EGL10.EGL_BUFFER_SIZE, + EGL10.EGL_RED_SIZE, + EGL10.EGL_GREEN_SIZE, + EGL10.EGL_BLUE_SIZE, + EGL10.EGL_ALPHA_SIZE, + EGL10.EGL_CONFIG_CAVEAT, + EGL10.EGL_DEPTH_SIZE, + EGL10.EGL_LEVEL, + EGL10.EGL_MAX_PBUFFER_WIDTH, + EGL10.EGL_MAX_PBUFFER_HEIGHT, + EGL10.EGL_MAX_PBUFFER_PIXELS, + EGL10.EGL_NATIVE_RENDERABLE, + EGL10.EGL_NATIVE_VISUAL_ID, + EGL10.EGL_NATIVE_VISUAL_TYPE, + EGL10.EGL_SAMPLE_BUFFERS, + EGL10.EGL_SAMPLES, + EGL10.EGL_STENCIL_SIZE, + EGL10.EGL_SURFACE_TYPE, + EGL10.EGL_TRANSPARENT_TYPE, + EGL10.EGL_TRANSPARENT_RED_VALUE, + EGL10.EGL_TRANSPARENT_GREEN_VALUE, + EGL10.EGL_TRANSPARENT_BLUE_VALUE }; - // For debugging - private static final Map attribs; + final private class EglAttribs extends LinkedHashMap { + public EglAttribs(EGLConfig config) { + super(s_eglAttribs.length); - static { - attribs = new LinkedHashMap(); - attribs.put("CONFIG_ID", EGL10.EGL_CONFIG_ID); - attribs.put("BUFFER_SIZE", EGL10.EGL_BUFFER_SIZE); - attribs.put("RED_SIZE", EGL10.EGL_RED_SIZE); - attribs.put("GREEN_SIZE", EGL10.EGL_GREEN_SIZE); - attribs.put("BLUE_SIZE", EGL10.EGL_BLUE_SIZE); - attribs.put("ALPHA_SIZE", EGL10.EGL_ALPHA_SIZE); - //attribs.put("BIND_TO_RGB", EGL10.EGL_BIND_TO_TEXTURE_RGB); - //attribs.put("BIND_TO_RGBA", EGL10.EGL_BIND_TO_TEXTURE_RGBA); - attribs.put("CONFIG_CAVEAT", EGL10.EGL_CONFIG_CAVEAT); - attribs.put("DEPTH_SIZE", EGL10.EGL_DEPTH_SIZE); - attribs.put("LEVEL", EGL10.EGL_LEVEL); - attribs.put("MAX_PBUFFER_WIDTH", EGL10.EGL_MAX_PBUFFER_WIDTH); - attribs.put("MAX_PBUFFER_HEIGHT", EGL10.EGL_MAX_PBUFFER_HEIGHT); - attribs.put("MAX_PBUFFER_PIXELS", EGL10.EGL_MAX_PBUFFER_PIXELS); - //attribs.put("MAX_SWAP_INTERVAL", EGL10.EGL_MAX_SWAP_INTERVAL); - //attribs.put("MIN_SWAP_INTERVAL", EGL10.EGL_MIN_SWAP_INTERVAL); - attribs.put("NATIVE_RENDERABLE", EGL10.EGL_NATIVE_RENDERABLE); - attribs.put("NATIVE_VISUAL_ID", EGL10.EGL_NATIVE_VISUAL_ID); - attribs.put("NATIVE_VISUAL_TYPE", EGL10.EGL_NATIVE_VISUAL_TYPE); - attribs.put("SAMPLE_BUFFERS", EGL10.EGL_SAMPLE_BUFFERS); - attribs.put("SAMPLES", EGL10.EGL_SAMPLES); - attribs.put("STENCIL_SIZE", EGL10.EGL_STENCIL_SIZE); - attribs.put("SURFACE_TYPE", EGL10.EGL_SURFACE_TYPE); - attribs.put("TRANSPARENT_TYPE", EGL10.EGL_TRANSPARENT_TYPE); - attribs.put("TRANSPARENT_RED_VALUE", EGL10.EGL_TRANSPARENT_RED_VALUE); - attribs.put("TRANSPARENT_GREEN_VALUE", EGL10.EGL_TRANSPARENT_GREEN_VALUE); - attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE); - } + int[] value = new int[1]; - final private void dumpEglConfig(EGLConfig config) { - int[] value = new int[1]; + for (int i : s_eglAttribs) { + _egl.eglGetConfigAttrib(_egl_display, config, i, value); - for (Map.Entry entry : attribs.entrySet()) { - _egl.eglGetConfigAttrib(_egl_display, config, - entry.getValue(), value); - - if (value[0] == EGL10.EGL_NONE) - Log.d(LOG_TAG, entry.getKey() + ": NONE"); - else - Log.d(LOG_TAG, String.format("%s: %d", entry.getKey(), value[0])); + put(i, value[0]); + } } - } - final private EGLConfig chooseEglConfig(EGLConfig[] configs) { - int best = 0; - int bestScore = -1; - int[] value = new int[1]; + private int weightBits(int attr, int size) { + final int value = get(attr); - for (int i = 0; i < configs.length; i++) { - EGLConfig config = configs[i]; - int score = 10000; + int score = 0; - _egl.eglGetConfigAttrib(_egl_display, config, - EGL10.EGL_SURFACE_TYPE, value); + if (value == size || (size > 0 && value > size)) + score += 10; - // must have - if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0) - continue; + // penalize for wasted bits + score -= value - size; + + return score; + } - _egl.eglGetConfigAttrib(_egl_display, config, - EGL10.EGL_CONFIG_CAVEAT, value); + public int weight() { + int score = 10000; - if (value[0] != EGL10.EGL_NONE) + if (get(EGL10.EGL_CONFIG_CAVEAT) != EGL10.EGL_NONE) score -= 1000; - // Must be at least 555, but then smaller is better - final int[] colorBits = { EGL10.EGL_RED_SIZE, - EGL10.EGL_GREEN_SIZE, - EGL10.EGL_BLUE_SIZE, - EGL10.EGL_ALPHA_SIZE - }; + // less MSAA is better + score -= get(EGL10.EGL_SAMPLES) * 100; - for (int component : colorBits) { - _egl.eglGetConfigAttrib(_egl_display, config, component, value); + // Must be at least 565, but then smaller is better + score += weightBits(EGL10.EGL_RED_SIZE, 5); + score += weightBits(EGL10.EGL_GREEN_SIZE, 6); + score += weightBits(EGL10.EGL_BLUE_SIZE, 5); + score += weightBits(EGL10.EGL_ALPHA_SIZE, 0); + score += weightBits(EGL10.EGL_DEPTH_SIZE, 0); + score += weightBits(EGL10.EGL_STENCIL_SIZE, 0); - // boost if >5 bits accuracy - if (value[0] >= 5) - score += 10; + return score; + } + + public String toString() { + String s; - // penalize for wasted bits - score -= value[0]; + if (get(EGL10.EGL_ALPHA_SIZE) > 0) + s = String.format("[%d] RGBA%d%d%d%d", + get(EGL10.EGL_CONFIG_ID), + get(EGL10.EGL_RED_SIZE), + get(EGL10.EGL_GREEN_SIZE), + get(EGL10.EGL_BLUE_SIZE), + get(EGL10.EGL_ALPHA_SIZE)); + else + s = String.format("[%d] RGB%d%d%d", + get(EGL10.EGL_CONFIG_ID), + get(EGL10.EGL_RED_SIZE), + get(EGL10.EGL_GREEN_SIZE), + get(EGL10.EGL_BLUE_SIZE)); + + if (get(EGL10.EGL_DEPTH_SIZE) > 0) + s += String.format(" D%d", get(EGL10.EGL_DEPTH_SIZE)); + + if (get(EGL10.EGL_STENCIL_SIZE) > 0) + s += String.format(" S%d", get(EGL10.EGL_STENCIL_SIZE)); + + if (get(EGL10.EGL_SAMPLES) > 0) + s += String.format(" MSAAx%d", get(EGL10.EGL_SAMPLES)); + + if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) > 0) + s += " W"; + if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PBUFFER_BIT) > 0) + s += " P"; + if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PIXMAP_BIT) > 0) + s += " X"; + + switch (get(EGL10.EGL_CONFIG_CAVEAT)) { + case EGL10.EGL_NONE: + break; + + case EGL10.EGL_SLOW_CONFIG: + s += " SLOW"; + break; + + case EGL10.EGL_NON_CONFORMANT_CONFIG: + s += " NON_CONFORMANT"; + + default: + s += String.format(" unknown CAVEAT 0x%x", + get(EGL10.EGL_CONFIG_CAVEAT)); } - _egl.eglGetConfigAttrib(_egl_display, config, - EGL10.EGL_DEPTH_SIZE, value); + return s; + } + }; - // penalize for wasted bits - score -= value[0]; + final private EGLConfig chooseEglConfig(EGLConfig[] configs) { + EGLConfig res = configs[0]; + int bestScore = -1; + + Log.d(LOG_TAG, "EGL configs:"); + + for (EGLConfig config : configs) { + EglAttribs attr = new EglAttribs(config); + + // must have + if ((attr.get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) == 0) + continue; + + int score = attr.weight(); + + Log.d(LOG_TAG, String.format("%s (%d)", attr.toString(), score)); if (score > bestScore) { - best = i; + res = config; bestScore = score; } } - if (bestScore < 0) { - Log.e(LOG_TAG, "Unable to find an acceptable EGL config, expect badness."); - return configs[0]; - } + if (bestScore < 0) + Log.e(LOG_TAG, + "Unable to find an acceptable EGL config, expect badness."); + + Log.d(LOG_TAG, String.format("Chosen EGL config: %s", + new EglAttribs(res).toString())); - return configs[best]; + return res; } static { -- cgit v1.2.3 From e71c2cf850388b2a25200d544d2fb422525b4c88 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 15 Mar 2011 23:01:09 +0100 Subject: ANDROID: Constify getDrawRect() --- backends/platform/android/texture.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 4f2bfe4c4f..64489da0a4 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -73,7 +73,7 @@ public: _draw_rect = Common::Rect(x1, y1, x2, y2); } - inline const Common::Rect &getDrawRect() { + inline const Common::Rect &getDrawRect() const { return _draw_rect; } -- cgit v1.2.3 From adef4c3f4256a690b374b9801279952c39ccf7a4 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 15 Mar 2011 23:30:17 +0100 Subject: ANDROID: Input system overhaul Rewritten input system with many new feature. Fixed related bugs and shortcomings on the way. --- backends/platform/android/android.cpp | 179 +----- backends/platform/android/android.h | 23 +- backends/platform/android/android.mk | 1 + backends/platform/android/events.cpp | 661 +++++++++++++++++++++ backends/platform/android/gfx.cpp | 48 +- backends/platform/android/jni.cpp | 96 +-- backends/platform/android/jni.h | 13 +- backends/platform/android/module.mk | 3 +- .../android/org/inodes/gus/scummvm/Event.java | 330 ---------- .../android/org/inodes/gus/scummvm/ScummVM.java | 5 +- .../org/inodes/gus/scummvm/ScummVMActivity.java | 295 +-------- .../org/inodes/gus/scummvm/ScummVMEvents.java | 201 +++++++ 12 files changed, 940 insertions(+), 915 deletions(-) create mode 100644 backends/platform/android/events.cpp delete mode 100644 backends/platform/android/org/inodes/gus/scummvm/Event.java create mode 100644 backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index ddef4275a4..4e1373a1b1 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -94,12 +94,6 @@ void checkGlError(const char *expr, const char *file, int line) { } #endif -// floating point. use sparingly -template -static inline T scalef(T in, float numerator, float denominator) { - return static_cast(in) * numerator / denominator; -} - OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _audio_sample_rate(audio_sample_rate), _audio_buffer_size(audio_buffer_size), @@ -126,7 +120,16 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _timer(0), _fsFactory(new POSIXFilesystemFactory()), _shake_offset(0), - _event_queue_lock(createMutex()) { + _event_queue_lock(createMutex()), + _touch_pt_down(), + _touch_pt_dt(), + _eventScaleX(100), + _eventScaleY(100), + // TODO put these values in some option dlg? + _touchpad_mode(true), + _touchpad_scale(50), + _dpad_scale(4), + _trackball_scale(2) { } OSystem_Android::~OSystem_Android() { @@ -310,6 +313,10 @@ void OSystem_Android::initBackend() { ConfMan.setBool("FM_high_quality", false); ConfMan.setBool("FM_medium_quality", true); + // TODO hackity hack + if (ConfMan.hasKey("multi_midi")) + _touchpad_mode = !ConfMan.getBool("multi_midi"); + // must happen before creating TimerManager to avoid race in // creating EventManager setupKeymapper(); @@ -396,164 +403,6 @@ bool OSystem_Android::getFeatureState(Feature f) { } } -void OSystem_Android::setupKeymapper() { -#ifdef ENABLE_KEYMAPPER - using namespace Common; - - Keymapper *mapper = getEventManager()->getKeymapper(); - - HardwareKeySet *keySet = new HardwareKeySet(); - - keySet->addHardwareKey( - new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)", - kTriggerLeftKeyType, - kVirtualKeyboardActionType)); - - mapper->registerHardwareKeySet(keySet); - - Keymap *globalMap = new Keymap("global"); - Action *act; - - act = new Action(globalMap, "VIRT", "Display keyboard", - kVirtualKeyboardActionType); - act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0)); - - mapper->addGlobalKeymap(globalMap); - - mapper->pushKeymap("global"); -#endif -} - -bool OSystem_Android::pollEvent(Common::Event &event) { - //ENTER(); - - if (pthread_self() == _main_thread) { - if (_screen_changeid != JNI::surface_changeid) { - if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { - if (_egl_surface_width > 0 && _egl_surface_height > 0) { - // surface still alive but changed - _screen_changeid = JNI::surface_changeid; - _egl_surface_width = JNI::egl_surface_width; - _egl_surface_height = JNI::egl_surface_height; - - initViewport(); - updateScreenRect(); - - // double buffered, flip twice - clearScreen(kClearUpdate, 2); - - event.type = Common::EVENT_SCREEN_CHANGED; - - return true; - } else { - // new surface - initSurface(); - updateScreenRect(); - - // double buffered, flip twice - clearScreen(kClearUpdate, 2); - - event.type = Common::EVENT_SCREEN_CHANGED; - - return true; - } - } else { - // surface lost - deinitSurface(); - } - } - - if (JNI::pause) { - deinitSurface(); - - LOGD("main thread going to sleep"); - sem_wait(&JNI::pause_sem); - LOGD("main thread woke up"); - } - } - - lockMutex(_event_queue_lock); - - if (_event_queue.empty()) { - unlockMutex(_event_queue_lock); - return false; - } - - event = _event_queue.pop(); - unlockMutex(_event_queue_lock); - - switch (event.type) { - case Common::EVENT_MOUSEMOVE: - _force_redraw = true; - // fallthrough - 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: { - // relative mouse hack - if (event.kbd.flags == 1) { - // Relative (trackball) mouse hack. - const Common::Point& mouse_pos = - getEventManager()->getMousePos(); - event.mouse.x += mouse_pos.x; - event.mouse.y += mouse_pos.y; - event.mouse.x = CLIP(event.mouse.x, (int16)0, _show_overlay ? - getOverlayWidth() : getWidth()); - event.mouse.y = CLIP(event.mouse.y, (int16)0, _show_overlay ? - getOverlayHeight() : getHeight()); - } else { - // Touchscreen events need to be converted - // from device to game coords first. - if (_show_overlay) { - event.mouse.x = scalef(event.mouse.x, - _overlay_texture->width(), - _egl_surface_width); - event.mouse.y = scalef(event.mouse.y, - _overlay_texture->height(), - _egl_surface_height); - } else { - const Common::Rect &r = _game_texture->getDrawRect(); - - event.mouse.x -= r.left; - event.mouse.y -= r.top; - - event.mouse.x = scalef(event.mouse.x, - _game_texture->width(), - r.width()); - event.mouse.y = scalef(event.mouse.y, - _game_texture->height(), - r.height()); - - event.mouse.x -= _shake_offset; - - event.mouse.x = CLIP(event.mouse.x, int16(0), - int16(_game_texture->width())); - event.mouse.y = CLIP(event.mouse.y, int16(0), - int16(_game_texture->height())); - } - } - break; - } - - default: - break; - } - - return true; -} - -void OSystem_Android::pushEvent(const Common::Event& event) { - lockMutex(_event_queue_lock); - - _event_queue.push(event); - - unlockMutex(_event_queue_lock); -} - uint32 OSystem_Android::getMillis() { timeval curTime; diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index dc45f06cb6..7ff96186f9 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -125,9 +125,6 @@ private: bool _fullscreen; bool _ar_correction; - Common::Queue _event_queue; - MutexRef _event_queue_lock; - pthread_t _main_thread; bool _timer_thread_exit; @@ -205,6 +202,25 @@ public: return this; } +public: + void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5); + +private: + Common::Queue _event_queue; + MutexRef _event_queue_lock; + + Common::Point _touch_pt_down, _touch_pt_dt; + int _eventScaleX; + int _eventScaleY; + bool _touchpad_mode; + int _touchpad_scale; + int _trackball_scale; + int _dpad_scale; + + void clipMouse(Common::Point &p); + void scaleMouse(Common::Point &p, int x, int y, bool deductDrawRect = true); + void updateEventScale(); + protected: // PaletteManager API virtual void setPalette(const byte *colors, uint start, uint num); @@ -242,7 +258,6 @@ public: 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); diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index eb58089376..cb39f8acfe 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -6,6 +6,7 @@ ANDROID_PLUGIN_VERSIONCODE = 6 JAVA_FILES = \ ScummVM.java \ + ScummVMEvents.java \ ScummVMApplication.java \ ScummVMActivity.java \ EditableSurfaceView.java \ diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp new file mode 100644 index 0000000000..1715e6a8a7 --- /dev/null +++ b/backends/platform/android/events.cpp @@ -0,0 +1,661 @@ +/* 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 "common/events.h" + +#include "backends/platform/android/android.h" +#include "backends/platform/android/jni.h" + +// $ANDROID_NDK/platforms/android-9/arch-arm/usr/include/android/keycodes.h +// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=libs/ui/Input.cpp +// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/KeyEvent.java + +// event type +enum { + JE_SYS_KEY = 0, + JE_KEY = 1, + JE_DOWN = 2, + JE_SCROLL = 3, + JE_TAP = 4, + JE_DOUBLE_TAP = 5, + JE_BALL = 6, + JE_QUIT = 0x1000 +}; + +// action type +enum { + JACTION_DOWN = 0, + JACTION_UP = 1, + JACTION_MULTIPLE = 2 +}; + +// system keys +enum { + JKEYCODE_SOFT_RIGHT = 2, + JKEYCODE_HOME = 3, + JKEYCODE_BACK = 4, + JKEYCODE_CALL = 5, + JKEYCODE_ENDCALL = 6, + JKEYCODE_VOLUME_UP = 24, + JKEYCODE_VOLUME_DOWN = 25, + JKEYCODE_POWER = 26, + JKEYCODE_CAMERA = 27, + JKEYCODE_HEADSETHOOK = 79, + JKEYCODE_FOCUS = 80, + JKEYCODE_MENU = 82, + JKEYCODE_SEARCH = 84, + JKEYCODE_MUTE = 91, + JKEYCODE_MEDIA_PLAY_PAUSE = 85, + JKEYCODE_MEDIA_STOP = 86, + JKEYCODE_MEDIA_NEXT = 87, + JKEYCODE_MEDIA_PREVIOUS = 88, + JKEYCODE_MEDIA_REWIND = 89, + JKEYCODE_MEDIA_FAST_FORWARD = 90 +}; + +// five-way navigation control +enum { + JKEYCODE_DPAD_UP = 19, + JKEYCODE_DPAD_DOWN = 20, + JKEYCODE_DPAD_LEFT = 21, + JKEYCODE_DPAD_RIGHT = 22, + JKEYCODE_DPAD_CENTER = 23 +}; + +// meta modifier +enum { + JMETA_SHIFT = 0x01, + JMETA_ALT = 0x02, + JMETA_SYM = 0x04, + JMETA_CTRL = 0x1000 +}; + +// map android key codes to our kbd codes +static const Common::KeyCode jkeymap[] = { + Common::KEYCODE_INVALID, // KEYCODE_UNKNOWN + Common::KEYCODE_INVALID, // KEYCODE_SOFT_LEFT + Common::KEYCODE_INVALID, // KEYCODE_SOFT_RIGHT + Common::KEYCODE_INVALID, // KEYCODE_HOME + Common::KEYCODE_INVALID, // KEYCODE_BACK + Common::KEYCODE_INVALID, // KEYCODE_CALL + Common::KEYCODE_INVALID, // KEYCODE_ENDCALL + Common::KEYCODE_0, // KEYCODE_0 + Common::KEYCODE_1, // KEYCODE_1 + Common::KEYCODE_2, // KEYCODE_2 + Common::KEYCODE_3, // KEYCODE_3 + Common::KEYCODE_4, // KEYCODE_4 + Common::KEYCODE_5, // KEYCODE_5 + Common::KEYCODE_6, // KEYCODE_6 + Common::KEYCODE_7, // KEYCODE_7 + Common::KEYCODE_8, // KEYCODE_8 + Common::KEYCODE_9, // KEYCODE_9 + Common::KEYCODE_ASTERISK, // KEYCODE_STAR + Common::KEYCODE_HASH, // KEYCODE_POUND + Common::KEYCODE_INVALID, // KEYCODE_DPAD_UP + Common::KEYCODE_INVALID, // KEYCODE_DPAD_DOWN + Common::KEYCODE_INVALID, // KEYCODE_DPAD_LEFT + Common::KEYCODE_INVALID, // KEYCODE_DPAD_RIGHT + Common::KEYCODE_INVALID, // KEYCODE_DPAD_CENTER + Common::KEYCODE_INVALID, // KEYCODE_VOLUME_UP + Common::KEYCODE_INVALID, // KEYCODE_VOLUME_DOWN + Common::KEYCODE_INVALID, // KEYCODE_POWER + Common::KEYCODE_INVALID, // KEYCODE_CAMERA + Common::KEYCODE_INVALID, // KEYCODE_CLEAR + Common::KEYCODE_a, // KEYCODE_A + Common::KEYCODE_b, // KEYCODE_B + Common::KEYCODE_c, // KEYCODE_C + Common::KEYCODE_d, // KEYCODE_D + Common::KEYCODE_e, // KEYCODE_E + Common::KEYCODE_f, // KEYCODE_F + Common::KEYCODE_g, // KEYCODE_G + Common::KEYCODE_h, // KEYCODE_H + Common::KEYCODE_i, // KEYCODE_I + Common::KEYCODE_j, // KEYCODE_J + Common::KEYCODE_k, // KEYCODE_K + Common::KEYCODE_l, // KEYCODE_L + Common::KEYCODE_m, // KEYCODE_M + Common::KEYCODE_n, // KEYCODE_N + Common::KEYCODE_o, // KEYCODE_O + Common::KEYCODE_p, // KEYCODE_P + Common::KEYCODE_q, // KEYCODE_Q + Common::KEYCODE_r, // KEYCODE_R + Common::KEYCODE_s, // KEYCODE_S + Common::KEYCODE_t, // KEYCODE_T + Common::KEYCODE_u, // KEYCODE_U + Common::KEYCODE_v, // KEYCODE_V + Common::KEYCODE_w, // KEYCODE_W + Common::KEYCODE_x, // KEYCODE_X + Common::KEYCODE_y, // KEYCODE_Y + Common::KEYCODE_z, // KEYCODE_Z + Common::KEYCODE_COMMA, // KEYCODE_COMMA + Common::KEYCODE_PERIOD, // KEYCODE_PERIOD + Common::KEYCODE_LALT, // KEYCODE_ALT_LEFT + Common::KEYCODE_RALT, // KEYCODE_ALT_RIGHT + Common::KEYCODE_LSHIFT, // KEYCODE_SHIFT_LEFT + Common::KEYCODE_RSHIFT, // KEYCODE_SHIFT_RIGHT + Common::KEYCODE_TAB, // KEYCODE_TAB + Common::KEYCODE_SPACE, // KEYCODE_SPACE + Common::KEYCODE_LCTRL, // KEYCODE_SYM + Common::KEYCODE_INVALID, // KEYCODE_EXPLORER + Common::KEYCODE_INVALID, // KEYCODE_ENVELOPE + Common::KEYCODE_RETURN, // KEYCODE_ENTER + Common::KEYCODE_BACKSPACE, // KEYCODE_DEL + Common::KEYCODE_BACKQUOTE, // KEYCODE_GRAVE + Common::KEYCODE_MINUS, // KEYCODE_MINUS + Common::KEYCODE_EQUALS, // KEYCODE_EQUALS + Common::KEYCODE_LEFTPAREN, // KEYCODE_LEFT_BRACKET + Common::KEYCODE_RIGHTPAREN, // KEYCODE_RIGHT_BRACKET + Common::KEYCODE_BACKSLASH, // KEYCODE_BACKSLASH + Common::KEYCODE_SEMICOLON, // KEYCODE_SEMICOLON + Common::KEYCODE_QUOTE, // KEYCODE_APOSTROPHE + Common::KEYCODE_SLASH, // KEYCODE_SLASH + Common::KEYCODE_AT, // KEYCODE_AT + Common::KEYCODE_INVALID, // KEYCODE_NUM + Common::KEYCODE_INVALID, // KEYCODE_HEADSETHOOK + Common::KEYCODE_INVALID, // KEYCODE_FOCUS + Common::KEYCODE_PLUS, // KEYCODE_PLUS + Common::KEYCODE_INVALID, // KEYCODE_MENU + Common::KEYCODE_INVALID, // KEYCODE_NOTIFICATION + Common::KEYCODE_INVALID, // KEYCODE_SEARCH + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PLAY_PAUSE + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_STOP + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_NEXT + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PREVIOUS + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_REWIND + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_FAST_FORWARD + Common::KEYCODE_INVALID, // KEYCODE_MUTE + Common::KEYCODE_PAGEUP, // KEYCODE_PAGE_UP + Common::KEYCODE_PAGEDOWN // KEYCODE_PAGE_DOWN +}; + +// floating point. use sparingly +template +static inline T scalef(T in, float numerator, float denominator) { + return static_cast(in) * numerator / denominator; +} + +void OSystem_Android::setupKeymapper() { +#ifdef ENABLE_KEYMAPPER + using namespace Common; + + Keymapper *mapper = getEventManager()->getKeymapper(); + + HardwareKeySet *keySet = new HardwareKeySet(); + + keySet->addHardwareKey( + new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)", + kTriggerLeftKeyType, + kVirtualKeyboardActionType)); + + mapper->registerHardwareKeySet(keySet); + + Keymap *globalMap = new Keymap("global"); + Action *act; + + act = new Action(globalMap, "VIRT", "Display keyboard", + kVirtualKeyboardActionType); + act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0)); + + mapper->addGlobalKeymap(globalMap); + + mapper->pushKeymap("global"); +#endif +} + +void OSystem_Android::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); + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); +} + +void OSystem_Android::clipMouse(Common::Point &p) { + const GLESBaseTexture *tex; + + if (_show_overlay) + tex = _overlay_texture; + else + tex = _game_texture; + + p.x = CLIP(p.x, int16(0), int16(tex->width())); + p.y = CLIP(p.y, int16(0), int16(tex->height())); +} + +void OSystem_Android::scaleMouse(Common::Point &p, int x, int y, + bool deductDrawRect) { + const GLESBaseTexture *tex; + + if (_show_overlay) + tex = _overlay_texture; + else + tex = _game_texture; + + const Common::Rect &r = tex->getDrawRect(); + + if (_touchpad_mode) { + x = x * 100 / _touchpad_scale; + y = y * 100 / _touchpad_scale; + } + + if (deductDrawRect) { + x -= r.left; + y -= r.top; + } + + p.x = scalef(x, tex->width(), r.width()); + p.y = scalef(y, tex->height(), r.height()); +} + +void OSystem_Android::updateEventScale() { + const GLESBaseTexture *tex; + + if (_show_overlay) + tex = _overlay_texture; + else + tex = _game_texture; + + _eventScaleY = 100 * 480 / tex->height(); + _eventScaleX = 100 * 640 / tex->width(); +} + +void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, + int arg4, int arg5) { + Common::Event e; + + switch (type) { + case JE_SYS_KEY: + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_KEYDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_KEYUP; + break; + default: + LOGE("unhandled jaction on system key: %d", arg1); + return; + } + + switch (arg2) { + case JKEYCODE_BACK: + e.kbd.keycode = Common::KEYCODE_ESCAPE; + e.kbd.ascii = Common::ASCII_ESCAPE; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + // special case. we'll only get it's up event + case JKEYCODE_MENU: + e.type = Common::EVENT_MAINMENU; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + default: + LOGW("unmapped system key: %d", arg2); + return; + } + + break; + + case JE_KEY: + // five-way first + switch (arg2) { + case JKEYCODE_DPAD_UP: + case JKEYCODE_DPAD_DOWN: + case JKEYCODE_DPAD_LEFT: + case JKEYCODE_DPAD_RIGHT: + { + if (arg1 != JACTION_DOWN) + return; + + e.type = Common::EVENT_MOUSEMOVE; + e.synthetic = true; + + e.mouse = getEventManager()->getMousePos(); + + int16 *c; + int s; + + if (arg2 == JKEYCODE_DPAD_UP || arg2 == JKEYCODE_DPAD_DOWN) { + c = &e.mouse.y; + s = _eventScaleY; + } else { + c = &e.mouse.x; + s = _eventScaleX; + } + + // the longer the button held, the faster the pointer is + // TODO put these values in some option dlg? + int f = CLIP(arg5, 1, 8) * _dpad_scale * 100 / s; + + *c += ((arg2 == JKEYCODE_DPAD_UP || + arg2 == JKEYCODE_DPAD_LEFT) ? -1 : 1) * f; + + clipMouse(e.mouse); + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + } + + return; + + case JKEYCODE_DPAD_CENTER: + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_LBUTTONDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_LBUTTONUP; + break; + default: + LOGE("unhandled jaction on dpad key: %d", arg1); + return; + } + + { + const Common::Point &m = getEventManager()->getMousePos(); + + e.mouse = m; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + } + + return; + } + + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_KEYDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_KEYUP; + break; + default: + LOGE("unhandled jaction on key: %d", arg1); + return; + } + + if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) { + LOGE("received invalid keycode: %d", arg2); + return; + } + + if (arg5 > 0) + e.synthetic = true; + + e.kbd.keycode = jkeymap[arg2]; + e.kbd.ascii = arg3; + + if (arg4 & JMETA_SHIFT) + e.kbd.flags |= Common::KBD_SHIFT; + if (arg4 & JMETA_ALT) + e.kbd.flags |= Common::KBD_ALT; + if (arg4 & (JMETA_SYM | JMETA_CTRL)) + e.kbd.flags |= Common::KBD_CTRL; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_DOWN: + _touch_pt_down = getEventManager()->getMousePos(); + break; + + case JE_SCROLL: + e.type = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + scaleMouse(e.mouse, arg3 - arg1, arg4 - arg2, false); + e.mouse += _touch_pt_down; + clipMouse(e.mouse); + } else { + scaleMouse(e.mouse, arg3, arg4); + clipMouse(e.mouse); + } + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_TAP: + e.type = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + e.mouse = getEventManager()->getMousePos(); + } else { + scaleMouse(e.mouse, arg1, arg2); + clipMouse(e.mouse); + } + + { + Common::EventType down, up; + + // TODO put these values in some option dlg? + if (arg3 > 1000) { + down = Common::EVENT_MBUTTONDOWN; + up = Common::EVENT_MBUTTONUP; + } else if (arg3 > 500) { + down = Common::EVENT_RBUTTONDOWN; + up = Common::EVENT_RBUTTONUP; + } else { + down = Common::EVENT_LBUTTONDOWN; + up = Common::EVENT_LBUTTONUP; + } + + lockMutex(_event_queue_lock); + + if (!_touchpad_mode) + _event_queue.push(e); + + e.type = down; + _event_queue.push(e); + e.type = up; + _event_queue.push(e); + + unlockMutex(_event_queue_lock); + } + + return; + + case JE_DOUBLE_TAP: + e.type = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + e.mouse = getEventManager()->getMousePos(); + } else { + scaleMouse(e.mouse, arg1, arg2); + clipMouse(e.mouse); + } + + { + Common::EventType dptype = Common::EVENT_INVALID; + + switch (arg3) { + case JACTION_DOWN: + dptype = Common::EVENT_LBUTTONDOWN; + _touch_pt_dt.x = arg1; + _touch_pt_dt.y = arg2; + break; + case JACTION_UP: + dptype = Common::EVENT_LBUTTONUP; + break; + case JACTION_MULTIPLE: + // held and moved + dptype = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + scaleMouse(e.mouse, arg1 - _touch_pt_dt.x, + arg2 - _touch_pt_dt.y, false); + e.mouse += _touch_pt_down; + + clipMouse(e.mouse); + } + + break; + default: + LOGE("unhandled jaction on double tap: %d", arg3); + return; + } + + lockMutex(_event_queue_lock); + _event_queue.push(e); + e.type = dptype; + _event_queue.push(e); + unlockMutex(_event_queue_lock); + } + + return; + + case JE_BALL: + e.type = Common::EVENT_MOUSEMOVE; + + e.mouse = getEventManager()->getMousePos(); + + // already multiplied by 100 + e.mouse.x += arg1 * _trackball_scale / _eventScaleX; + e.mouse.y += arg2 * _trackball_scale / _eventScaleY; + + clipMouse(e.mouse); + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_QUIT: + e.type = Common::EVENT_QUIT; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + default: + LOGE("unknown jevent type: %d", type); + + break; + } +} + +bool OSystem_Android::pollEvent(Common::Event &event) { + //ENTER(); + + if (pthread_self() == _main_thread) { + if (_screen_changeid != JNI::surface_changeid) { + if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { + if (_egl_surface_width > 0 && _egl_surface_height > 0) { + // surface still alive but changed + _screen_changeid = JNI::surface_changeid; + _egl_surface_width = JNI::egl_surface_width; + _egl_surface_height = JNI::egl_surface_height; + + initViewport(); + updateScreenRect(); + updateEventScale(); + + // double buffered, flip twice + clearScreen(kClearUpdate, 2); + + event.type = Common::EVENT_SCREEN_CHANGED; + + return true; + } else { + // new surface + initSurface(); + updateScreenRect(); + updateEventScale(); + + // double buffered, flip twice + clearScreen(kClearUpdate, 2); + + event.type = Common::EVENT_SCREEN_CHANGED; + + return true; + } + } else { + // surface lost + deinitSurface(); + } + } + + if (JNI::pause) { + deinitSurface(); + + LOGD("main thread going to sleep"); + sem_wait(&JNI::pause_sem); + LOGD("main thread woke up"); + } + } + + lockMutex(_event_queue_lock); + + if (_event_queue.empty()) { + unlockMutex(_event_queue_lock); + return false; + } + + event = _event_queue.pop(); + + unlockMutex(_event_queue_lock); + + if (event.type == Common::EVENT_MOUSEMOVE) { + const Common::Point &m = getEventManager()->getMousePos(); + + if (m != event.mouse) + _force_redraw = true; + } + + return true; +} + +#endif + diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 65f98d5094..fc45f4c9e1 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -272,6 +272,7 @@ void OSystem_Android::initSize(uint width, uint height, #endif updateScreenRect(); + updateEventScale(); // Don't know mouse size yet - it gets reallocated in // setMouseCursor. We need the palette allocated before @@ -285,17 +286,13 @@ void OSystem_Android::initSize(uint width, uint height, void OSystem_Android::clearScreen(FixupType type, byte count) { assert(count > 0); - for (byte i = 0; i < count; ++i) { - if (!_show_overlay) - GLCALL(glDisable(GL_SCISSOR_TEST)); + GLCALL(glDisable(GL_SCISSOR_TEST)); + for (byte i = 0; i < count; ++i) { // clear screen GLCALL(glClearColorx(0, 0, 0, 1 << 16)); GLCALL(glClear(GL_COLOR_BUFFER_BIT)); - if (!_show_overlay) - GLCALL(glEnable(GL_SCISSOR_TEST)); - switch (type) { case kClear: break; @@ -310,6 +307,9 @@ void OSystem_Android::clearScreen(FixupType type, byte count) { break; } } + + if (!_show_overlay) + GLCALL(glEnable(GL_SCISSOR_TEST)); } void OSystem_Android::updateScreenRect() { @@ -577,34 +577,27 @@ void OSystem_Android::clearFocusRectangle() { void OSystem_Android::showOverlay() { ENTER(); - Common::Event e; - e.type = Common::EVENT_MOUSEMOVE; - e.mouse.x = _egl_surface_width / 2; - e.mouse.y = _egl_surface_height / 2; - - pushEvent(e); - _show_overlay = true; _force_redraw = true; + updateEventScale(); + + warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2); + GLCALL(glDisable(GL_SCISSOR_TEST)); } void OSystem_Android::hideOverlay() { ENTER(); - Common::Event e; - e.type = Common::EVENT_MOUSEMOVE; - e.mouse.x = _egl_surface_width / 2; - e.mouse.y = _egl_surface_height / 2; - - pushEvent(e); + clearScreen(kClear); _show_overlay = false; _force_redraw = true; - // double buffered, flip twice - clearScreen(kClearUpdate, 2); + updateEventScale(); + + warpMouse(_game_texture->width() / 2, _game_texture->height() / 2); GLCALL(glEnable(GL_SCISSOR_TEST)); } @@ -673,13 +666,6 @@ bool OSystem_Android::showMouse(bool 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, @@ -719,8 +705,10 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0); } - if (w == 0 || h == 0) + if (w == 0 || h == 0) { + _show_mouse = false; return; + } if (_mouse_texture == _mouse_texture_palette) { _mouse_texture->updateBuffer(0, 0, w, h, buf, w); @@ -737,7 +725,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, delete[] tmp; - _mouse_texture->fillBuffer(0); + _show_mouse = false; return; } diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 0628d92a2f..92cb04904c 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -56,15 +56,6 @@ int JNI::egl_surface_width = 0; int JNI::egl_surface_height = 0; bool JNI::_ready_for_events = 0; -jfieldID JNI::_FID_Event_type = 0; -jfieldID JNI::_FID_Event_synthetic = 0; -jfieldID JNI::_FID_Event_kbd_keycode = 0; -jfieldID JNI::_FID_Event_kbd_ascii = 0; -jfieldID JNI::_FID_Event_kbd_flags = 0; -jfieldID JNI::_FID_Event_mouse_x = 0; -jfieldID JNI::_FID_Event_mouse_y = 0; -jfieldID JNI::_FID_Event_mouse_relative = 0; - jmethodID JNI::_MID_getDPI = 0; jmethodID JNI::_MID_displayMessageOnOSD = 0; jmethodID JNI::_MID_setWindowCaption = 0; @@ -94,7 +85,7 @@ const JNINativeMethod JNI::_natives[] = { (void *)JNI::setSurface }, { "main", "([Ljava/lang/String;)I", (void *)JNI::main }, - { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", + { "pushEvent", "(IIIIII)V", (void *)JNI::pushEvent }, { "enableZoning", "(Z)V", (void *)JNI::enableZoning }, @@ -123,42 +114,6 @@ jint JNI::onLoad(JavaVM *vm) { if (env->RegisterNatives(cls, _natives, ARRAYSIZE(_natives)) < 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; - return JNI_VERSION_1_2; } @@ -600,54 +555,17 @@ cleanup: return res; } -void JNI::pushEvent(JNIEnv *env, jobject self, jobject java_event) { +void JNI::pushEvent(JNIEnv *env, jobject self, int type, int arg1, int arg2, + int arg3, int arg4, int arg5) { // drop events until we're ready and after we quit - if (!_ready_for_events) + if (!_ready_for_events) { + LOGW("dropping event"); return; + } assert(_system); - 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(env->GetIntField( - java_event, _FID_Event_kbd_ascii)); - event.kbd.flags = static_cast(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; - } - - _system->pushEvent(event); + _system->pushEvent(type, arg1, arg2, arg3, arg4, arg5); } void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h index 5746c01afd..d029f1a2a8 100644 --- a/backends/platform/android/jni.h +++ b/backends/platform/android/jni.h @@ -91,16 +91,6 @@ private: static bool _ready_for_events; - 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_getDPI; static jmethodID _MID_displayMessageOnOSD; static jmethodID _MID_setWindowCaption; @@ -133,7 +123,8 @@ private: static void setSurface(JNIEnv *env, jobject self, jint width, jint height); static jint main(JNIEnv *env, jobject self, jobjectArray args); - static void pushEvent(JNIEnv *env, jobject self, jobject java_event); + static void pushEvent(JNIEnv *env, jobject self, int type, int arg1, + int arg2, int arg3, int arg4, int arg5); static void enableZoning(JNIEnv *env, jobject self, jboolean enable); static void setPause(JNIEnv *env, jobject self, jboolean value); diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk index 3bcfa7ad87..2fe4b40585 100644 --- a/backends/platform/android/module.mk +++ b/backends/platform/android/module.mk @@ -5,7 +5,8 @@ MODULE_OBJS := \ texture.o \ asset-archive.o \ android.o \ - gfx.o + gfx.o \ + events.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/inodes/gus/scummvm/Event.java b/backends/platform/android/org/inodes/gus/scummvm/Event.java deleted file mode 100644 index f9c7aba93b..0000000000 --- a/backends/platform/android/org/inodes/gus/scummvm/Event.java +++ /dev/null @@ -1,330 +0,0 @@ -package org.inodes.gus.scummvm; - -import android.view.KeyEvent; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class Event { - // Common::EventType enum. - // Must be kept in sync with common/events.h - public final static int EVENT_INVALID = 0; - public final static int EVENT_KEYDOWN = 1; - public final static int EVENT_KEYUP = 2; - public final static int EVENT_MOUSEMOVE = 3; - public final static int EVENT_LBUTTONDOWN = 4; - public final static int EVENT_LBUTTONUP = 5; - public final static int EVENT_RBUTTONDOWN = 6; - public final static int EVENT_RBUTTONUP = 7; - public final static int EVENT_WHEELUP = 8; - public final static int EVENT_WHEELDOWN = 9; - public final static int EVENT_QUIT = 10; - public final static int EVENT_SCREEN_CHANGED = 11; - public final static int EVENT_PREDICTIVE_DIALOG = 12; - public final static int EVENT_MBUTTONDOWN = 13; - public final static int EVENT_MBUTTONUP = 14; - public final static int EVENT_MAINMENU = 15; - public final static int EVENT_RTL = 16; - - // common/keyboard.h - public final static int ASCII_F1 = 315; - public final static int ASCII_F2 = 316; - public final static int ASCII_F3 = 317; - public final static int ASCII_F4 = 318; - public final static int ASCII_F5 = 319; - public final static int ASCII_F6 = 320; - public final static int ASCII_F7 = 321; - public final static int ASCII_F8 = 322; - public final static int ASCII_F9 = 323; - public final static int ASCII_F10 = 324; - public final static int ASCII_F11 = 325; - public final static int ASCII_F12 = 326; - public final static int KBD_CTRL = 1 << 0; - public final static int KBD_ALT = 1 << 1; - public final static int KBD_SHIFT = 1 << 2; - - public final static int KEYCODE_INVALID = 0; - public final static int KEYCODE_BACKSPACE = 8; - public final static int KEYCODE_TAB = 9; - public final static int KEYCODE_CLEAR = 12; - public final static int KEYCODE_RETURN = 13; - public final static int KEYCODE_PAUSE = 19; - public final static int KEYCODE_ESCAPE = 27; - public final static int KEYCODE_SPACE = 32; - public final static int KEYCODE_EXCLAIM = 33; - public final static int KEYCODE_QUOTEDBL = 34; - public final static int KEYCODE_HASH = 35; - public final static int KEYCODE_DOLLAR = 36; - public final static int KEYCODE_AMPERSAND = 38; - public final static int KEYCODE_QUOTE = 39; - public final static int KEYCODE_LEFTPAREN = 40; - public final static int KEYCODE_RIGHTPAREN = 41; - public final static int KEYCODE_ASTERISK = 42; - public final static int KEYCODE_PLUS = 43; - public final static int KEYCODE_COMMA = 44; - public final static int KEYCODE_MINUS = 45; - public final static int KEYCODE_PERIOD = 46; - public final static int KEYCODE_SLASH = 47; - public final static int KEYCODE_0 = 48; - public final static int KEYCODE_1 = 49; - public final static int KEYCODE_2 = 50; - public final static int KEYCODE_3 = 51; - public final static int KEYCODE_4 = 52; - public final static int KEYCODE_5 = 53; - public final static int KEYCODE_6 = 54; - public final static int KEYCODE_7 = 55; - public final static int KEYCODE_8 = 56; - public final static int KEYCODE_9 = 57; - public final static int KEYCODE_COLON = 58; - public final static int KEYCODE_SEMICOLON = 59; - public final static int KEYCODE_LESS = 60; - public final static int KEYCODE_EQUALS = 61; - public final static int KEYCODE_GREATER = 62; - public final static int KEYCODE_QUESTION = 63; - public final static int KEYCODE_AT = 64; - public final static int KEYCODE_LEFTBRACKET = 91; - public final static int KEYCODE_BACKSLASH = 92; - public final static int KEYCODE_RIGHTBRACKET = 93; - public final static int KEYCODE_CARET = 94; - public final static int KEYCODE_UNDERSCORE = 95; - public final static int KEYCODE_BACKQUOTE = 96; - public final static int KEYCODE_a = 97; - public final static int KEYCODE_b = 98; - public final static int KEYCODE_c = 99; - public final static int KEYCODE_d = 100; - public final static int KEYCODE_e = 101; - public final static int KEYCODE_f = 102; - public final static int KEYCODE_g = 103; - public final static int KEYCODE_h = 104; - public final static int KEYCODE_i = 105; - public final static int KEYCODE_j = 106; - public final static int KEYCODE_k = 107; - public final static int KEYCODE_l = 108; - public final static int KEYCODE_m = 109; - public final static int KEYCODE_n = 110; - public final static int KEYCODE_o = 111; - public final static int KEYCODE_p = 112; - public final static int KEYCODE_q = 113; - public final static int KEYCODE_r = 114; - public final static int KEYCODE_s = 115; - public final static int KEYCODE_t = 116; - public final static int KEYCODE_u = 117; - public final static int KEYCODE_v = 118; - public final static int KEYCODE_w = 119; - public final static int KEYCODE_x = 120; - public final static int KEYCODE_y = 121; - public final static int KEYCODE_z = 122; - public final static int KEYCODE_DELETE = 127; - // Numeric keypad - public final static int KEYCODE_KP0 = 256; - public final static int KEYCODE_KP1 = 257; - public final static int KEYCODE_KP2 = 258; - public final static int KEYCODE_KP3 = 259; - public final static int KEYCODE_KP4 = 260; - public final static int KEYCODE_KP5 = 261; - public final static int KEYCODE_KP6 = 262; - public final static int KEYCODE_KP7 = 263; - public final static int KEYCODE_KP8 = 264; - public final static int KEYCODE_KP9 = 265; - public final static int KEYCODE_KP_PERIOD = 266; - public final static int KEYCODE_KP_DIVIDE = 267; - public final static int KEYCODE_KP_MULTIPLY = 268; - public final static int KEYCODE_KP_MINUS = 269; - public final static int KEYCODE_KP_PLUS = 270; - public final static int KEYCODE_KP_ENTER = 271; - public final static int KEYCODE_KP_EQUALS = 272; - // Arrows + Home/End pad - public final static int KEYCODE_UP = 273; - public final static int KEYCODE_DOWN = 274; - public final static int KEYCODE_RIGHT = 275; - public final static int KEYCODE_LEFT = 276; - public final static int KEYCODE_INSERT = 277; - public final static int KEYCODE_HOME = 278; - public final static int KEYCODE_END = 279; - public final static int KEYCODE_PAGEUP = 280; - public final static int KEYCODE_PAGEDOWN = 281; - // Function keys - public final static int KEYCODE_F1 = 282; - public final static int KEYCODE_F2 = 283; - public final static int KEYCODE_F3 = 284; - public final static int KEYCODE_F4 = 285; - public final static int KEYCODE_F5 = 286; - public final static int KEYCODE_F6 = 287; - public final static int KEYCODE_F7 = 288; - public final static int KEYCODE_F8 = 289; - public final static int KEYCODE_F9 = 290; - public final static int KEYCODE_F10 = 291; - public final static int KEYCODE_F11 = 292; - public final static int KEYCODE_F12 = 293; - public final static int KEYCODE_F13 = 294; - public final static int KEYCODE_F14 = 295; - public final static int KEYCODE_F15 = 296; - // Key state modifier keys - public final static int KEYCODE_NUMLOCK = 300; - public final static int KEYCODE_CAPSLOCK = 301; - public final static int KEYCODE_SCROLLOCK = 302; - public final static int KEYCODE_RSHIFT = 303; - public final static int KEYCODE_LSHIFT = 304; - public final static int KEYCODE_RCTRL = 305; - public final static int KEYCODE_LCTRL = 306; - public final static int KEYCODE_RALT = 307; - public final static int KEYCODE_LALT = 308; - public final static int KEYCODE_RMETA = 309; - public final static int KEYCODE_LMETA = 310; - public final static int KEYCODE_LSUPER = 311; // Left "Windows" key - public final static int KEYCODE_RSUPER = 312; // Right "Windows" key - public final static int KEYCODE_MODE = 313; // "Alt Gr" key - public final static int KEYCODE_COMPOSE = 314; // Multi-key compose key - // Miscellaneous function keys - public final static int KEYCODE_HELP = 315; - public final static int KEYCODE_PRINT = 316; - public final static int KEYCODE_SYSREQ = 317; - public final static int KEYCODE_BREAK = 318; - public final static int KEYCODE_MENU = 319; - public final static int KEYCODE_POWER = 320; // Power Macintosh power key - public final static int KEYCODE_EURO = 321; // Some european keyboards - public final static int KEYCODE_UNDO = 322; // Atari keyboard has Undo - - // Android KeyEvent keycode -> ScummVM keycode - public final static Map androidKeyMap; - static { - Map map = new HashMap(); - - map.put(KeyEvent.KEYCODE_DEL, KEYCODE_BACKSPACE); - map.put(KeyEvent.KEYCODE_TAB, KEYCODE_TAB); - map.put(KeyEvent.KEYCODE_CLEAR, KEYCODE_CLEAR); - map.put(KeyEvent.KEYCODE_ENTER, KEYCODE_RETURN); - //map.put(??, KEYCODE_PAUSE); - map.put(KeyEvent.KEYCODE_BACK, KEYCODE_ESCAPE); - map.put(KeyEvent.KEYCODE_SPACE, KEYCODE_SPACE); - //map.put(??, KEYCODE_EXCLAIM); - //map.put(??, KEYCODE_QUOTEDBL); - map.put(KeyEvent.KEYCODE_POUND, KEYCODE_HASH); - //map.put(??, KEYCODE_DOLLAR); - //map.put(??, KEYCODE_AMPERSAND); - map.put(KeyEvent.KEYCODE_APOSTROPHE, KEYCODE_QUOTE); - //map.put(??, KEYCODE_LEFTPAREN); - //map.put(??, KEYCODE_RIGHTPAREN); - //map.put(??, KEYCODE_ASTERISK); - map.put(KeyEvent.KEYCODE_PLUS, KEYCODE_PLUS); - map.put(KeyEvent.KEYCODE_COMMA, KEYCODE_COMMA); - map.put(KeyEvent.KEYCODE_MINUS, KEYCODE_MINUS); - map.put(KeyEvent.KEYCODE_PERIOD, KEYCODE_PERIOD); - map.put(KeyEvent.KEYCODE_SLASH, KEYCODE_SLASH); - map.put(KeyEvent.KEYCODE_0, KEYCODE_0); - map.put(KeyEvent.KEYCODE_1, KEYCODE_1); - map.put(KeyEvent.KEYCODE_2, KEYCODE_2); - map.put(KeyEvent.KEYCODE_3, KEYCODE_3); - map.put(KeyEvent.KEYCODE_4, KEYCODE_4); - map.put(KeyEvent.KEYCODE_5, KEYCODE_5); - map.put(KeyEvent.KEYCODE_6, KEYCODE_6); - map.put(KeyEvent.KEYCODE_7, KEYCODE_7); - map.put(KeyEvent.KEYCODE_8, KEYCODE_8); - map.put(KeyEvent.KEYCODE_9, KEYCODE_9); - //map.put(??, KEYCODE_COLON); - map.put(KeyEvent.KEYCODE_SEMICOLON, KEYCODE_SEMICOLON); - //map.put(??, KEYCODE_LESS); - map.put(KeyEvent.KEYCODE_EQUALS, KEYCODE_EQUALS); - //map.put(??, KEYCODE_GREATER); - //map.put(??, KEYCODE_QUESTION); - map.put(KeyEvent.KEYCODE_AT, KEYCODE_AT); - map.put(KeyEvent.KEYCODE_LEFT_BRACKET, KEYCODE_LEFTBRACKET); - map.put(KeyEvent.KEYCODE_BACKSLASH, KEYCODE_BACKSLASH); - map.put(KeyEvent.KEYCODE_RIGHT_BRACKET, KEYCODE_RIGHTBRACKET); - //map.put(??, KEYCODE_CARET); - //map.put(??, KEYCODE_UNDERSCORE); - //map.put(??, KEYCODE_BACKQUOTE); - map.put(KeyEvent.KEYCODE_A, KEYCODE_a); - map.put(KeyEvent.KEYCODE_B, KEYCODE_b); - map.put(KeyEvent.KEYCODE_C, KEYCODE_c); - map.put(KeyEvent.KEYCODE_D, KEYCODE_d); - map.put(KeyEvent.KEYCODE_E, KEYCODE_e); - map.put(KeyEvent.KEYCODE_F, KEYCODE_f); - map.put(KeyEvent.KEYCODE_G, KEYCODE_g); - map.put(KeyEvent.KEYCODE_H, KEYCODE_h); - map.put(KeyEvent.KEYCODE_I, KEYCODE_i); - map.put(KeyEvent.KEYCODE_J, KEYCODE_j); - map.put(KeyEvent.KEYCODE_K, KEYCODE_k); - map.put(KeyEvent.KEYCODE_L, KEYCODE_l); - map.put(KeyEvent.KEYCODE_M, KEYCODE_m); - map.put(KeyEvent.KEYCODE_N, KEYCODE_n); - map.put(KeyEvent.KEYCODE_O, KEYCODE_o); - map.put(KeyEvent.KEYCODE_P, KEYCODE_p); - map.put(KeyEvent.KEYCODE_Q, KEYCODE_q); - map.put(KeyEvent.KEYCODE_R, KEYCODE_r); - map.put(KeyEvent.KEYCODE_S, KEYCODE_s); - map.put(KeyEvent.KEYCODE_T, KEYCODE_t); - map.put(KeyEvent.KEYCODE_U, KEYCODE_u); - map.put(KeyEvent.KEYCODE_V, KEYCODE_v); - map.put(KeyEvent.KEYCODE_W, KEYCODE_w); - map.put(KeyEvent.KEYCODE_X, KEYCODE_x); - map.put(KeyEvent.KEYCODE_Y, KEYCODE_y); - map.put(KeyEvent.KEYCODE_Z, KEYCODE_z); - //map.put(KeyEvent.KEYCODE_DEL, KEYCODE_DELETE); use BACKSPACE instead - //map.put(??, KEYCODE_KP_*); - map.put(KeyEvent.KEYCODE_DPAD_UP, KEYCODE_UP); - map.put(KeyEvent.KEYCODE_DPAD_DOWN, KEYCODE_DOWN); - map.put(KeyEvent.KEYCODE_DPAD_RIGHT, KEYCODE_RIGHT); - map.put(KeyEvent.KEYCODE_DPAD_LEFT, KEYCODE_LEFT); - //map.put(??, KEYCODE_INSERT); - //map.put(??, KEYCODE_HOME); - //map.put(??, KEYCODE_END); - //map.put(??, KEYCODE_PAGEUP); - //map.put(??, KEYCODE_PAGEDOWN); - //map.put(??, KEYCODE_F{1-15}); - map.put(KeyEvent.KEYCODE_NUM, KEYCODE_NUMLOCK); - //map.put(??, KEYCODE_CAPSLOCK); - //map.put(??, KEYCODE_SCROLLLOCK); - map.put(KeyEvent.KEYCODE_SHIFT_RIGHT, KEYCODE_RSHIFT); - map.put(KeyEvent.KEYCODE_SHIFT_LEFT, KEYCODE_LSHIFT); - //map.put(??, KEYCODE_RCTRL); - //map.put(??, KEYCODE_LCTRL); - map.put(KeyEvent.KEYCODE_ALT_RIGHT, KEYCODE_RALT); - map.put(KeyEvent.KEYCODE_ALT_LEFT, KEYCODE_LALT); - // ?? META, SUPER - // ?? MODE, COMPOSE - // ?? HELP, PRINT, SYSREQ, BREAK, EURO, UNDO - map.put(KeyEvent.KEYCODE_MENU, KEYCODE_MENU); - map.put(KeyEvent.KEYCODE_POWER, KEYCODE_POWER); - - androidKeyMap = Collections.unmodifiableMap(map); - } - - public int type; - public boolean synthetic; - public int kbd_keycode; - public int kbd_ascii; - public int kbd_flags; - public int mouse_x; - public int mouse_y; - public boolean mouse_relative; // Used for trackball events - - public Event() { - type = EVENT_INVALID; - synthetic = false; - } - - public Event(int type) { - this.type = type; - synthetic = false; - } - - public static Event KeyboardEvent(int type, int keycode, int ascii, - int flags) { - Event e = new Event(); - e.type = type; - e.kbd_keycode = keycode; - e.kbd_ascii = ascii; - e.kbd_flags = flags; - return e; - } - - public static Event MouseEvent(int type, int x, int y) { - Event e = new Event(); - e.type = type; - e.mouse_x = x; - e.mouse_y = y; - return e; - } -} diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index ed4e00d769..fe225af48b 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -9,14 +9,12 @@ import android.media.AudioTrack; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGL11; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import java.io.File; -import java.util.Map; import java.util.LinkedHashMap; public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { @@ -49,7 +47,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { final public native void setPause(boolean pause); final public native void enableZoning(boolean enable); // Feed an event to ScummVM. Safe to call from other threads. - final public native void pushEvent(Event e); + final public native void pushEvent(int type, int arg1, int arg2, int arg3, + int arg4, int arg5); // Callbacks from C++ peer instance abstract protected void getDPI(float[] values); diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 2cf6f58941..1978b690d0 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -3,33 +3,18 @@ package org.inodes.gus.scummvm; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; -import android.content.res.AssetManager; -import android.content.res.Configuration; import android.media.AudioManager; import android.os.Bundle; import android.os.Environment; -import android.os.Handler; -import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; import android.view.SurfaceView; import android.view.SurfaceHolder; -import android.view.View; -import android.view.ViewConfiguration; +import android.view.MotionEvent; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; -import java.io.IOException; - public class ScummVMActivity extends Activity { - private boolean _do_right_click; - private boolean _last_click_was_right; - - // game pixels to move per trackball/dpad event. - // FIXME: replace this with proper mouse acceleration - private final static int TRACKBALL_SCALE = 2; private class MyScummVM extends ScummVM { private boolean usingSmallScreen() { @@ -106,13 +91,13 @@ public class ScummVMActivity extends Activity { } private MyScummVM _scummvm; + private ScummVMEvents _events; private Thread _scummvm_thread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - _do_right_click = false; setVolumeControlStream(AudioManager.STREAM_MUSIC); setContentView(R.layout.main); @@ -139,18 +124,6 @@ public class ScummVMActivity extends Activity { SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); - main_surface.setOnTouchListener(new View.OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - return onTouchEvent(event); - } - }); - - main_surface.setOnKeyListener(new View.OnKeyListener() { - public boolean onKey(View v, int code, KeyEvent ev) { - return onKeyDown(code, ev); - } - }); - main_surface.requestFocus(); getFilesDir().mkdirs(); @@ -166,6 +139,11 @@ public class ScummVMActivity extends Activity { "--savepath=" + getDir("saves", 0).getPath() }); + _events = new ScummVMEvents(this, _scummvm); + + main_surface.setOnKeyListener(_events); + main_surface.setOnTouchListener(_events); + _scummvm_thread = new Thread(_scummvm, "ScummVM"); _scummvm_thread.start(); } @@ -210,8 +188,8 @@ public class ScummVMActivity extends Activity { super.onDestroy(); - if (_scummvm != null) { - _scummvm.pushEvent(new Event(Event.EVENT_QUIT)); + if (_events != null) { + _events.sendQuitEvent(); try { // 1s timeout @@ -224,259 +202,12 @@ public class ScummVMActivity extends Activity { } } - static final int MSG_MENU_LONG_PRESS = 1; - - private final Handler keycodeMenuTimeoutHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (msg.what == MSG_MENU_LONG_PRESS) { - InputMethodManager imm = (InputMethodManager) - getSystemService(INPUT_METHOD_SERVICE); - if (imm != null) - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); - } - } - }; - - @Override - public boolean onKeyUp(int keyCode, KeyEvent kevent) { - return onKeyDown(keyCode, kevent); - } - - @Override - public boolean onKeyMultiple(int keyCode, int repeatCount, - KeyEvent kevent) { - return onKeyDown(keyCode, kevent); - } - @Override - public boolean onKeyDown(int keyCode, KeyEvent kevent) { - // Filter out "special" keys - switch (keyCode) { - case KeyEvent.KEYCODE_MENU: - // Have to reimplement hold-down-menu-brings-up-softkeybd - // ourselves, since we are otherwise hijacking the menu key :( - // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel() - // for the usual Android implementation of this feature. - - // Ignore keyrepeat for menu - if (kevent.getRepeatCount() > 0) - return false; - - boolean timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS); - keycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - - if (kevent.getAction() == KeyEvent.ACTION_DOWN) { - keycodeMenuTimeoutHandler.sendMessageDelayed(keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); - return true; - } - - if (kevent.getAction() == KeyEvent.ACTION_UP) { - if (!timeout_fired) - _scummvm.pushEvent(new Event(Event.EVENT_MAINMENU)); - - return true; - } - - return false; - - case KeyEvent.KEYCODE_CAMERA: - case KeyEvent.KEYCODE_SEARCH: - _do_right_click = (kevent.getAction() == KeyEvent.ACTION_DOWN); - return true; - - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: { - // HTC Hero doesn't seem to generate - // MotionEvent.ACTION_DOWN events on trackball press :( - // We'll have to just fake one here. - // Some other handsets lack a trackball, so the DPAD is - // the only way of moving the cursor. - int motion_action; - - // FIXME: this logic is a mess. - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { - switch (kevent.getAction()) { - case KeyEvent.ACTION_DOWN: - motion_action = MotionEvent.ACTION_DOWN; - break; - - case KeyEvent.ACTION_UP: - motion_action = MotionEvent.ACTION_UP; - break; - - // ACTION_MULTIPLE - default: - return false; - } - } else { - motion_action = MotionEvent.ACTION_MOVE; - } - - Event e = new Event(getEventType(motion_action)); - - e.mouse_x = 0; - e.mouse_y = 0; - e.mouse_relative = true; - - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - e.mouse_y = -TRACKBALL_SCALE; - break; - - case KeyEvent.KEYCODE_DPAD_DOWN: - e.mouse_y = TRACKBALL_SCALE; - break; - - case KeyEvent.KEYCODE_DPAD_LEFT: - e.mouse_x = -TRACKBALL_SCALE; - break; - - case KeyEvent.KEYCODE_DPAD_RIGHT: - e.mouse_x = TRACKBALL_SCALE; - break; - } - - _scummvm.pushEvent(e); - - return true; - } - - case KeyEvent.KEYCODE_BACK: - // skip isSystem() check and fall through to main code - break; - - default: - if (kevent.isSystem()) - return false; - } - - // FIXME: what do I need to do for composed characters? - - Event e = new Event(); - - switch (kevent.getAction()) { - case KeyEvent.ACTION_DOWN: - e.type = Event.EVENT_KEYDOWN; - e.synthetic = false; - break; - - case KeyEvent.ACTION_UP: - e.type = Event.EVENT_KEYUP; - e.synthetic = false; - break; - - case KeyEvent.ACTION_MULTIPLE: - // e.type is handled below - e.synthetic = true; - break; - - default: - return false; - } - - e.kbd_keycode = Event.androidKeyMap.containsKey(keyCode) ? - Event.androidKeyMap.get(keyCode) : Event.KEYCODE_INVALID; - - e.kbd_ascii = kevent.getUnicodeChar(); - - if (e.kbd_ascii == 0) - e.kbd_ascii = e.kbd_keycode; // scummvm keycodes are mostly ascii - - e.kbd_flags = 0; - - if (kevent.isAltPressed()) - e.kbd_flags |= Event.KBD_ALT; - - // no ctrl key in android, so use sym (?) - if (kevent.isSymPressed()) - e.kbd_flags |= Event.KBD_CTRL; - - if (kevent.isShiftPressed()) { - if (keyCode >= KeyEvent.KEYCODE_0 && - keyCode <= KeyEvent.KEYCODE_9) { - // Shift+number -> convert to F* key - int offset = keyCode == KeyEvent.KEYCODE_0 ? - 10 : keyCode - KeyEvent.KEYCODE_1; // turn 0 into 10 - - e.kbd_keycode = Event.KEYCODE_F1 + offset; - e.kbd_ascii = Event.ASCII_F1 + offset; - } else { - e.kbd_flags |= Event.KBD_SHIFT; - } - } - - if (kevent.getAction() == KeyEvent.ACTION_MULTIPLE) { - for (int i = 0; i <= kevent.getRepeatCount(); i++) { - e.type = Event.EVENT_KEYDOWN; - _scummvm.pushEvent(e); - - e.type = Event.EVENT_KEYUP; - _scummvm.pushEvent(e); - } - } else { - _scummvm.pushEvent(e); - } - - return true; - } - - private int getEventType(int action) { - switch (action) { - case MotionEvent.ACTION_DOWN: - _last_click_was_right = _do_right_click; - return _last_click_was_right ? - Event.EVENT_RBUTTONDOWN : Event.EVENT_LBUTTONDOWN; - - case MotionEvent.ACTION_UP: - return _last_click_was_right ? - Event.EVENT_RBUTTONUP : Event.EVENT_LBUTTONUP; - - case MotionEvent.ACTION_MOVE: - return Event.EVENT_MOUSEMOVE; - - default: - return Event.EVENT_INVALID; - } - } - - @Override - public boolean onTrackballEvent(MotionEvent event) { - int type = getEventType(event.getAction()); - if (type == Event.EVENT_INVALID) - return false; - - Event e = new Event(type); - e.mouse_x = - (int)(event.getX() * event.getXPrecision()) * TRACKBALL_SCALE; - e.mouse_y = - (int)(event.getY() * event.getYPrecision()) * TRACKBALL_SCALE; - e.mouse_relative = true; - - _scummvm.pushEvent(e); - - return true; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - int type = getEventType(event.getAction()); - - if (type == Event.EVENT_INVALID) - return false; - - Event e = new Event(type); - e.mouse_x = (int)event.getX(); - e.mouse_y = (int)event.getY(); - e.mouse_relative = false; - - _scummvm.pushEvent(e); + public boolean onTrackballEvent(MotionEvent e) { + if (_events != null) + return _events.onTrackballEvent(e); - return true; + return false; } private void showKeyboard(boolean show) { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java new file mode 100644 index 0000000000..3d3fdeece4 --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -0,0 +1,201 @@ +package org.inodes.gus.scummvm; + +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.content.Context; +import android.view.KeyEvent; +import android.view.KeyCharacterMap; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.GestureDetector; +import android.view.inputmethod.InputMethodManager; + +public class ScummVMEvents implements + android.view.View.OnKeyListener, + android.view.View.OnTouchListener, + android.view.GestureDetector.OnGestureListener, + android.view.GestureDetector.OnDoubleTapListener { + + public static final int JE_SYS_KEY = 0; + public static final int JE_KEY = 1; + public static final int JE_DOWN = 2; + public static final int JE_SCROLL = 3; + public static final int JE_TAP = 4; + public static final int JE_DOUBLE_TAP = 5; + public static final int JE_BALL = 6; + public static final int JE_QUIT = 0x1000; + + final protected Context _context; + final protected ScummVM _scummvm; + final protected GestureDetector _gd; + final protected int _longPress; + final protected int _slop; + + public ScummVMEvents(Context context, ScummVM scummvm) { + _context = context; + _scummvm = scummvm; + + _gd = new GestureDetector(context, this); + _gd.setOnDoubleTapListener(this); + _gd.setIsLongpressEnabled(false); + + _longPress = ViewConfiguration.getLongPressTimeout(); + _slop = ViewConfiguration.get(context).getScaledTouchSlop(); + + } + + final public void sendQuitEvent() { + _scummvm.pushEvent(JE_QUIT, 0, 0, 0, 0, 0); + } + + public boolean onTrackballEvent(MotionEvent e) { + _scummvm.pushEvent(JE_BALL, (int)(e.getX() * e.getXPrecision() * 100), + (int)(e.getY() * e.getYPrecision() * 100), 0, 0, 0); + return true; + } + + final static int MSG_MENU_LONG_PRESS = 1; + + final private Handler keyHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_MENU_LONG_PRESS) { + InputMethodManager imm = (InputMethodManager) + _context.getSystemService(_context.INPUT_METHOD_SERVICE); + + if (imm != null) + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + } + }; + + // OnKeyListener + final public boolean onKey(View v, int keyCode, KeyEvent e) { + final int action = e.getAction(); + + if (e.isSystem()) { + // filter what we handle + switch (keyCode) { + case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_MENU: + break; + + default: + return false; + } + + // no repeats for system keys + if (e.getRepeatCount() > 0) + return false; + + // Have to reimplement hold-down-menu-brings-up-softkeybd + // ourselves, since we are otherwise hijacking the menu key :( + // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel() + // for the usual Android implementation of this feature. + if (keyCode == KeyEvent.KEYCODE_MENU) { + final boolean fired = + !keyHandler.hasMessages(MSG_MENU_LONG_PRESS); + + keyHandler.removeMessages(MSG_MENU_LONG_PRESS); + + if (action == KeyEvent.ACTION_DOWN) { + keyHandler.sendMessageDelayed(keyHandler.obtainMessage( + MSG_MENU_LONG_PRESS), _longPress); + return true; + } + + if (fired) + return true; + + // only send up events of the menu button to the native side + if (action != KeyEvent.ACTION_UP) + return true; + } + + _scummvm.pushEvent(JE_SYS_KEY, action, keyCode, 0, 0, 0); + + return true; + } + + // sequence of characters + if (action == KeyEvent.ACTION_MULTIPLE && + keyCode == KeyEvent.KEYCODE_UNKNOWN) { + KeyCharacterMap m = KeyCharacterMap.load(e.getDeviceId()); + + for (KeyEvent s : m.getEvents(e.getCharacters().toCharArray())) { + _scummvm.pushEvent(JE_KEY, s.getAction(), s.getKeyCode(), + s.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK, + s.getMetaState(), s.getRepeatCount()); + } + + return true; + } + + _scummvm.pushEvent(JE_KEY, action, keyCode, + e.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK, + e.getMetaState(), e.getRepeatCount()); + + return true; + } + + // OnTouchListener + final public boolean onTouch(View v, MotionEvent e) { + return _gd.onTouchEvent(e); + } + + // OnGestureListener + final public boolean onDown(MotionEvent e) { + _scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0); + return true; + } + + final public boolean onFling(MotionEvent e1, MotionEvent e2, + float velocityX, float velocityY) { + //Log.d(ScummVM.LOG_TAG, String.format("onFling: %s -> %s (%.3f %.3f)", + // e1.toString(), e2.toString(), + // velocityX, velocityY)); + + return true; + } + + final public void onLongPress(MotionEvent e) { + // disabled, interferes with drag&drop + } + + final public boolean onScroll(MotionEvent e1, MotionEvent e2, + float distanceX, float distanceY) { + _scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(), + (int)e2.getX(), (int)e2.getY(), _slop); + + return true; + } + + final public void onShowPress(MotionEvent e) { + } + + final public boolean onSingleTapUp(MotionEvent e) { + _scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(), + (int)(e.getEventTime() - e.getDownTime()), 0, 0); + + return true; + } + + // OnDoubleTapListener + final public boolean onDoubleTap(MotionEvent e) { + return true; + } + + final public boolean onDoubleTapEvent(MotionEvent e) { + _scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(), + e.getAction(), _slop, 0); + + return true; + } + + final public boolean onSingleTapConfirmed(MotionEvent e) { + return true; + } +} + -- cgit v1.2.3 From 093b74e40541842e4f385f92a75e9eee93a24c2d Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 16 Mar 2011 23:55:54 +0100 Subject: ANDROID: Disable game/overlay blending Doesn't work on some drivers, need to do it differently --- backends/platform/android/gfx.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index fc45f4c9e1..d7e31fcad7 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -442,8 +442,9 @@ void OSystem_Android::updateScreen() { GLCALL(glTranslatex(0, -_shake_offset << 16, 0)); } - if (_show_overlay) - GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f)); +// TODO this doesnt work on those sucky drivers, do it differently +// if (_show_overlay) +// GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f)); if (_focus_rect.isEmpty()) { _game_texture->drawTextureRect(); @@ -467,7 +468,8 @@ void OSystem_Android::updateScreen() { int cs = _mouse_targetscale; if (_show_overlay) { - GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); +// TODO see above +// GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); // ugly, but the modern theme sets a wacko factor, only god knows why cs = 1; -- cgit v1.2.3 From 2ea6380040e934802de2ed65abeb074c98304b4a Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 18:23:37 +0100 Subject: ANDROID: Plug RGB cursor memleak --- backends/platform/android/gfx.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index d7e31fcad7..ec98c35f42 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -679,10 +679,13 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, #ifdef USE_RGB_COLOR if (format && format->bytesPerPixel > 1) { - if (_mouse_texture != _mouse_texture_rgb) + if (_mouse_texture != _mouse_texture_rgb) { LOGD("switching to rgb mouse cursor"); - _mouse_texture_rgb = new GLES5551Texture(); + assert(!_mouse_texture_rgb); + _mouse_texture_rgb = new GLES5551Texture(); + } + _mouse_texture = _mouse_texture_rgb; } else { if (_mouse_texture != _mouse_texture_palette) -- cgit v1.2.3 From 23213d23dc51d158321ce22c4cefddf771a3a36f Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 18:25:23 +0100 Subject: ANDROID: Log ASCII code of invalid keycodes --- backends/platform/android/events.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 1715e6a8a7..b8e8d8e69c 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -419,7 +419,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, } if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) { - LOGE("received invalid keycode: %d", arg2); + LOGE("received invalid keycode: %d (%d)", arg2, arg3); return; } -- cgit v1.2.3 From f4fd9e8b504a2e49fbd67d288e591377c466760c Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 18:56:22 +0100 Subject: ANDROID: Fix cursor visibility --- backends/platform/android/gfx.cpp | 8 +++----- backends/platform/android/texture.h | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index ec98c35f42..8a03a19fee 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -477,7 +477,7 @@ void OSystem_Android::updateScreen() { GLCALL(_overlay_texture->drawTextureRect()); } - if (_show_mouse) { + if (_show_mouse && !_mouse_texture->isEmpty()) { GLCALL(glPushMatrix()); const Common::Point &mouse = getEventManager()->getMousePos(); @@ -710,10 +710,8 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0); } - if (w == 0 || h == 0) { - _show_mouse = false; + if (w == 0 || h == 0) return; - } if (_mouse_texture == _mouse_texture_palette) { _mouse_texture->updateBuffer(0, 0, w, h, buf, w); @@ -730,7 +728,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, delete[] tmp; - _show_mouse = false; + _mouse_texture->allocBuffer(0, 0); return; } diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 64489da0a4..925418721b 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -98,6 +98,10 @@ public: return _surface.pitch; } + inline bool isEmpty() const { + return _surface.w == 0 || _surface.h == 0; + } + inline const Graphics::Surface *surface_const() const { return &_surface; } -- cgit v1.2.3 From 82bcddf8dacb894fe1155ca768df9a072984ef91 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 19:03:51 +0100 Subject: ANDROID: Init vars to match with the defaults The feature flags are set too late, so lets fix that here --- backends/platform/android/android.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 4e1373a1b1..483b37310a 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -109,9 +109,9 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _mouse_hotspot(), _mouse_keycolor(0), _use_mouse_palette(false), - _fullscreen(false), _graphicsMode(0), - _ar_correction(false), + _fullscreen(true), + _ar_correction(true), _show_mouse(false), _show_overlay(false), _enable_zoning(false), -- cgit v1.2.3 From 70e2c4266b20d09e4bc2d89fcd3d3fba6ddaade9 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 19:29:34 +0100 Subject: ANDROID: Get rid of more gfx glitches --- backends/platform/android/gfx.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 8a03a19fee..5b03af9698 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -286,6 +286,9 @@ void OSystem_Android::initSize(uint width, uint height, void OSystem_Android::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) { @@ -310,6 +313,9 @@ void OSystem_Android::clearScreen(FixupType type, byte count) { if (!_show_overlay) GLCALL(glEnable(GL_SCISSOR_TEST)); + + _show_mouse = sm; + _force_redraw = true; } void OSystem_Android::updateScreenRect() { @@ -592,15 +598,15 @@ void OSystem_Android::showOverlay() { void OSystem_Android::hideOverlay() { ENTER(); - clearScreen(kClear); - _show_overlay = false; - _force_redraw = true; updateEventScale(); warpMouse(_game_texture->width() / 2, _game_texture->height() / 2); + // double buffered, flip twice + clearScreen(kClearUpdate, 2); + GLCALL(glEnable(GL_SCISSOR_TEST)); } -- cgit v1.2.3 From 8953581ec9dcde966ec7a5e2e7f2c37a4cf4d109 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 20:48:44 +0100 Subject: ANDROID: Ignore the slop area on all touch scrolls Prevents initial cursor jumps --- backends/platform/android/android.cpp | 1 + backends/platform/android/android.h | 2 +- backends/platform/android/events.cpp | 23 ++++++++++++++++++---- .../org/inodes/gus/scummvm/ScummVMEvents.java | 7 ++----- 4 files changed, 23 insertions(+), 10 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 483b37310a..cf711301fa 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -122,6 +122,7 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _shake_offset(0), _event_queue_lock(createMutex()), _touch_pt_down(), + _touch_pt_scroll(), _touch_pt_dt(), _eventScaleX(100), _eventScaleY(100), diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 7ff96186f9..839b3f01c1 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -209,7 +209,7 @@ private: Common::Queue _event_queue; MutexRef _event_queue_lock; - Common::Point _touch_pt_down, _touch_pt_dt; + Common::Point _touch_pt_down, _touch_pt_scroll, _touch_pt_dt; int _eventScaleX; int _eventScaleY; bool _touchpad_mode; diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index b8e8d8e69c..cab09e04dd 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -444,13 +444,22 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case JE_DOWN: _touch_pt_down = getEventManager()->getMousePos(); + _touch_pt_scroll.x = -1; + _touch_pt_scroll.y = -1; break; case JE_SCROLL: e.type = Common::EVENT_MOUSEMOVE; if (_touchpad_mode) { - scaleMouse(e.mouse, arg3 - arg1, arg4 - arg2, false); + if (_touch_pt_scroll.x == -1 && _touch_pt_scroll.y == -1) { + _touch_pt_scroll.x = arg3; + _touch_pt_scroll.y = arg4; + return; + } + + scaleMouse(e.mouse, arg3 - _touch_pt_scroll.x, + arg4 - _touch_pt_scroll.y, false); e.mouse += _touch_pt_down; clipMouse(e.mouse); } else { @@ -520,14 +529,20 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, switch (arg3) { case JACTION_DOWN: dptype = Common::EVENT_LBUTTONDOWN; - _touch_pt_dt.x = arg1; - _touch_pt_dt.y = arg2; + _touch_pt_dt.x = -1; + _touch_pt_dt.y = -1; break; case JACTION_UP: dptype = Common::EVENT_LBUTTONUP; break; + // held and moved case JACTION_MULTIPLE: - // held and moved + if (_touch_pt_dt.x == -1 && _touch_pt_dt.y == -1) { + _touch_pt_dt.x = arg1; + _touch_pt_dt.y = arg2; + return; + } + dptype = Common::EVENT_MOUSEMOVE; if (_touchpad_mode) { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java index 3d3fdeece4..7507d7e5fc 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -31,7 +31,6 @@ public class ScummVMEvents implements final protected ScummVM _scummvm; final protected GestureDetector _gd; final protected int _longPress; - final protected int _slop; public ScummVMEvents(Context context, ScummVM scummvm) { _context = context; @@ -42,8 +41,6 @@ public class ScummVMEvents implements _gd.setIsLongpressEnabled(false); _longPress = ViewConfiguration.getLongPressTimeout(); - _slop = ViewConfiguration.get(context).getScaledTouchSlop(); - } final public void sendQuitEvent() { @@ -167,7 +164,7 @@ public class ScummVMEvents implements final public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { _scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(), - (int)e2.getX(), (int)e2.getY(), _slop); + (int)e2.getX(), (int)e2.getY(), 0); return true; } @@ -189,7 +186,7 @@ public class ScummVMEvents implements final public boolean onDoubleTapEvent(MotionEvent e) { _scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(), - e.getAction(), _slop, 0); + e.getAction(), 0, 0); return true; } -- cgit v1.2.3 From 0eb5352290ddfea9d90f99b97fa0d89c806d25e0 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 21:00:15 +0100 Subject: ANDROID: Increase default touchpad mode scale aka my display is bigger than yours --- backends/platform/android/android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index cf711301fa..6bb6de7289 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -128,7 +128,7 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _eventScaleY(100), // TODO put these values in some option dlg? _touchpad_mode(true), - _touchpad_scale(50), + _touchpad_scale(66), _dpad_scale(4), _trackball_scale(2) { } -- cgit v1.2.3 From 47e9db8fdff9c538698450725cc0a369e6e9eab5 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 17 Mar 2011 22:02:17 +0100 Subject: ANDROID: Fix KeyEvent NullPointerException Could happen with some special symbols from the virtual keyboard --- .../platform/android/org/inodes/gus/scummvm/ScummVMEvents.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java index 7507d7e5fc..da589a326e 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -119,9 +119,13 @@ public class ScummVMEvents implements // sequence of characters if (action == KeyEvent.ACTION_MULTIPLE && keyCode == KeyEvent.KEYCODE_UNKNOWN) { - KeyCharacterMap m = KeyCharacterMap.load(e.getDeviceId()); + final KeyCharacterMap m = KeyCharacterMap.load(e.getDeviceId()); + final KeyEvent[] es = m.getEvents(e.getCharacters().toCharArray()); - for (KeyEvent s : m.getEvents(e.getCharacters().toCharArray())) { + if (es == null) + return true; + + for (KeyEvent s : es) { _scummvm.pushEvent(JE_KEY, s.getAction(), s.getKeyCode(), s.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK, s.getMetaState(), s.getRepeatCount()); -- cgit v1.2.3 From b7215472136c91841d44decd6955b4eb3e3e2ce1 Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 18 Mar 2011 21:05:46 +0100 Subject: ANDROID: Implement trackball click --- backends/platform/android/events.cpp | 26 +++++++++++++++++----- .../org/inodes/gus/scummvm/ScummVMEvents.java | 6 +++-- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index cab09e04dd..da17b8ec32 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -569,15 +569,29 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; case JE_BALL: - e.type = Common::EVENT_MOUSEMOVE; - e.mouse = getEventManager()->getMousePos(); - // already multiplied by 100 - e.mouse.x += arg1 * _trackball_scale / _eventScaleX; - e.mouse.y += arg2 * _trackball_scale / _eventScaleY; + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_LBUTTONDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_LBUTTONUP; + break; + case JACTION_MULTIPLE: + e.type = Common::EVENT_MOUSEMOVE; + + // already multiplied by 100 + e.mouse.x += arg2 * _trackball_scale / _eventScaleX; + e.mouse.y += arg3 * _trackball_scale / _eventScaleY; - clipMouse(e.mouse); + clipMouse(e.mouse); + + break; + default: + LOGE("unhandled jaction on system key: %d", arg1); + return; + } lockMutex(_event_queue_lock); _event_queue.push(e); diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java index da589a326e..baf128292e 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -48,8 +48,10 @@ public class ScummVMEvents implements } public boolean onTrackballEvent(MotionEvent e) { - _scummvm.pushEvent(JE_BALL, (int)(e.getX() * e.getXPrecision() * 100), - (int)(e.getY() * e.getYPrecision() * 100), 0, 0, 0); + _scummvm.pushEvent(JE_BALL, e.getAction(), + (int)(e.getX() * e.getXPrecision() * 100), + (int)(e.getY() * e.getYPrecision() * 100), + 0, 0); return true; } -- cgit v1.2.3 From e056bfca9c0ef1a07f4a9703d842ffa669096b0d Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 18 Mar 2011 21:22:48 +0100 Subject: ANDROID: Seperate DPAD codes --- backends/platform/android/events.cpp | 94 +++++++++++----------- .../org/inodes/gus/scummvm/ScummVMEvents.java | 23 ++++-- 2 files changed, 66 insertions(+), 51 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index da17b8ec32..2f6049224a 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -38,11 +38,12 @@ enum { JE_SYS_KEY = 0, JE_KEY = 1, - JE_DOWN = 2, - JE_SCROLL = 3, - JE_TAP = 4, - JE_DOUBLE_TAP = 5, - JE_BALL = 6, + JE_DPAD = 2, + JE_DOWN = 3, + JE_SCROLL = 4, + JE_TAP = 5, + JE_DOUBLE_TAP = 6, + JE_BALL = 7, JE_QUIT = 0x1000 }; @@ -338,7 +339,43 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, break; case JE_KEY: - // five-way first + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_KEYDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_KEYUP; + break; + default: + LOGE("unhandled jaction on key: %d", arg1); + return; + } + + if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) { + LOGE("received invalid keycode: %d (%d)", arg2, arg3); + return; + } + + if (arg5 > 0) + e.synthetic = true; + + e.kbd.keycode = jkeymap[arg2]; + e.kbd.ascii = arg3; + + if (arg4 & JMETA_SHIFT) + e.kbd.flags |= Common::KBD_SHIFT; + if (arg4 & JMETA_ALT) + e.kbd.flags |= Common::KBD_ALT; + if (arg4 & (JMETA_SYM | JMETA_CTRL)) + e.kbd.flags |= Common::KBD_CTRL; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_DPAD: switch (arg2) { case JKEYCODE_DPAD_UP: case JKEYCODE_DPAD_DOWN: @@ -349,7 +386,6 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; e.type = Common::EVENT_MOUSEMOVE; - e.synthetic = true; e.mouse = getEventManager()->getMousePos(); @@ -366,10 +402,12 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, // the longer the button held, the faster the pointer is // TODO put these values in some option dlg? - int f = CLIP(arg5, 1, 8) * _dpad_scale * 100 / s; + int f = CLIP(arg4, 1, 8) * _dpad_scale * 100 / s; - *c += ((arg2 == JKEYCODE_DPAD_UP || - arg2 == JKEYCODE_DPAD_LEFT) ? -1 : 1) * f; + if (arg2 == JKEYCODE_DPAD_UP || arg2 == JKEYCODE_DPAD_LEFT) + *c -= f; + else + *c += f; clipMouse(e.mouse); @@ -406,42 +444,6 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; } - switch (arg1) { - case JACTION_DOWN: - e.type = Common::EVENT_KEYDOWN; - break; - case JACTION_UP: - e.type = Common::EVENT_KEYUP; - break; - default: - LOGE("unhandled jaction on key: %d", arg1); - return; - } - - if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) { - LOGE("received invalid keycode: %d (%d)", arg2, arg3); - return; - } - - if (arg5 > 0) - e.synthetic = true; - - e.kbd.keycode = jkeymap[arg2]; - e.kbd.ascii = arg3; - - if (arg4 & JMETA_SHIFT) - e.kbd.flags |= Common::KBD_SHIFT; - if (arg4 & JMETA_ALT) - e.kbd.flags |= Common::KBD_ALT; - if (arg4 & (JMETA_SYM | JMETA_CTRL)) - e.kbd.flags |= Common::KBD_CTRL; - - lockMutex(_event_queue_lock); - _event_queue.push(e); - unlockMutex(_event_queue_lock); - - return; - case JE_DOWN: _touch_pt_down = getEventManager()->getMousePos(); _touch_pt_scroll.x = -1; diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java index baf128292e..cae88ea111 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -20,11 +20,12 @@ public class ScummVMEvents implements public static final int JE_SYS_KEY = 0; public static final int JE_KEY = 1; - public static final int JE_DOWN = 2; - public static final int JE_SCROLL = 3; - public static final int JE_TAP = 4; - public static final int JE_DOUBLE_TAP = 5; - public static final int JE_BALL = 6; + public static final int JE_DPAD = 2; + public static final int JE_DOWN = 3; + public static final int JE_SCROLL = 4; + public static final int JE_TAP = 5; + public static final int JE_DOUBLE_TAP = 6; + public static final int JE_BALL = 7; public static final int JE_QUIT = 0x1000; final protected Context _context; @@ -136,6 +137,18 @@ public class ScummVMEvents implements return true; } + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_CENTER: + _scummvm.pushEvent(JE_DPAD, action, keyCode, + (int)(e.getEventTime() - e.getDownTime()), + e.getRepeatCount(), 0); + return true; + } + _scummvm.pushEvent(JE_KEY, action, keyCode, e.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK, e.getMetaState(), e.getRepeatCount()); -- cgit v1.2.3 From 3e3619feb87c9b63a0dae08c2dd29ed43dc1bc82 Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 18 Mar 2011 22:14:54 +0100 Subject: ANDROID: Cleanup --- backends/platform/android/events.cpp | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 2f6049224a..5fc10b2161 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -381,14 +381,14 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case JKEYCODE_DPAD_DOWN: case JKEYCODE_DPAD_LEFT: case JKEYCODE_DPAD_RIGHT: - { - if (arg1 != JACTION_DOWN) - return; + if (arg1 != JACTION_DOWN) + return; - e.type = Common::EVENT_MOUSEMOVE; + e.type = Common::EVENT_MOUSEMOVE; - e.mouse = getEventManager()->getMousePos(); + e.mouse = getEventManager()->getMousePos(); + { int16 *c; int s; @@ -408,13 +408,13 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, *c -= f; else *c += f; + } - clipMouse(e.mouse); + clipMouse(e.mouse); - lockMutex(_event_queue_lock); - _event_queue.push(e); - unlockMutex(_event_queue_lock); - } + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); return; @@ -431,15 +431,11 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; } - { - const Common::Point &m = getEventManager()->getMousePos(); - - e.mouse = m; + e.mouse = getEventManager()->getMousePos(); - lockMutex(_event_queue_lock); - _event_queue.push(e); - unlockMutex(_event_queue_lock); - } + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); return; } -- cgit v1.2.3 From 69e271225f43e7c6c34fbc9c1e0cf73afeedfe18 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 19 Mar 2011 12:17:43 +0100 Subject: ANDROID: Log some system properties --- backends/platform/android/android.cpp | 14 ++++++++++++++ backends/platform/android/android.h | 2 ++ 2 files changed, 16 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 6bb6de7289..73b310c0bc 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -131,6 +132,11 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _touchpad_scale(66), _dpad_scale(4), _trackball_scale(2) { + LOGI("Running on: [%s] [%s] SDK:%s ABI:%s", + getSystemProperty("ro.build.fingerprint").c_str(), + getSystemProperty("ro.build.display.id").c_str(), + getSystemProperty("ro.build.version.sdk").c_str(), + getSystemProperty("ro.product.cpu.abi").c_str()); } OSystem_Android::~OSystem_Android() { @@ -548,6 +554,14 @@ void OSystem_Android::logMessage(LogMessageType::Type type, } } +Common::String OSystem_Android::getSystemProperty(const char *name) const { + char value[PROP_VALUE_MAX]; + + int len = __system_property_get(name, value); + + return Common::String(value, len); +} + #ifdef DYNAMIC_MODULES void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const { ((OSystem_Android *)g_system)->addPluginDirectories(dirs); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 839b3f01c1..da5e75c04b 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -144,6 +144,8 @@ private: FilesystemFactory *_fsFactory; timeval _startTime; + Common::String getSystemProperty(const char *name) const; + void initSurface(); void deinitSurface(); void initViewport(); -- cgit v1.2.3 From 0d9a852f464e484d5733de6268d6d0b917294120 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 19 Mar 2011 12:36:27 +0100 Subject: ANDROID: Implement OSystem::getSystemLanguage() --- backends/platform/android/android.cpp | 6 ++++++ backends/platform/android/android.h | 1 + 2 files changed, 7 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 73b310c0bc..69b3f1e084 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -554,6 +554,12 @@ void OSystem_Android::logMessage(LogMessageType::Type type, } } +Common::String OSystem_Android::getSystemLanguage() const { + return Common::String::format("%s_%s", + getSystemProperty("persist.sys.language").c_str(), + getSystemProperty("persist.sys.country").c_str()); +} + Common::String OSystem_Android::getSystemProperty(const char *name) const { char value[PROP_VALUE_MAX]; diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index da5e75c04b..eb05dbd390 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -282,6 +282,7 @@ public: virtual void logMessage(LogMessageType::Type type, const char *message); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual Common::String getSystemLanguage() const; }; #endif -- cgit v1.2.3 From 0e9af50d486acded5f1bcac309dcc3cee86943ca Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 19 Mar 2011 19:52:01 +0100 Subject: ANDROID: Add port specific README First version, just describing the controls and related hacks --- backends/platform/android/android.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index cb39f8acfe..01ebf73a81 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -22,6 +22,8 @@ JAVA_FILES_GEN = \ PATH_DIST = $(srcdir)/dists/android PATH_RESOURCES = $(PATH_DIST)/res +PORT_DISTFILES = $(PATH_DIST)/README.Android + RESOURCES = \ $(PATH_RESOURCES)/values/strings.xml \ $(PATH_RESOURCES)/layout/main.xml \ @@ -178,7 +180,7 @@ androidtest: $(APK_MAIN) $(APK_PLUGINS) androiddistdebug: all $(MKDIR) debug $(CP) $(APK_MAIN) $(APK_PLUGINS) debug/ - for i in $(DIST_FILES_DOCS); do \ + for i in $(DIST_FILES_DOCS) $(PORT_DISTFILES); do \ sed 's/$$/\r/' < $$i > debug/`basename $$i`.txt; \ done -- cgit v1.2.3 From c77e7f75a66c5236347fc6fc907e67f053a048fb Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 20 Mar 2011 13:29:21 +0100 Subject: ANDROID: Trust ASCII kbd codes on unknown keys --- backends/platform/android/events.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 5fc10b2161..c969068d70 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -352,14 +352,20 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, } if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) { - LOGE("received invalid keycode: %d (%d)", arg2, arg3); - return; + if (arg3 < 1) { + LOGE("received invalid keycode: %d (%d)", arg2, arg3); + return; + } else { + // lets bet on the ascii code + e.kbd.keycode = Common::KEYCODE_INVALID; + } + } else { + e.kbd.keycode = jkeymap[arg2]; } if (arg5 > 0) e.synthetic = true; - e.kbd.keycode = jkeymap[arg2]; e.kbd.ascii = arg3; if (arg4 & JMETA_SHIFT) -- cgit v1.2.3 From 5f96dc6867a509291af4e9b2632ae5c548101707 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 22 Mar 2011 20:29:08 +0100 Subject: ANDROID: Fix timer frequency to match SDL --- backends/platform/android/android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 69b3f1e084..9a6995646c 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -162,7 +162,7 @@ void *OSystem_Android::timerThreadFunc(void *arg) { struct timespec tv; tv.tv_sec = 0; - tv.tv_nsec = 100 * 1000 * 1000; // 100ms + tv.tv_nsec = 10 * 1000 * 1000; // 10ms while (!system->_timer_thread_exit) { if (JNI::pause) { -- cgit v1.2.3 From 397fd31a17f007a610aa7b673170983414efb5d5 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 24 Mar 2011 18:54:14 +0100 Subject: ANDROID: Cleanup --- backends/platform/android/gfx.cpp | 5 +---- backends/platform/android/texture.cpp | 36 +++++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 5b03af9698..e32e2095bc 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -146,7 +146,6 @@ void OSystem_Android::initTexture(GLESBaseTexture **texture, } (*texture)->allocBuffer(width, height); - (*texture)->fillBuffer(0); } #endif @@ -253,7 +252,6 @@ void OSystem_Android::initOverlay() { LOGI("overlay size is %ux%u", overlay_width, overlay_height); _overlay_texture->allocBuffer(overlay_width, overlay_height); - _overlay_texture->fillBuffer(0); _overlay_texture->setDrawRect(0, 0, _egl_surface_width, _egl_surface_height); } @@ -268,7 +266,6 @@ void OSystem_Android::initSize(uint width, uint height, initTexture(&_game_texture, width, height, format); #else _game_texture->allocBuffer(width, height); - _game_texture->fillBuffer(0); #endif updateScreenRect(); @@ -710,8 +707,8 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, assert(keycolor < 256); byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2; - WRITE_UINT16(p, READ_UINT16(p) | 1); + _mouse_keycolor = keycolor; WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0); } diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 691c384a18..b96d6bf443 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -229,8 +229,10 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); - if (_surface.w == oldw && _surface.h == oldh) + if (_surface.w == oldw && _surface.h == oldh) { + fillBuffer(0); return; + } delete[] _buf; delete[] _pixels; @@ -241,6 +243,8 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _surface.pixels = _pixels; _surface.pitch = w * _pixelFormat.bytesPerPixel; + fillBuffer(0); + _buf = new byte[w * h * _surface.bytesPerPixel]; assert(_buf); } @@ -358,22 +362,26 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); - if (_surface.w == oldw && _surface.h == oldh) + if (_surface.w == oldw && _surface.h == oldh) { + fillBuffer(0); return; + } - byte *new_buffer = new byte[_paletteSize + - _texture_width * _texture_height]; - assert(new_buffer); + byte *old_texture = _texture; - if (_texture) { - // preserve palette - memcpy(new_buffer, _texture, _paletteSize); - delete[] _texture; - } + _texture = new byte[_paletteSize + _texture_width * _texture_height]; + assert(_texture); - _texture = new_buffer; _surface.pixels = _texture + _paletteSize; _surface.pitch = _texture_width; + + fillBuffer(0); + + if (old_texture) { + // preserve palette + memcpy(_texture, old_texture, _paletteSize); + delete[] old_texture; + } } void GLESPaletteTexture::fillBuffer(uint32 color) { @@ -480,8 +488,10 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); - if (_surface.w == oldw && _surface.h == oldh) + if (_surface.w == oldw && _surface.h == oldh) { + fillBuffer(0); return; + } delete[] _buf; delete[] _pixels; @@ -494,6 +504,8 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { _surface.bytesPerPixel = 1; _surface.pitch = w; + fillBuffer(0); + _buf = new uint16[w * h]; assert(_buf); } -- cgit v1.2.3 From e6080087c8453b5a0345bf62b2cd3809e46f7591 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 24 Mar 2011 18:54:49 +0100 Subject: ANDROID: Fix cursor's keycolor Don't wipe the RGB bits, fixes wrong colors on BASS cursors --- backends/platform/android/gfx.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index e32e2095bc..bbd09ad20a 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -710,7 +710,9 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, WRITE_UINT16(p, READ_UINT16(p) | 1); _mouse_keycolor = keycolor; - WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0); + + p = _mouse_texture_palette->palette() + _mouse_keycolor * 2; + WRITE_UINT16(p, READ_UINT16(p) & ~1); } if (w == 0 || h == 0) @@ -761,7 +763,8 @@ void OSystem_Android::setCursorPaletteInternal(const byte *colors, for (uint i = 0; i < num; ++i, colors += 3, p += 2) WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2])); - WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0); + p = _mouse_texture_palette->palette() + _mouse_keycolor * 2; + WRITE_UINT16(p, READ_UINT16(p) & ~1); } void OSystem_Android::setCursorPalette(const byte *colors, @@ -804,7 +807,8 @@ void OSystem_Android::disableCursorPalette(bool disable) { WRITE_UINT16(dst, pf_dst.RGBToColor(r, g, b)); } - WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0); + byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2; + WRITE_UINT16(p, READ_UINT16(p) & ~1); } _use_mouse_palette = !disable; -- cgit v1.2.3 From 19c407ca69ea2b98623203948bb62d84729645b3 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 24 Mar 2011 21:22:44 +0100 Subject: ANDROID: Fix texture double release --- backends/platform/android/texture.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index b96d6bf443..407ba0419d 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -102,10 +102,12 @@ GLESBaseTexture::~GLESBaseTexture() { } void GLESBaseTexture::release() { - LOGD("Destroying texture %u", _texture_name); + if (_texture_name) { + LOGD("Destroying texture %u", _texture_name); - GLCALL(glDeleteTextures(1, &_texture_name)); - _texture_name = 0; + GLCALL(glDeleteTextures(1, &_texture_name)); + _texture_name = 0; + } } void GLESBaseTexture::reinit() { -- cgit v1.2.3 From b4a6c89662700b448db41d1e0c99cdf39a2dc5e0 Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 25 Mar 2011 00:35:47 +0100 Subject: ANDROID: Always set the surface properties Didn't happen on the shortcut, which led to wrong properties and surface functions scribbling over memory --- backends/platform/android/texture.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 407ba0419d..573f8f83e1 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -231,6 +231,8 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); + _surface.pitch = w * _pixelFormat.bytesPerPixel; + if (_surface.w == oldw && _surface.h == oldh) { fillBuffer(0); return; @@ -243,7 +245,6 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { assert(_pixels); _surface.pixels = _pixels; - _surface.pitch = w * _pixelFormat.bytesPerPixel; fillBuffer(0); @@ -364,6 +365,8 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); + _surface.pitch = _texture_width; + if (_surface.w == oldw && _surface.h == oldh) { fillBuffer(0); return; @@ -375,7 +378,6 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { assert(_texture); _surface.pixels = _texture + _paletteSize; - _surface.pitch = _texture_width; fillBuffer(0); @@ -490,6 +492,9 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); + _surface.bytesPerPixel = 1; + _surface.pitch = w; + if (_surface.w == oldw && _surface.h == oldh) { fillBuffer(0); return; @@ -503,8 +508,6 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { // fixup surface, for the outside this is a CLUT8 surface _surface.pixels = _pixels; - _surface.bytesPerPixel = 1; - _surface.pitch = w; fillBuffer(0); -- cgit v1.2.3 From 68908773ac0ef335f491a257473358269616ab69 Mon Sep 17 00:00:00 2001 From: dhewg Date: Fri, 25 Mar 2011 19:52:33 +0100 Subject: ANDROID: Use 'our' ASCII codes for special keys Fixes stuff like enter key on SCI games with text input --- backends/platform/android/events.cpp | 58 +++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index c969068d70..d845ab8ffc 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -366,7 +366,63 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, if (arg5 > 0) e.synthetic = true; - e.kbd.ascii = arg3; + // map special keys to 'our' ascii codes + switch (e.kbd.keycode) { + case Common::KEYCODE_BACKSPACE: + e.kbd.ascii = Common::ASCII_BACKSPACE; + break; + case Common::KEYCODE_TAB: + e.kbd.ascii = Common::ASCII_TAB; + break; + case Common::KEYCODE_RETURN: + e.kbd.ascii = Common::ASCII_RETURN; + break; + case Common::KEYCODE_ESCAPE: + e.kbd.ascii = Common::ASCII_ESCAPE; + break; + case Common::KEYCODE_SPACE: + e.kbd.ascii = Common::ASCII_SPACE; + break; + case Common::KEYCODE_F1: + e.kbd.ascii = Common::ASCII_F1; + break; + case Common::KEYCODE_F2: + e.kbd.ascii = Common::ASCII_F2; + break; + case Common::KEYCODE_F3: + e.kbd.ascii = Common::ASCII_F3; + break; + case Common::KEYCODE_F4: + e.kbd.ascii = Common::ASCII_F4; + break; + case Common::KEYCODE_F5: + e.kbd.ascii = Common::ASCII_F5; + break; + case Common::KEYCODE_F6: + e.kbd.ascii = Common::ASCII_F6; + break; + case Common::KEYCODE_F7: + e.kbd.ascii = Common::ASCII_F7; + break; + case Common::KEYCODE_F8: + e.kbd.ascii = Common::ASCII_F8; + break; + case Common::KEYCODE_F9: + e.kbd.ascii = Common::ASCII_F9; + break; + case Common::KEYCODE_F10: + e.kbd.ascii = Common::ASCII_F10; + break; + case Common::KEYCODE_F11: + e.kbd.ascii = Common::ASCII_F11; + break; + case Common::KEYCODE_F12: + e.kbd.ascii = Common::ASCII_F12; + break; + default: + e.kbd.ascii = arg3; + break; + } if (arg4 & JMETA_SHIFT) e.kbd.flags |= Common::KBD_SHIFT; -- cgit v1.2.3 From dd1c52fd8294daaf32e9047936d24c0c737f07da Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 30 Mar 2011 23:38:22 +0200 Subject: ANDROID: Map right click to Camera/Search --- backends/platform/android/events.cpp | 15 +++++++++++++++ .../android/org/inodes/gus/scummvm/ScummVMEvents.java | 2 ++ 2 files changed, 17 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index d845ab8ffc..2576287a83 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -331,6 +331,21 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; + case JKEYCODE_CAMERA: + case JKEYCODE_SEARCH: + if (arg1 == JACTION_DOWN) + e.type = Common::EVENT_RBUTTONDOWN; + else + e.type = Common::EVENT_RBUTTONUP; + + e.mouse = getEventManager()->getMousePos(); + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + default: LOGW("unmapped system key: %d", arg2); return; diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java index cae88ea111..8182f194a8 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -80,6 +80,8 @@ public class ScummVMEvents implements switch (keyCode) { case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_MENU: + case KeyEvent.KEYCODE_CAMERA: + case KeyEvent.KEYCODE_SEARCH: break; default: -- cgit v1.2.3 From bceab2656bdff4aa99f99b047f6bbd18ad5f86fc Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 2 Apr 2011 13:30:38 +0200 Subject: ANDROID: Attempt at working around some HTC fail --- backends/platform/android/android.cpp | 11 ++++++++++- backends/platform/android/android.h | 1 + backends/platform/android/gfx.cpp | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 9a6995646c..1a83289c25 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -101,6 +101,7 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _screen_changeid(0), _egl_surface_width(0), _egl_surface_height(0), + _htc_fail(false), _force_redraw(false), _game_texture(0), _overlay_texture(0), @@ -132,11 +133,19 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _touchpad_scale(66), _dpad_scale(4), _trackball_scale(2) { + Common::String fp = getSystemProperty("ro.build.fingerprint"); + LOGI("Running on: [%s] [%s] SDK:%s ABI:%s", - getSystemProperty("ro.build.fingerprint").c_str(), + fp.c_str(), getSystemProperty("ro.build.display.id").c_str(), getSystemProperty("ro.build.version.sdk").c_str(), getSystemProperty("ro.product.cpu.abi").c_str()); + + fp.toLowercase(); + _htc_fail = fp.contains("htc"); + + if (_htc_fail) + LOGI("Enabling HTC workaround"); } OSystem_Android::~OSystem_Android() { diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index eb05dbd390..40dc0fe4fd 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -99,6 +99,7 @@ private: int _screen_changeid; int _egl_surface_width; int _egl_surface_height; + bool _htc_fail; bool _force_redraw; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index bbd09ad20a..ab7240e648 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -523,6 +523,14 @@ void OSystem_Android::updateScreen() { if (!JNI::swapBuffers()) LOGW("swapBuffers failed: 0x%x", glGetError()); + + // HTC's GLES drivers are made of fail + // http://code.google.com/p/android/issues/detail?id=3047 + if (!_show_overlay && _htc_fail) { + const Common::Rect &rect = _game_texture->getDrawRect(); + + glScissor(rect.left, rect.top, rect.width(), rect.height()); + } } Graphics::Surface *OSystem_Android::lockScreen() { -- cgit v1.2.3 From 801f576f9c36025068d13cb852082e5fc9d21e87 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 3 Apr 2011 16:39:00 +0200 Subject: ANDROID: Log the ScummVM version --- backends/platform/android/jni.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 92cb04904c..08a1491998 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -26,6 +26,7 @@ #if defined(__ANDROID__) #include "base/main.h" +#include "base/version.h" #include "common/config-manager.h" #include "engines/engine.h" @@ -403,6 +404,8 @@ void JNI::setAudioStop() { void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, jobject egl, jobject egl_display, jobject at, jint audio_sample_rate, jint audio_buffer_size) { + LOGI(gScummVMFullVersion); + assert(!_system); pause = false; -- cgit v1.2.3 From 1692605b0840cd869a83bd87055e9372acda0e76 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 3 Apr 2011 17:33:10 +0200 Subject: ANDROID: Helper define to debug hanging GLES calls --- backends/platform/android/android.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 40dc0fe4fd..76db012173 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -48,6 +48,7 @@ // toggles start //#define ANDROID_DEBUG_ENTER //#define ANDROID_DEBUG_GL +//#define ANDROID_DEBUG_GL_CALLS // toggles end extern const char *android_log_tag; @@ -67,9 +68,23 @@ extern const char *android_log_tag; #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) -- cgit v1.2.3 From fba1c6360c0194e5cad6133dc312c1c8ae80ac39 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 3 Apr 2011 20:25:31 +0200 Subject: ANDROID: Ignore unrelated surface changes --- backends/platform/android/org/inodes/gus/scummvm/ScummVM.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index fe225af48b..8bf40ac553 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -75,6 +75,14 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { // SurfaceHolder callback final public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + // the orientation may reset on standby mode and the theme manager + // could assert when using a portrait resolution. so lets not do that. + if (height > width) { + Log.d(LOG_TAG, String.format("Ignoring surfaceChanged: %dx%d (%d)", + width, height, format)); + return; + } + Log.d(LOG_TAG, String.format("surfaceChanged: %dx%d (%d)", width, height, format)); -- cgit v1.2.3 From ea4223d941ec9dcbcca0530ed633cf8b5d05be40 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 3 Apr 2011 20:26:27 +0200 Subject: ANDROID: Always use the surface size for the overlay When coming back from standby, there might be an indermediate surface change --- backends/platform/android/events.cpp | 36 ++++++++++-------------------------- backends/platform/android/gfx.cpp | 8 +++++--- 2 files changed, 15 insertions(+), 29 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 2576287a83..ccb18dde89 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -696,35 +696,19 @@ bool OSystem_Android::pollEvent(Common::Event &event) { if (pthread_self() == _main_thread) { if (_screen_changeid != JNI::surface_changeid) { if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { - if (_egl_surface_width > 0 && _egl_surface_height > 0) { - // surface still alive but changed - _screen_changeid = JNI::surface_changeid; - _egl_surface_width = JNI::egl_surface_width; - _egl_surface_height = JNI::egl_surface_height; + // surface changed + JNI::deinitSurface(); + initSurface(); + initViewport(); + updateScreenRect(); + updateEventScale(); - initViewport(); - updateScreenRect(); - updateEventScale(); + // double buffered, flip twice + clearScreen(kClearUpdate, 2); - // double buffered, flip twice - clearScreen(kClearUpdate, 2); + event.type = Common::EVENT_SCREEN_CHANGED; - event.type = Common::EVENT_SCREEN_CHANGED; - - return true; - } else { - // new surface - initSurface(); - updateScreenRect(); - updateEventScale(); - - // double buffered, flip twice - clearScreen(kClearUpdate, 2); - - event.type = Common::EVENT_SCREEN_CHANGED; - - return true; - } + return true; } else { // surface lost deinitSurface(); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index ab7240e648..b2f5427f01 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -235,8 +235,10 @@ void OSystem_Android::initViewport() { } void OSystem_Android::initOverlay() { - int overlay_width = _egl_surface_width; - int overlay_height = _egl_surface_height; + // minimum of 320x200 + // (surface can get smaller when opening the virtual keyboard on *QVGA*) + int overlay_width = MAX(_egl_surface_width, 320); + int overlay_height = MAX(_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 @@ -244,7 +246,7 @@ void OSystem_Android::initOverlay() { // 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 - if (overlay_height > 480) { + while (overlay_height > 480) { overlay_width /= 2; overlay_height /= 2; } -- cgit v1.2.3 From 449e9cf33923f2685356596f82bc596e1f05407c Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Mon, 4 Apr 2011 12:21:30 +0200 Subject: ANDROID: Fix non-fullscreen corruption on HTC devices. HTC's drivers don't preserve the color buffer between frames (as allowed by the spec, apparently), so we have to force-clear it every frame when we're not rendering a texture over the whole screen. --- backends/platform/android/gfx.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index b2f5427f01..19cfd7f5a3 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -430,7 +430,9 @@ void OSystem_Android::updateScreen() { _force_redraw = false; // clear pointer leftovers in dead areas - if (_show_overlay && !_fullscreen) + // also, HTC's GLES drivers are made of fail and don't preserve the buffer + // ( http://www.khronos.org/registry/egl/specs/EGLTechNote0001.html ) + if ((_show_overlay || _htc_fail) && !_fullscreen) clearScreen(kClear); GLCALL(glPushMatrix()); @@ -525,14 +527,6 @@ void OSystem_Android::updateScreen() { if (!JNI::swapBuffers()) LOGW("swapBuffers failed: 0x%x", glGetError()); - - // HTC's GLES drivers are made of fail - // http://code.google.com/p/android/issues/detail?id=3047 - if (!_show_overlay && _htc_fail) { - const Common::Rect &rect = _game_texture->getDrawRect(); - - glScissor(rect.left, rect.top, rect.width(), rect.height()); - } } Graphics::Surface *OSystem_Android::lockScreen() { -- cgit v1.2.3 From 1c8fc0538815b1418bb7824e4eefda65eb2719d9 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 5 Apr 2011 13:57:09 +0200 Subject: ANDROID: Temporarily enable GL error checks There's a black screen issue on Samsung devices running 2.2.1 which I can not reproduce. Hopefully this helps hunting it down. --- backends/platform/android/android.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 76db012173..a5a30aef19 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -47,7 +47,7 @@ // toggles start //#define ANDROID_DEBUG_ENTER -//#define ANDROID_DEBUG_GL +#define ANDROID_DEBUG_GL //#define ANDROID_DEBUG_GL_CALLS // toggles end -- cgit v1.2.3 From ea253ff26d2d5ffeec85d34a79c00f0f50598111 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 5 Apr 2011 15:07:07 +0200 Subject: ANDROID: Use a faked paletted texture for CLUT cursors Same change as for the game screen, reduces CPU usage a little --- backends/platform/android/android.cpp | 2 +- backends/platform/android/android.h | 2 +- backends/platform/android/texture.cpp | 8 ++++++++ backends/platform/android/texture.h | 6 ++++++ 4 files changed, 16 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 1a83289c25..6346ffa7a3 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -359,7 +359,7 @@ void OSystem_Android::initBackend() { _game_texture = new GLESFakePalette565Texture(); _overlay_texture = new GLES4444Texture(); - _mouse_texture_palette = new GLESPalette5551Texture(); + _mouse_texture_palette = new GLESFakePalette5551Texture(); _mouse_texture = _mouse_texture_palette; initOverlay(); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index a5a30aef19..55a828b873 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -129,7 +129,7 @@ private: // Mouse layer GLESBaseTexture *_mouse_texture; - GLESPaletteTexture *_mouse_texture_palette; + GLESBaseTexture *_mouse_texture_palette; GLES5551Texture *_mouse_texture_rgb; Common::Point _mouse_hotspot; uint32 _mouse_keycolor; diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 573f8f83e1..2018dfdaab 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -584,5 +584,13 @@ GLESFakePalette565Texture::GLESFakePalette565Texture() : GLESFakePalette565Texture::~GLESFakePalette565Texture() { } +GLESFakePalette5551Texture::GLESFakePalette5551Texture() : + GLESFakePaletteTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, + GLES5551Texture::pixelFormat()) { +} + +GLESFakePalette5551Texture::~GLESFakePalette5551Texture() { +} + #endif diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index 925418721b..d825357760 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -330,6 +330,12 @@ public: virtual ~GLESFakePalette565Texture(); }; +class GLESFakePalette5551Texture : public GLESFakePaletteTexture { +public: + GLESFakePalette5551Texture(); + virtual ~GLESFakePalette5551Texture(); +}; + #endif #endif -- cgit v1.2.3 From 4440aa431070897215b8b5b588aefe8eeb9b4be2 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 5 Apr 2011 15:09:46 +0200 Subject: ANDROID: Remove code for paletted textures Unused now, because the performance isn't good enough on weak GLES drivers. --- backends/platform/android/texture.cpp | 119 ---------------------------------- backends/platform/android/texture.h | 64 ------------------ 2 files changed, 183 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 2018dfdaab..a6b28ca485 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -345,125 +345,6 @@ GLES565Texture::GLES565Texture() : GLES565Texture::~GLES565Texture() { } -GLESPaletteTexture::GLESPaletteTexture(GLenum glFormat, GLenum glType, - Graphics::PixelFormat palettePixelFormat) : - GLESBaseTexture(glFormat, glType, - Graphics::PixelFormat::createFormatCLUT8()), - _texture(0) -{ - _palettePixelFormat = palettePixelFormat; - _paletteSize = _palettePixelFormat.bytesPerPixel * 256; -} - -GLESPaletteTexture::~GLESPaletteTexture() { - delete[] _texture; -} - -void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { - GLuint oldw = _surface.w; - GLuint oldh = _surface.h; - - GLESBaseTexture::allocBuffer(w, h); - - _surface.pitch = _texture_width; - - if (_surface.w == oldw && _surface.h == oldh) { - fillBuffer(0); - return; - } - - byte *old_texture = _texture; - - _texture = new byte[_paletteSize + _texture_width * _texture_height]; - assert(_texture); - - _surface.pixels = _texture + _paletteSize; - - fillBuffer(0); - - if (old_texture) { - // preserve palette - memcpy(_texture, old_texture, _paletteSize); - delete[] old_texture; - } -} - -void GLESPaletteTexture::fillBuffer(uint32 color) { - assert(_surface.pixels); - memset(_surface.pixels, color & 0xff, _surface.pitch * _surface.h); - setDirty(); -} - -void GLESPaletteTexture::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 = static_cast(buf); - byte *dst = static_cast(_surface.getBasePtr(x, y)); - - do { - memcpy(dst, src, w); - dst += _surface.pitch; - src += pitch_buf; - } while (--h); -} - -void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, - GLshort h) { - if (dirty()) { - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - - const size_t texture_size = _paletteSize + - _texture_width * _texture_height; - - GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType, - _texture_width, _texture_height, - 0, texture_size, _texture)); - } - - GLESBaseTexture::drawTexture(x, y, w, h); -} - -GLESPalette888Texture::GLESPalette888Texture() : - GLESPaletteTexture(GL_RGB, GL_PALETTE8_RGB8_OES, - Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)) { -} - -GLESPalette888Texture::~GLESPalette888Texture() { -} - -GLESPalette8888Texture::GLESPalette8888Texture() : - GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA8_OES, - Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { -} - -GLESPalette8888Texture::~GLESPalette8888Texture() { -} - -GLESPalette565Texture::GLESPalette565Texture() : - GLESPaletteTexture(GL_RGB, GL_PALETTE8_R5_G6_B5_OES, - Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { -} - -GLESPalette565Texture::~GLESPalette565Texture() { -} - -GLESPalette4444Texture::GLESPalette4444Texture() : - GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA4_OES, - Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { -} - -GLESPalette4444Texture::~GLESPalette4444Texture() { -} - -GLESPalette5551Texture::GLESPalette5551Texture() : - GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGB5_A1_OES, - Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) { -} - -GLESPalette5551Texture::~GLESPalette5551Texture() { -} - GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType, Graphics::PixelFormat pixelFormat) : GLESBaseTexture(glFormat, glType, pixelFormat), diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h index d825357760..6344326259 100644 --- a/backends/platform/android/texture.h +++ b/backends/platform/android/texture.h @@ -227,70 +227,6 @@ public: } }; -class GLESPaletteTexture : public GLESBaseTexture { -protected: - GLESPaletteTexture(GLenum glFormat, GLenum glType, - Graphics::PixelFormat palettePixelFormat); - -public: - virtual ~GLESPaletteTexture(); - - 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); - - virtual const byte *palette_const() const { - return _texture; - }; - - virtual byte *palette() { - setDirty(); - return _texture; - }; - -protected: - byte *_texture; - size_t _paletteSize; -}; - -// RGB888 256-entry paletted texture -class GLESPalette888Texture : public GLESPaletteTexture { -public: - GLESPalette888Texture(); - virtual ~GLESPalette888Texture(); -}; - -// RGBA8888 256-entry paletted texture -class GLESPalette8888Texture : public GLESPaletteTexture { -public: - GLESPalette8888Texture(); - virtual ~GLESPalette8888Texture(); -}; - -// RGB565 256-entry paletted texture -class GLESPalette565Texture : public GLESPaletteTexture { -public: - GLESPalette565Texture(); - virtual ~GLESPalette565Texture(); -}; - -// RGBA4444 256-entry paletted texture -class GLESPalette4444Texture : public GLESPaletteTexture { -public: - GLESPalette4444Texture(); - virtual ~GLESPalette4444Texture(); -}; - -// RGBA5551 256-entry paletted texture -class GLESPalette5551Texture : public GLESPaletteTexture { -public: - GLESPalette5551Texture(); - virtual ~GLESPalette5551Texture(); -}; - class GLESFakePaletteTexture : public GLESBaseTexture { protected: GLESFakePaletteTexture(GLenum glFormat, GLenum glType, -- cgit v1.2.3 From 0adfe7296664b2bd7edaf9b1e351c069631addc4 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 5 Apr 2011 15:14:58 +0200 Subject: ANDROID: Remove commented workarounds for Nexus 1 Reports suggest that its working and not required --- backends/platform/android/gfx.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 19cfd7f5a3..ea0f556364 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -617,10 +617,6 @@ void OSystem_Android::clearOverlay() { GLTHREADCHECK; _overlay_texture->fillBuffer(0); - - // breaks more than it fixes, disabled for now - // Shouldn't need this, but works around a 'blank screen' bug on Nexus1 - //updateScreen(); } void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { @@ -650,9 +646,6 @@ void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, // 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() { -- cgit v1.2.3 From d50e7af797266e20dda17a80a45c1af45b176d3d Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 5 Apr 2011 18:25:37 +0200 Subject: ANDROID: Fix endless loop in AndroidAssetArchive Can happen on empty member filenames, seen on some Samsung firmwares. --- backends/platform/android/asset-archive.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index 26b1a6ad39..8e95029894 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -440,19 +440,22 @@ int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { for (jsize i = 0; i < env->GetArrayLength(jpathlist); ++i) { jstring elem = (jstring)env->GetObjectArrayElement(jpathlist, i); const char *p = env->GetStringUTFChars(elem, 0); - Common::String thispath = dir; - if (!thispath.empty()) - thispath += "/"; + if (strlen(p)) { + Common::String thispath = dir; - thispath += p; + if (!thispath.empty()) + thispath += "/"; - // Assume files have a . in them, and directories don't - if (strchr(p, '.')) { - member_list.push_back(getMember(thispath)); - ++count; - } else { - dirlist.push_back(thispath); + thispath += p; + + // Assume files have a . in them, and directories don't + if (strchr(p, '.')) { + member_list.push_back(getMember(thispath)); + ++count; + } else { + dirlist.push_back(thispath); + } } env->ReleaseStringUTFChars(elem, p); -- cgit v1.2.3 From 507bff8233662019e7b7078b645ce035e796af5b Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 5 Apr 2011 19:01:51 +0200 Subject: ANDROID: Log device manufacturer, model and brand --- backends/platform/android/android.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 6346ffa7a3..eb0e164109 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -135,7 +135,10 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _trackball_scale(2) { Common::String fp = getSystemProperty("ro.build.fingerprint"); - LOGI("Running on: [%s] [%s] SDK:%s ABI:%s", + LOGI("Running on: [%s] [%s] [%s] [%s] [%s] SDK:%s ABI:%s", + getSystemProperty("ro.product.manufacturer").c_str(), + getSystemProperty("ro.product.model").c_str(), + getSystemProperty("ro.product.brand").c_str(), fp.c_str(), getSystemProperty("ro.build.display.id").c_str(), getSystemProperty("ro.build.version.sdk").c_str(), -- cgit v1.2.3 From 811b1fcc2a2d8e938c2e06489a04388c97715f48 Mon Sep 17 00:00:00 2001 From: dhewg Date: Tue, 5 Apr 2011 19:10:35 +0200 Subject: ANDROID: Use the manufacturer string for workarounds Some fingerprints don't contain it, so this should be more reliable. --- backends/platform/android/android.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index eb0e164109..ab3f1908c4 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -133,19 +133,19 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _touchpad_scale(66), _dpad_scale(4), _trackball_scale(2) { - Common::String fp = getSystemProperty("ro.build.fingerprint"); + Common::String mf = getSystemProperty("ro.product.manufacturer"); LOGI("Running on: [%s] [%s] [%s] [%s] [%s] SDK:%s ABI:%s", - getSystemProperty("ro.product.manufacturer").c_str(), + mf.c_str(), getSystemProperty("ro.product.model").c_str(), getSystemProperty("ro.product.brand").c_str(), - fp.c_str(), + getSystemProperty("ro.build.fingerprint").c_str(), getSystemProperty("ro.build.display.id").c_str(), getSystemProperty("ro.build.version.sdk").c_str(), getSystemProperty("ro.product.cpu.abi").c_str()); - fp.toLowercase(); - _htc_fail = fp.contains("htc"); + mf.toLowercase(); + _htc_fail = mf.contains("htc"); if (_htc_fail) LOGI("Enabling HTC workaround"); -- cgit v1.2.3 From 430c462031a25f598b3515d9164034c4389b0257 Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 6 Apr 2011 11:30:01 +0200 Subject: Revert "ANDROID: Temporarily enable GL error checks" This reverts commit 1c8fc0538815b1418bb7824e4eefda65eb2719d9. Commit d50e7af7 confirmed as fix, so it wasn't a GL issue at all --- backends/platform/android/android.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 55a828b873..f3d989c3f8 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -47,7 +47,7 @@ // toggles start //#define ANDROID_DEBUG_ENTER -#define ANDROID_DEBUG_GL +//#define ANDROID_DEBUG_GL //#define ANDROID_DEBUG_GL_CALLS // toggles end -- cgit v1.2.3 From b45640c47b97c36442d01c35e73b4cae9ad5648e Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 6 Apr 2011 15:21:31 +0200 Subject: ANDROID: Fix off-by-one when clipping mouse coords --- backends/platform/android/events.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index ccb18dde89..ed825dbc9c 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -251,8 +251,8 @@ void OSystem_Android::clipMouse(Common::Point &p) { else tex = _game_texture; - p.x = CLIP(p.x, int16(0), int16(tex->width())); - p.y = CLIP(p.y, int16(0), int16(tex->height())); + p.x = CLIP(p.x, int16(0), int16(tex->width() - 1)); + p.y = CLIP(p.y, int16(0), int16(tex->height() - 1)); } void OSystem_Android::scaleMouse(Common::Point &p, int x, int y, -- cgit v1.2.3 From a565e63c48b2bb55b9e1197addddd3c03cf85c48 Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 6 Apr 2011 18:08:38 +0200 Subject: ANDROID: Add multitouch support --- backends/platform/android/android.cpp | 1 + backends/platform/android/android.h | 1 + backends/platform/android/events.cpp | 60 +++++++++++++++++++++- .../org/inodes/gus/scummvm/ScummVMEvents.java | 15 +++++- 4 files changed, 74 insertions(+), 3 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index ab3f1908c4..bbfdb06b8d 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -132,6 +132,7 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _touchpad_mode(true), _touchpad_scale(66), _dpad_scale(4), + _fingersDown(0), _trackball_scale(2) { Common::String mf = getSystemProperty("ro.product.manufacturer"); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index f3d989c3f8..6eebdb97d9 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -234,6 +234,7 @@ private: int _touchpad_scale; int _trackball_scale; int _dpad_scale; + int _fingersDown; void clipMouse(Common::Point &p); void scaleMouse(Common::Point &p, int x, int y, bool deductDrawRect = true); diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index ed825dbc9c..09466b4d2f 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -43,7 +43,8 @@ enum { JE_SCROLL = 4, JE_TAP = 5, JE_DOUBLE_TAP = 6, - JE_BALL = 7, + JE_MULTI = 7, + JE_BALL = 8, JE_QUIT = 0x1000 }; @@ -51,7 +52,9 @@ enum { enum { JACTION_DOWN = 0, JACTION_UP = 1, - JACTION_MULTIPLE = 2 + JACTION_MULTIPLE = 2, + JACTION_POINTER_DOWN = 5, + JACTION_POINTER_UP = 6 }; // system keys @@ -549,6 +552,11 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; case JE_TAP: + if (_fingersDown > 0) { + _fingersDown = 0; + return; + } + e.type = Common::EVENT_MOUSEMOVE; if (_touchpad_mode) { @@ -643,6 +651,54 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, return; + case JE_MULTI: + switch (arg2) { + case JACTION_POINTER_DOWN: + if (arg1 > _fingersDown) + _fingersDown = arg1; + + return; + + case JACTION_POINTER_UP: + if (arg1 != _fingersDown) + return; + + { + Common::EventType up; + + switch (_fingersDown) { + case 1: + e.type = Common::EVENT_RBUTTONDOWN; + up = Common::EVENT_RBUTTONUP; + break; + case 2: + e.type = Common::EVENT_MBUTTONDOWN; + up = Common::EVENT_MBUTTONUP; + break; + default: + LOGD("unmapped multi tap: %d", _fingersDown); + return; + } + + e.mouse = getEventManager()->getMousePos(); + + lockMutex(_event_queue_lock); + + _event_queue.push(e); + e.type = up; + _event_queue.push(e); + + unlockMutex(_event_queue_lock); + return; + + default: + LOGE("unhandled jaction on multi tap: %d", arg2); + return; + } + } + + return; + case JE_BALL: e.mouse = getEventManager()->getMousePos(); diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java index 8182f194a8..2d5c100a1c 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -25,7 +25,8 @@ public class ScummVMEvents implements public static final int JE_SCROLL = 4; public static final int JE_TAP = 5; public static final int JE_DOUBLE_TAP = 6; - public static final int JE_BALL = 7; + public static final int JE_MULTI = 7; + public static final int JE_BALL = 8; public static final int JE_QUIT = 0x1000; final protected Context _context; @@ -160,6 +161,18 @@ public class ScummVMEvents implements // OnTouchListener final public boolean onTouch(View v, MotionEvent e) { + final int action = e.getAction(); + + // constants from APIv5: + // (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT + final int pointer = (action & 0xff00) >> 8; + + if (pointer > 0) { + _scummvm.pushEvent(JE_MULTI, pointer, action & 0xff, // ACTION_MASK + (int)e.getX(), (int)e.getY(), 0); + return true; + } + return _gd.onTouchEvent(e); } -- cgit v1.2.3 From 4f09018b00007fc9acc6ac7b7930aa57ae392d02 Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 6 Apr 2011 21:15:15 +0200 Subject: ANDROID: Allow linear texture filtering on the cursor --- backends/platform/android/gfx.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index ea0f556364..86232030ff 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -59,6 +59,9 @@ bool OSystem_Android::setGraphicsMode(int mode) { if (_overlay_texture) _overlay_texture->setLinearFilter(mode == 1); + if (_mouse_texture) + _mouse_texture->setLinearFilter(mode == 1); + _graphicsMode = mode; return true; @@ -684,6 +687,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, assert(!_mouse_texture_rgb); _mouse_texture_rgb = new GLES5551Texture(); + _mouse_texture_rgb->setLinearFilter(_graphicsMode == 1); } _mouse_texture = _mouse_texture_rgb; -- cgit v1.2.3 From 90f47c7b1d9725c13d972a0e2a61b2cd966bbab5 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 9 Apr 2011 18:28:02 +0200 Subject: ANDOID: Replace mkmanifest.pl with sh/sed code Removes build dependencies like perl and its XML modules --- backends/platform/android/android.mk | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index 01ebf73a81..fdb0f8096a 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -110,14 +110,13 @@ $(FILE_DEX_PLUGIN): $(CLASSES_PLUGIN) @$(MKDIR) -p $(@D) $(DX) --dex --output=$@ $(PATH_BUILD_CLASSES_PLUGIN_TOP) -$(PATH_BUILD)/%/AndroidManifest.xml $(PATH_STAGE_PREFIX).%/res/values/strings.xml: $(PATH_DIST)/mkmanifest.pl $(srcdir)/configure $(PATH_DIST)/AndroidManifest.xml - $(PATH_DIST)/mkmanifest.pl --id=$* --configure=$(srcdir)/configure \ - --version-name=$(VERSION) \ - --version-code=$(ANDROID_PLUGIN_VERSIONCODE) \ - --stringres=$(PATH_STAGE_PREFIX).$*/res/values/strings.xml \ - --manifest=$(PATH_BUILD)/$*/AndroidManifest.xml \ - --master-manifest=$(PATH_DIST)/AndroidManifest.xml \ - --unpacklib=mylib/armeabi/lib$*.so +$(PATH_BUILD)/%/AndroidManifest.xml: $(PATH_DIST)/mkplugin.sh $(srcdir)/configure $(PATH_DIST)/plugin-manifest.xml + @$(MKDIR) -p $(@D) + $(PATH_DIST)/mkplugin.sh $(srcdir)/configure $* $(PATH_DIST)/plugin-manifest.xml $(ANDROID_PLUGIN_VERSIONCODE) $@ + +$(PATH_STAGE_PREFIX).%/res/values/strings.xml: $(PATH_DIST)/mkplugin.sh $(srcdir)/configure $(PATH_DIST)/plugin-manifest.xml + @$(MKDIR) -p $(@D) + $(PATH_DIST)/mkplugin.sh $(srcdir)/configure $* $(PATH_DIST)/plugin-strings.xml $(ANDROID_PLUGIN_VERSIONCODE) $@ $(PATH_STAGE_PREFIX).%/res/drawable/scummvm.png: $(PATH_RESOURCES)/drawable/scummvm.png @$(MKDIR) -p $(@D) -- cgit v1.2.3 From b0351e1b85a550ec4f2422d4439e5ce17150f5a3 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sat, 9 Apr 2011 18:37:06 +0200 Subject: ANDROID: Automate the Manifest's versionCode --- backends/platform/android/android.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index fdb0f8096a..7cf6587cc0 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -1,7 +1,7 @@ # Android specific build targets # These must be incremented for each market upload -#ANDROID_VERSIONCODE = 6 Specified in dists/android/AndroidManifest.xml.in +ANDROID_VERSIONCODE = 6 ANDROID_PLUGIN_VERSIONCODE = 6 JAVA_FILES = \ @@ -72,7 +72,8 @@ PATH_GEN = $(PATH_GEN_TOP)/$(PATH_REL) PATH_CLASSES_MAIN = $(PATH_BUILD_CLASSES_MAIN_TOP)/$(PATH_REL) PATH_CLASSES_PLUGIN = $(PATH_BUILD_CLASSES_PLUGIN_TOP)/$(PATH_REL) -FILE_MANIFEST = $(srcdir)/dists/android/AndroidManifest.xml +FILE_MANIFEST_SRC = $(srcdir)/dists/android/AndroidManifest.xml +FILE_MANIFEST = $(PATH_BUILD)/AndroidManifest.xml FILE_DEX = $(PATH_BUILD)/classes.dex FILE_DEX_PLUGIN = $(PATH_BUILD)/plugins/classes.dex FILE_RESOURCES = resources.ap_ @@ -87,6 +88,9 @@ CLASSES_PLUGIN = $(addprefix $(PATH_CLASSES_PLUGIN)/, $(JAVA_FILES_PLUGIN:%.java APK_MAIN = scummvm.apk APK_PLUGINS = $(patsubst plugins/lib%.so, scummvm-engine-%.apk, $(PLUGINS)) +$(FILE_MANIFEST): $(FILE_MANIFEST_SRC) + sed "s/@ANDROID_VERSIONCODE@/$(ANDROID_VERSIONCODE)/" < $< > $@ + $(SRC_GEN): $(FILE_MANIFEST) $(filter %.xml,$(RESOURCES)) $(ANDROID_JAR8) @$(MKDIR) -p $(PATH_GEN_TOP) $(AAPT) package -m -J $(PATH_GEN_TOP) -M $< -S $(PATH_RESOURCES) -I $(ANDROID_JAR8) -- cgit v1.2.3 From 6c0bca8aae3c84d55f1a8abbbe4ee3c52e2a2427 Mon Sep 17 00:00:00 2001 From: dhewg Date: Sun, 10 Apr 2011 11:12:40 +0200 Subject: ANDROID: Add missing mkdir --- backends/platform/android/android.mk | 1 + 1 file changed, 1 insertion(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index 7cf6587cc0..77fdb139d8 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -89,6 +89,7 @@ APK_MAIN = scummvm.apk APK_PLUGINS = $(patsubst plugins/lib%.so, scummvm-engine-%.apk, $(PLUGINS)) $(FILE_MANIFEST): $(FILE_MANIFEST_SRC) + @$(MKDIR) -p $(@D) sed "s/@ANDROID_VERSIONCODE@/$(ANDROID_VERSIONCODE)/" < $< > $@ $(SRC_GEN): $(FILE_MANIFEST) $(filter %.xml,$(RESOURCES)) $(ANDROID_JAR8) -- cgit v1.2.3 From 877004dbdd967d2f57d494b1aaa1cb55aae0fd52 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 17 Apr 2011 21:14:19 +0200 Subject: BACKENDS: Adapt various backends code to set up Surface::format correctly. Note that this change is not tested at all (not even compile wise!). --- backends/platform/android/gfx.cpp | 4 ++-- backends/platform/android/texture.cpp | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index 86232030ff..fae428d29f 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -628,13 +628,13 @@ void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { GLTHREADCHECK; const Graphics::Surface *surface = _overlay_texture->surface_const(); - assert(surface->bytesPerPixel == sizeof(buf[0])); + assert(surface->format.bytesPerPixel == sizeof(buf[0])); const byte *src = (const byte *)surface->pixels; uint h = surface->h; do { - memcpy(buf, src, surface->w * surface->bytesPerPixel); + memcpy(buf, src, surface->w * surface->format.bytesPerPixel); src += surface->pitch; // This 'pitch' is pixels not bytes buf += pitch; diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index a6b28ca485..5931902906 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -148,6 +148,7 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) { _surface.w = w; _surface.h = h; _surface.bytesPerPixel = _pixelFormat.bytesPerPixel; + _surface.format = _pixelFormat; if (w == _texture_width && h == _texture_height) return; @@ -241,14 +242,14 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { delete[] _buf; delete[] _pixels; - _pixels = new byte[w * h * _surface.bytesPerPixel]; + _pixels = new byte[w * h * _surface.format.bytesPerPixel]; assert(_pixels); _surface.pixels = _pixels; fillBuffer(0); - _buf = new byte[w * h * _surface.bytesPerPixel]; + _buf = new byte[w * h * _surface.format.bytesPerPixel]; assert(_buf); } @@ -257,10 +258,10 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, setDirtyRect(Common::Rect(x, y, x + w, y + h)); const byte *src = (const byte *)buf; - byte *dst = _pixels + y * _surface.pitch + x * _surface.bytesPerPixel; + byte *dst = _pixels + y * _surface.pitch + x * _surface.format.bytesPerPixel; do { - memcpy(dst, src, w * _surface.bytesPerPixel); + memcpy(dst, src, w * _surface.format.bytesPerPixel); dst += _surface.pitch; src += pitch_buf; } while (--h); @@ -301,10 +302,10 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { _tex = _buf; byte *src = _pixels + _dirty_rect.top * _surface.pitch + - _dirty_rect.left * _surface.bytesPerPixel; + _dirty_rect.left * _surface.format.bytesPerPixel; byte *dst = _buf; - uint16 l = dwidth * _surface.bytesPerPixel; + uint16 l = dwidth * _surface.format.bytesPerPixel; for (uint16 i = 0; i < dheight; ++i) { memcpy(dst, src, l); @@ -374,6 +375,7 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); _surface.bytesPerPixel = 1; + _surface.format = Graphics::PixelFormat::createFormatCLUT8(); _surface.pitch = w; if (_surface.w == oldw && _surface.h == oldh) { -- cgit v1.2.3 From da734a4af024a72ee155bc25d6e45f994de6b060 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 17 Apr 2011 21:27:34 +0200 Subject: ALL/GRAPHICS: Remove Surface::bytesPerPixel. --- backends/platform/android/texture.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 5931902906..2d73783309 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -147,7 +147,6 @@ void GLESBaseTexture::setLinearFilter(bool value) { void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) { _surface.w = w; _surface.h = h; - _surface.bytesPerPixel = _pixelFormat.bytesPerPixel; _surface.format = _pixelFormat; if (w == _texture_width && h == _texture_height) @@ -374,7 +373,6 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { GLESBaseTexture::allocBuffer(w, h); - _surface.bytesPerPixel = 1; _surface.format = Graphics::PixelFormat::createFormatCLUT8(); _surface.pitch = w; -- cgit v1.2.3 From 1b681e85a8a0345d0ce848a7584a7654ad629f07 Mon Sep 17 00:00:00 2001 From: Ori Avtalion Date: Thu, 28 Apr 2011 20:05:01 +0300 Subject: ANDROID: Fix compilation --- backends/platform/android/android.h | 1 + backends/platform/android/asset-archive.cpp | 1 + backends/platform/android/jni.cpp | 1 + 3 files changed, 3 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 6eebdb97d9..109d252a99 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -31,6 +31,7 @@ #include "common/fs.h" #include "common/archive.h" #include "audio/mixer_intern.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "backends/base-backend.h" #include "backends/plugins/posix/posix-provider.h" diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index 8e95029894..7c21b35281 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -35,6 +35,7 @@ #include "common/util.h" #include "common/archive.h" #include "common/debug.h" +#include "common/textconsole.h" #include "backends/platform/android/jni.h" #include "backends/platform/android/asset-archive.h" diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 08a1491998..7962fa7b4b 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -28,6 +28,7 @@ #include "base/main.h" #include "base/version.h" #include "common/config-manager.h" +#include "common/textconsole.h" #include "engines/engine.h" #include "backends/platform/android/android.h" -- cgit v1.2.3 From 52c0b2e28c85658d0ae2d2522e6e2d02c4db8796 Mon Sep 17 00:00:00 2001 From: Ori Avtalion Date: Thu, 28 Apr 2011 20:53:01 +0300 Subject: ANDROID: Another attempt at compilation fix --- backends/platform/android/jni.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index 7962fa7b4b..f23d71b2a4 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -28,6 +28,7 @@ #include "base/main.h" #include "base/version.h" #include "common/config-manager.h" +#include "common/error.h" #include "common/textconsole.h" #include "engines/engine.h" -- cgit v1.2.3 From 8feac89bc7329f002d3c4beba370d9c6ea05e798 Mon Sep 17 00:00:00 2001 From: dhewg Date: Thu, 28 Apr 2011 20:02:01 +0200 Subject: ANDROID: Fix compilation some more --- backends/platform/android/android.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index bbfdb06b8d..c7f62f523b 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -32,6 +32,7 @@ #include #include "common/util.h" +#include "common/textconsole.h" #include "common/rect.h" #include "common/queue.h" #include "common/mutex.h" -- cgit v1.2.3 From ea547ca3fd09ccc2dcdc6af7026b24b0e1966859 Mon Sep 17 00:00:00 2001 From: dhewg Date: Mon, 2 May 2011 18:41:04 +0200 Subject: ANDROID: Style fix --- backends/platform/android/org/inodes/gus/scummvm/ScummVM.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform/android') diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 8bf40ac553..c4de6d62f8 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -35,7 +35,7 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { private String[] _args; - final private native void create(AssetManager _asset_manager, + final private native void create(AssetManager asset_manager, EGL10 egl, EGLDisplay egl_display, AudioTrack audio_track, int sample_rate, int buffer_size); -- cgit v1.2.3 From 3d4e9fe674d2daf59ff4b481fc2f89f77b390a4f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 3 May 2011 11:27:44 +0200 Subject: BACKENDS: Allow various files to use stuff from time.h --- backends/platform/android/android.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index c7f62f523b..7cf1e988fc 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -25,6 +25,9 @@ #if defined(__ANDROID__) +// Allow use of stuff in +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h + #include #include #include -- cgit v1.2.3 From a50c36d1381be2e7d0748a2c734e41357fd4920f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 3 May 2011 14:29:01 +0200 Subject: ANDROID: Fix various forbidden symbol clashes --- backends/platform/android/android.cpp | 14 ++++++++++++++ backends/platform/android/events.cpp | 17 +++++++++++++++++ backends/platform/android/gfx.cpp | 17 +++++++++++++++++ backends/platform/android/jni.cpp | 17 +++++++++++++++++ backends/platform/android/texture.cpp | 17 +++++++++++++++++ 5 files changed, 82 insertions(+) (limited to 'backends/platform/android') diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 7cf1e988fc..b1d0727d1f 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -28,6 +28,20 @@ // Allow use of stuff in #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 #include #include diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 09466b4d2f..2f140f0c0b 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -25,6 +25,23 @@ #if defined(__ANDROID__) +// Allow use of stuff in +#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/events.h" #include "backends/platform/android/android.h" diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index fae428d29f..ebce58e291 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -25,6 +25,23 @@ #if defined(__ANDROID__) +// Allow use of stuff in +#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/endian.h" #include "graphics/conversion.h" diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp index f23d71b2a4..13aef11fa2 100644 --- a/backends/platform/android/jni.cpp +++ b/backends/platform/android/jni.cpp @@ -25,6 +25,23 @@ #if defined(__ANDROID__) +// Allow use of stuff in +#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 "base/version.h" #include "common/config-manager.h" diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 2d73783309..c830676c07 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -25,6 +25,23 @@ #if defined(__ANDROID__) +// Allow use of stuff in +#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" -- cgit v1.2.3