diff options
Diffstat (limited to 'backends/platform')
-rw-r--r-- | backends/platform/android/android.cpp | 596 | ||||
-rw-r--r-- | backends/platform/android/android.mk | 18 | ||||
-rw-r--r-- | backends/platform/android/asset-archive.cpp | 166 | ||||
-rw-r--r-- | backends/platform/android/video.cpp | 85 | ||||
-rw-r--r-- | backends/platform/android/video.h | 128 |
5 files changed, 663 insertions, 330 deletions
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 125fd629d3..6566146313 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -78,14 +78,14 @@ extern "C" { void __assert(const char *file, int line, const char *expr) { __android_log_assert(expr, LOG_TAG, - "Assertion failure: '%s' in %s:%d", - expr, file, line); + "Assertion failure: '%s' in %s:%d", + expr, file, line); } void __assert2(const char *file, int line, const char *func, const char *expr) { __android_log_assert(expr, LOG_TAG, - "Assertion failure: '%s' in %s:%d (%s)", - expr, file, line, func); + "Assertion failure: '%s' in %s:%d (%s)", + expr, file, line, func); } } @@ -105,6 +105,7 @@ JNIEnv *JNU_GetEnv() { JNIEnv *env = 0; jint res = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2); + if (res != JNI_OK) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GetEnv() failed: %d", res); abort(); @@ -113,15 +114,17 @@ JNIEnv *JNU_GetEnv() { return env; } -static void JNU_ThrowByName(JNIEnv* env, const char* name, const char* msg) { +static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) { jclass cls = env->FindClass(name); - // if cls is NULL, an exception has already been thrown - if (cls != NULL) + + // if cls is 0, an exception has already been thrown + if (cls != 0) env->ThrowNew(cls, msg); + env->DeleteLocalRef(cls); } -// floating point. use sparingly. +// floating point. use sparingly template <class T> static inline T scalef(T in, float numerator, float denominator) { return static_cast<float>(in) * numerator / denominator; @@ -139,10 +142,9 @@ protected: }; #endif - #if 0 #define CHECK_GL_ERROR() checkGlError(__FILE__, __LINE__) -static const char* getGlErrStr(GLenum error) { +static const char *getGlErrStr(GLenum error) { switch (error) { case GL_NO_ERROR: return "GL_NO_ERROR"; case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; @@ -156,7 +158,7 @@ static const char* getGlErrStr(GLenum error) { snprintf(buf, sizeof(buf), "(Unknown GL error code 0x%x)", error); return buf; } -static void checkGlError(const char* file, int line) { +static void checkGlError(const char *file, int line) { GLenum error = glGetError(); if (error != GL_NO_ERROR) warning("%s:%d: GL error: %s", file, line, getGlErrStr(error)); @@ -167,7 +169,9 @@ static void checkGlError(const char* file, int line) { class OSystem_Android : public BaseBackend, public PaletteManager { private: - jobject _back_ptr; // back pointer to (java) peer instance + // back pointer to (java) peer instance + jobject _back_ptr; + jmethodID MID_displayMessageOnOSD; jmethodID MID_setWindowCaption; jmethodID MID_initBackend; @@ -186,16 +190,16 @@ private: bool _force_redraw; // Game layer - GLESPaletteTexture* _game_texture; + GLESPaletteTexture *_game_texture; int _shake_offset; Common::Rect _focus_rect; // Overlay layer - GLES4444Texture* _overlay_texture; + GLES4444Texture *_overlay_texture; bool _show_overlay; // Mouse layer - GLESPaletteATexture* _mouse_texture; + GLESPaletteATexture *_mouse_texture; Common::Point _mouse_hotspot; int _mouse_targetscale; bool _show_mouse; @@ -206,7 +210,7 @@ private: bool _timer_thread_exit; pthread_t _timer_thread; - static void* timerThreadFunc(void* arg); + static void *timerThreadFunc(void *arg); bool _enable_zoning; bool _virtkeybd_on; @@ -226,9 +230,9 @@ private: public: OSystem_Android(jobject am); virtual ~OSystem_Android(); - bool initJavaHooks(JNIEnv* env, jobject self); + bool initJavaHooks(JNIEnv *env, jobject self); - static OSystem_Android* fromJavaObject(JNIEnv* env, jobject obj); + static OSystem_Android *fromJavaObject(JNIEnv *env, jobject obj); virtual void initBackend(); void addPluginDirectories(Common::FSList &dirs) const; void enableZoning(bool enable) { _enable_zoning = enable; } @@ -246,12 +250,19 @@ public: 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; } + const Graphics::PixelFormat *format); + + virtual int getScreenChangeID() const { + return _screen_changeid; + } + virtual int16 getHeight(); virtual int16 getWidth(); - virtual PaletteManager *getPaletteManager() { return this; } + virtual PaletteManager *getPaletteManager() { + return this; + } + protected: // PaletteManager API virtual void setPalette(const byte *colors, uint start, uint num); @@ -274,18 +285,21 @@ public: 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 { - // RGBA 4444 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; + format.rShift = 3 * 4; + format.gShift = 2 * 4; + format.bShift = 1 * 4; + format.aShift = 0 * 4; + return format; } @@ -321,49 +335,54 @@ public: virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); }; -OSystem_Android::OSystem_Android(jobject am) - : _back_ptr(0), - _screen_changeid(0), - _force_redraw(false), - _game_texture(NULL), - _overlay_texture(NULL), - _mouse_texture(NULL), - _use_mouse_palette(false), - _show_mouse(false), - _show_overlay(false), - _enable_zoning(false), - _savefile(0), - _mixer(0), - _timer(0), - _fsFactory(new POSIXFilesystemFactory()), - _asset_archive(new AndroidAssetArchive(am)), - _shake_offset(0), - _event_queue_lock(createMutex()) { +OSystem_Android::OSystem_Android(jobject am) : + _back_ptr(0), + _screen_changeid(0), + _force_redraw(false), + _game_texture(0), + _overlay_texture(0), + _mouse_texture(0), + _use_mouse_palette(false), + _show_mouse(false), + _show_overlay(false), + _enable_zoning(false), + _savefile(0), + _mixer(0), + _timer(0), + _fsFactory(new POSIXFilesystemFactory()), + _asset_archive(new AndroidAssetArchive(am)), + _shake_offset(0), + _event_queue_lock(createMutex()) { } OSystem_Android::~OSystem_Android() { ENTER("~OSystem_Android()"); + delete _game_texture; delete _overlay_texture; delete _mouse_texture; + destroyScummVMSurface(); - JNIEnv* env = JNU_GetEnv(); + + JNIEnv *env = JNU_GetEnv(); //env->DeleteWeakGlobalRef(_back_ptr); env->DeleteGlobalRef(_back_ptr); + delete _savefile; delete _mixer; delete _timer; delete _fsFactory; delete _asset_archive; + deleteMutex(_event_queue_lock); } -OSystem_Android* OSystem_Android::fromJavaObject(JNIEnv* env, jobject obj) { +OSystem_Android *OSystem_Android::fromJavaObject(JNIEnv *env, jobject obj) { jlong peer = env->GetLongField(obj, FID_ScummVM_nativeScummVM); - return (OSystem_Android*)peer; + return (OSystem_Android *)peer; } -bool OSystem_Android::initJavaHooks(JNIEnv* env, jobject self) { +bool OSystem_Android::initJavaHooks(JNIEnv *env, jobject self) { // weak global ref to allow class to be unloaded // ... except dalvik doesn't implement NewWeakGlobalRef (yet) //_back_ptr = env->NewWeakGlobalRef(self); @@ -373,7 +392,7 @@ bool OSystem_Android::initJavaHooks(JNIEnv* env, jobject self) { #define FIND_METHOD(name, signature) do { \ MID_ ## name = env->GetMethodID(cls, #name, signature); \ - if (MID_ ## name == NULL) \ + if (MID_ ## name == 0) \ return false; \ } while (0) @@ -393,10 +412,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); +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)) - // Exception already thrown by initJavaHooks return; env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)cpp_obj); @@ -406,56 +426,69 @@ static void ScummVM_create(JNIEnv* env, jobject self, jobject am) { #endif } -static void ScummVM_nativeDestroy(JNIEnv* env, jobject self) { - OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +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); +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, NULL); - if (buf == NULL) { + jbyte *buf = env->GetByteArrayElements(jbuf, 0); + + if (buf == 0) { warning("Unable to get Java audio byte array. Skipping"); return; } - Audio::MixerImpl* mixer = - static_cast<Audio::MixerImpl*>(cpp_obj->getMixer()); + + Audio::MixerImpl *mixer = + static_cast<Audio::MixerImpl *>(cpp_obj->getMixer()); assert(mixer); - mixer->mixCallback(reinterpret_cast<byte*>(buf), len); + mixer->mixCallback(reinterpret_cast<byte *>(buf), len); + env->ReleaseByteArrayElements(jbuf, buf, 0); } -static void ScummVM_setConfManInt(JNIEnv* env, jclass cls, - jstring key_obj, jint value) { +static void ScummVM_setConfManInt(JNIEnv *env, jclass cls, + jstring key_obj, jint value) { ENTER("setConfManInt(%p, %d)", key_obj, (int)value); - const char* key = env->GetStringUTFChars(key_obj, NULL); - if (key == NULL) + + 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) { +static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj, + jstring value_obj) { ENTER("setConfManStr(%p, %p)", key_obj, value_obj); - const char* key = env->GetStringUTFChars(key_obj, NULL); - if (key == NULL) + + const char *key = env->GetStringUTFChars(key_obj, 0); + + if (key == 0) return; - const char* value = env->GetStringUTFChars(value_obj, NULL); - if (value == NULL) { + + 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); +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); @@ -471,7 +504,7 @@ void* OSystem_Android::timerThreadFunc(void* arg) { while (!system->_timer_thread_exit) { timer->handler(); - nanosleep(&tv, NULL); + nanosleep(&tv, 0); } res = cached_jvm->DetachCurrentThread(); @@ -481,12 +514,13 @@ void* OSystem_Android::timerThreadFunc(void* arg) { abort(); } - return NULL; + return 0; } void OSystem_Android::initBackend() { ENTER("initBackend()"); - JNIEnv* env = JNU_GetEnv(); + + JNIEnv *env = JNU_GetEnv(); ConfMan.setInt("autosave_period", 0); ConfMan.setInt("FM_medium_quality", true); @@ -496,32 +530,37 @@ void OSystem_Android::initBackend() { setupKeymapper(); // BUG: "transient" ConfMan settings get nuked by the options - // screen. Passing the savepath in this way makes it stick + // screen. Passing the savepath in this way makes it stick // (via ConfMan.registerDefault) _savefile = new DefaultSaveFileManager(ConfMan.get("savepath")); _timer = new DefaultTimerManager(); - gettimeofday(&_startTime, NULL); + 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->setReady(true); env->CallVoidMethod(_back_ptr, MID_initBackend); + if (env->ExceptionCheck()) { error("Error in Java initBackend"); + env->ExceptionDescribe(); env->ExceptionClear(); } _timer_thread_exit = false; - pthread_create(&_timer_thread, NULL, timerThreadFunc, this); + pthread_create(&_timer_thread, 0, timerThreadFunc, this); OSystem::initBackend(); @@ -530,30 +569,39 @@ void OSystem_Android::initBackend() { void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { ENTER("OSystem_Android::addPluginDirectories()"); - JNIEnv* env = JNU_GetEnv(); + + JNIEnv *env = JNU_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 == NULL) + + if (path_obj == 0) continue; - const char* path = env->GetStringUTFChars(path_obj, NULL); - if (path == NULL) { + + 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); } @@ -561,12 +609,13 @@ void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { bool OSystem_Android::hasFeature(Feature f) { return (f == kFeatureCursorHasPalette || - f == kFeatureVirtualKeyboard || - f == kFeatureOverlaySupportsAlpha); + f == kFeatureVirtualKeyboard || + f == kFeatureOverlaySupportsAlpha); } void OSystem_Android::setFeatureState(Feature f, bool enable) { ENTER("setFeatureState(%d, %d)", f, enable); + switch (f) { case kFeatureVirtualKeyboard: _virtkeybd_on = enable; @@ -586,11 +635,12 @@ bool OSystem_Android::getFeatureState(Feature f) { } } -const OSystem::GraphicsMode* OSystem_Android::getSupportedGraphicsModes() const { +const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const { static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { - {"default", "Default", 1}, - {0, 0, 0}, + { "default", "Default", 1 }, + { 0, 0, 0 }, }; + return s_supportedGraphicsModes; } @@ -615,13 +665,14 @@ int OSystem_Android::getGraphicsMode() const { void OSystem_Android::setupScummVMSurface() { ENTER("setupScummVMSurface"); - JNIEnv* env = JNU_GetEnv(); + + 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 ;) @@ -630,6 +681,7 @@ void OSystem_Android::setupScummVMSurface() { glDisable(GL_LIGHTING); glDisable(GL_FOG); glDisable(GL_DITHER); + glShadeModel(GL_FLAT); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); @@ -669,13 +721,13 @@ void OSystem_Android::setupScummVMSurface() { } void OSystem_Android::destroyScummVMSurface() { - JNIEnv* env = JNU_GetEnv(); + 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) { + const Graphics::PixelFormat *format) { ENTER("initSize(%d,%d,%p)", width, height, format); _game_texture->allocBuffer(width, height); @@ -700,16 +752,18 @@ int16 OSystem_Android::getWidth() { return _game_texture->width(); } -void OSystem_Android::setPalette(const byte* colors, uint start, uint num) { +void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { ENTER("setPalette(%p, %u, %u)", colors, start, num); if (!_use_mouse_palette) _setCursorPalette(colors, start, num); - byte* palette = _game_texture->palette() + start*3; + byte *palette = _game_texture->palette() + start * 3; + do { for (int i = 0; i < 3; ++i) palette[i] = colors[i]; + palette += 3; colors += 4; } while (--num); @@ -717,11 +771,15 @@ void OSystem_Android::setPalette(const byte* colors, uint start, uint num) { void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { ENTER("grabPalette(%p, %u, %u)", colors, start, num); - const byte* palette = _game_texture->palette_const() + start*3; + + const byte *palette = _game_texture->palette_const() + start * 3; + do { for (int i = 0; i < 3; ++i) colors[i] = palette[i]; - colors[3] = 0xff; // alpha + + // alpha + colors[3] = 0xff; palette += 3; colors += 4; @@ -729,9 +787,9 @@ void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { } void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, - int x, int y, int w, int h) { + int x, int y, int w, int h) { ENTER("copyRectToScreen(%p, %d, %d, %d, %d, %d)", - buf, pitch, x, y, w, h); + buf, pitch, x, y, w, h); _game_texture->updateBuffer(x, y, w, h, buf, pitch); } @@ -740,9 +798,9 @@ void OSystem_Android::updateScreen() { //ENTER("updateScreen()"); if (!_force_redraw && - !_game_texture->dirty() && - !_overlay_texture->dirty() && - !_mouse_texture->dirty()) + !_game_texture->dirty() && + !_overlay_texture->dirty() && + !_mouse_texture->dirty()) return; _force_redraw = false; @@ -750,9 +808,9 @@ void OSystem_Android::updateScreen() { glPushMatrix(); if (_shake_offset != 0 || - (!_focus_rect.isEmpty() && - !Common::Rect(_game_texture->width(), - _game_texture->height()).contains(_focus_rect))) { + (!_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. glClearColorx(0, 0, 0, 1 << 16); @@ -764,18 +822,19 @@ void OSystem_Android::updateScreen() { if (_focus_rect.isEmpty()) { _game_texture->drawTexture(0, 0, - _egl_surface_width, _egl_surface_height); + _egl_surface_width, _egl_surface_height); } else { glPushMatrix(); glScalex(xdiv(_egl_surface_width, _focus_rect.width()), - xdiv(_egl_surface_height, _focus_rect.height()), - 1 << 16); + xdiv(_egl_surface_height, _focus_rect.height()), + 1 << 16); glTranslatex(-_focus_rect.left << 16, -_focus_rect.top << 16, 0); glScalex(xdiv(_game_texture->width(), _egl_surface_width), - xdiv(_game_texture->height(), _egl_surface_height), - 1 << 16); + xdiv(_game_texture->height(), _egl_surface_height), + 1 << 16); + _game_texture->drawTexture(0, 0, - _egl_surface_width, _egl_surface_height); + _egl_surface_width, _egl_surface_height); glPopMatrix(); } @@ -783,8 +842,8 @@ void OSystem_Android::updateScreen() { if (_show_overlay) { _overlay_texture->drawTexture(0, 0, - _egl_surface_width, - _egl_surface_height); + _egl_surface_width, + _egl_surface_height); CHECK_GL_ERROR(); } @@ -792,11 +851,12 @@ void OSystem_Android::updateScreen() { glPushMatrix(); glTranslatex(-_mouse_hotspot.x << 16, - -_mouse_hotspot.y << 16, - 0); + -_mouse_hotspot.y << 16, + 0); // Scale up ScummVM -> OpenGL (pixel) coordinates int texwidth, texheight; + if (_show_overlay) { texwidth = getOverlayWidth(); texheight = getOverlayHeight(); @@ -804,15 +864,16 @@ void OSystem_Android::updateScreen() { texwidth = getWidth(); texheight = getHeight(); } + glScalex(xdiv(_egl_surface_width, texwidth), - xdiv(_egl_surface_height, texheight), - 1 << 16); + xdiv(_egl_surface_height, texheight), + 1 << 16); // Note the extra half texel to position the mouse in // the middle of the x,y square: const Common::Point& mouse = getEventManager()->getMousePos(); glTranslatex((mouse.x << 16) | 1 << 15, - (mouse.y << 16) | 1 << 15, 0); + (mouse.y << 16) | 1 << 15, 0); // Mouse targetscale just seems to make the cursor way // too big :/ @@ -828,7 +889,7 @@ void OSystem_Android::updateScreen() { CHECK_GL_ERROR(); - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) { // Context lost -> need to reinit GL destroyScummVMSurface(); @@ -838,18 +899,22 @@ void OSystem_Android::updateScreen() { Graphics::Surface *OSystem_Android::lockScreen() { ENTER("lockScreen()"); - Graphics::Surface* surface = _game_texture->surface(); + + Graphics::Surface *surface = _game_texture->surface(); assert(surface->pixels); + return surface; } void OSystem_Android::unlockScreen() { ENTER("unlockScreen()"); + assert(_game_texture->dirty()); } void OSystem_Android::setShakePos(int shake_offset) { ENTER("setShakePos(%d)", shake_offset); + if (_shake_offset != shake_offset) { _shake_offset = shake_offset; _force_redraw = true; @@ -858,13 +923,15 @@ void OSystem_Android::setShakePos(int shake_offset) { void OSystem_Android::fillScreen(uint32 col) { ENTER("fillScreen(%u)", col); + assert(col < 256); _game_texture->fillBuffer(col); } void OSystem_Android::setFocusRectangle(const Common::Rect& rect) { ENTER("setFocusRectangle(%d,%d,%d,%d)", - rect.left, rect.top, rect.right, rect.bottom); + rect.left, rect.top, rect.right, rect.bottom); + if (_enable_zoning) { _focus_rect = rect; _force_redraw = true; @@ -873,6 +940,7 @@ void OSystem_Android::setFocusRectangle(const Common::Rect& rect) { void OSystem_Android::clearFocusRectangle() { ENTER("clearFocusRectangle()"); + if (_enable_zoning) { _focus_rect = Common::Rect(); _force_redraw = true; @@ -881,18 +949,21 @@ void OSystem_Android::clearFocusRectangle() { void OSystem_Android::showOverlay() { ENTER("showOverlay()"); + _show_overlay = true; _force_redraw = true; } void OSystem_Android::hideOverlay() { ENTER("hideOverlay()"); + _show_overlay = false; _force_redraw = true; } void OSystem_Android::clearOverlay() { ENTER("clearOverlay()"); + _overlay_texture->fillBuffer(0); // Shouldn't need this, but works around a 'blank screen' bug on Nexus1 @@ -901,23 +972,29 @@ void OSystem_Android::clearOverlay() { void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { ENTER("grabOverlay(%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(); + 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])); - buf += pitch; // This 'pitch' is pixels not bytes + + // 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) { + int x, int y, int w, int h) { ENTER("copyRectToOverlay(%p, %d, %d, %d, %d, %d)", - buf, pitch, x, y, w, h); - const Graphics::Surface* surface = _overlay_texture->surface_const(); + 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 @@ -937,37 +1014,43 @@ int16 OSystem_Android::getOverlayWidth() { bool OSystem_Android::showMouse(bool visible) { ENTER("showMouse(%d)", visible); + _show_mouse = visible; + return true; } void OSystem_Android::warpMouse(int x, int y) { ENTER("warpMouse(%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) { + int hotspotX, int hotspotY, + uint32 keycolor, int cursorTargetScale, + const Graphics::PixelFormat *format) { ENTER("setMouseCursor(%p, %u, %u, %d, %d, %d, %d, %p)", - buf, w, h, hotspotX, hotspotY, (int)keycolor, cursorTargetScale, - format); + buf, w, h, hotspotX, hotspotY, (int)keycolor, cursorTargetScale, + format); assert(keycolor < 256); _mouse_texture->allocBuffer(w, h); // Update palette alpha based on keycolor - byte* palette = _mouse_texture->palette(); + 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; + palette[keycolor * 4 + 3] = 0x00; + _mouse_texture->updateBuffer(0, 0, w, h, buf, w); _mouse_hotspot = Common::Point(hotspotX, hotspotY); @@ -975,11 +1058,13 @@ 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; + 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; @@ -988,14 +1073,16 @@ void OSystem_Android::_setCursorPalette(const byte *colors, } void OSystem_Android::setCursorPalette(const byte *colors, - uint start, uint num) { + uint start, uint num) { ENTER("setCursorPalette(%p, %u, %u)", colors, start, num); + _setCursorPalette(colors, start, num); _use_mouse_palette = true; } void OSystem_Android::disableCursorPalette(bool disable) { ENTER("disableCursorPalette(%d)", disable); + _use_mouse_palette = !disable; } @@ -1006,17 +1093,19 @@ void OSystem_Android::setupKeymapper() { 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); + kVirtualKeyboardActionType); act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0)); mapper->addGlobalKeymap(globalMap); @@ -1027,11 +1116,14 @@ void OSystem_Android::setupKeymapper() { bool OSystem_Android::pollEvent(Common::Event &event) { //ENTER("pollEvent()"); + lockMutex(_event_queue_lock); + if (_event_queue.empty()) { unlockMutex(_event_queue_lock); return false; } + event = _event_queue.pop(); unlockMutex(_event_queue_lock); @@ -1048,26 +1140,27 @@ bool OSystem_Android::pollEvent(Common::Event &event) { case Common::EVENT_WHEELDOWN: case Common::EVENT_MBUTTONDOWN: case Common::EVENT_MBUTTONUP: { - if (event.kbd.flags == 1) { // relative mouse hack + // 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()); + getOverlayWidth() : getWidth()); event.mouse.y = CLIP(event.mouse.y, (int16)0, _show_overlay ? - getOverlayHeight() : getHeight()); + getOverlayHeight() : getHeight()); } else { // Touchscreen events need to be converted // from device to game coords first. - const GLESTexture* tex = _show_overlay - ? static_cast<GLESTexture*>(_overlay_texture) - : static_cast<GLESTexture*>(_game_texture); + const GLESTexture *tex = _show_overlay + ? static_cast<GLESTexture *>(_overlay_texture) + : static_cast<GLESTexture *>(_game_texture); event.mouse.x = scalef(event.mouse.x, tex->width(), - _egl_surface_width); + _egl_surface_width); event.mouse.y = scalef(event.mouse.y, tex->height(), - _egl_surface_height); + _egl_surface_height); event.mouse.x -= _shake_offset; } break; @@ -1090,32 +1183,33 @@ void OSystem_Android::pushEvent(const Common::Event& event) { // 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 - tail.kbd.flags = 0; // clear relative flag - tail.mouse.x = event.mouse.x; - tail.mouse.y = event.mouse.y; - } - } - else + !_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); + } unlockMutex(_event_queue_lock); } -static void ScummVM_pushEvent(JNIEnv* env, jobject self, jobject java_event) { - OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +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); + FID_Event_type); + event.synthetic = env->GetBooleanField(java_event, FID_Event_synthetic); @@ -1157,7 +1251,9 @@ static void ScummVM_pushEvent(JNIEnv* env, jobject self, jobject java_event) { uint32 OSystem_Android::getMillis() { timeval curTime; - gettimeofday(&curTime, NULL); + + gettimeofday(&curTime, 0); + return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \ ((curTime.tv_usec - _startTime.tv_usec) / 1000)); } @@ -1172,26 +1268,31 @@ OSystem::MutexRef OSystem_Android::createMutex() { pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_t *mutex = new pthread_mutex_t; + if (pthread_mutex_init(mutex, &attr) != 0) { warning("pthread_mutex_init() failed"); + delete mutex; - return NULL; + + return 0; } + return (MutexRef)mutex; } void OSystem_Android::lockMutex(MutexRef mutex) { - if (pthread_mutex_lock((pthread_mutex_t*)mutex) != 0) + if (pthread_mutex_lock((pthread_mutex_t *)mutex) != 0) warning("pthread_mutex_lock() failed"); } void OSystem_Android::unlockMutex(MutexRef mutex) { - if (pthread_mutex_unlock((pthread_mutex_t*)mutex) != 0) + if (pthread_mutex_unlock((pthread_mutex_t *)mutex) != 0) warning("pthread_mutex_unlock() failed"); } void OSystem_Android::deleteMutex(MutexRef mutex) { - pthread_mutex_t* m = (pthread_mutex_t*)mutex; + pthread_mutex_t *m = (pthread_mutex_t *)mutex; + if (pthread_mutex_destroy(m) != 0) warning("pthread_mutex_destroy() failed"); else @@ -1202,41 +1303,54 @@ void OSystem_Android::quit() { ENTER("quit()"); _timer_thread_exit = true; - pthread_join(_timer_thread, NULL); + pthread_join(_timer_thread, 0); } void OSystem_Android::setWindowCaption(const char *caption) { ENTER("setWindowCaption(%s)", caption); - JNIEnv* env = JNU_GetEnv(); + + JNIEnv *env = JNU_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); } void OSystem_Android::displayMessageOnOSD(const char *msg) { ENTER("displayMessageOnOSD(%s)", msg); - JNIEnv* env = JNU_GetEnv(); + + JNIEnv *env = JNU_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); } void OSystem_Android::showVirtualKeyboard(bool enable) { ENTER("showVirtualKeyboard(%d)", enable); - JNIEnv* env = JNU_GetEnv(); + + JNIEnv *env = JNU_GetEnv(); + env->CallVoidMethod(_back_ptr, MID_showVirtualKeyboard, enable); + if (env->ExceptionCheck()) { error("Error trying to show virtual keyboard"); + env->ExceptionDescribe(); env->ExceptionClear(); } @@ -1259,7 +1373,8 @@ Common::TimerManager *OSystem_Android::getTimerManager() { void OSystem_Android::getTimeAndDate(TimeDate &td) const { struct tm tm; - const time_t curTime = time(NULL); + const time_t curTime = time(0); + localtime_r(&curTime, &tm); td.tm_sec = tm.tm_sec; td.tm_min = tm.tm_min; @@ -1274,28 +1389,33 @@ FilesystemFactory *OSystem_Android::getFilesystemFactory() { } void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, - int priority) { + int priority) { s.add("ASSET", _asset_archive, priority, false); - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); jobjectArray array = (jobjectArray)env->CallObjectMethod(_back_ptr, 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, NULL); - if (path != NULL) { + 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); } } @@ -1316,8 +1436,8 @@ 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); +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; @@ -1325,42 +1445,58 @@ static jint ScummVM_scummVMMain(JNIEnv* env, jobject self, jobjectArray args) { int argc = env->GetArrayLength(args); if (argc > MAX_NARGS) { JNU_ThrowByName(env, "java/lang/IllegalArgumentException", - "too many arguments"); + "too many arguments"); return 0; } - char* argv[MAX_NARGS]; - int nargs; // note use in cleanup loop below + 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 == NULL) { - argv[nargs] = NULL; + + if (arg == 0) { + argv[nargs] = 0; } else { - const char* cstr = env->GetStringUTFChars(arg, NULL); - argv[nargs] = const_cast<char*>(cstr); - if (cstr == NULL) - goto cleanup; // exception already thrown + const char *cstr = env->GetStringUTFChars(arg, 0); + + argv[nargs] = const_cast<char *>(cstr); + + // exception already thrown? + if (cstr == 0) + goto cleanup; } + env->DeleteLocalRef(arg); } g_system = cpp_obj; assert(g_system); + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, - "Entering scummvm_main with %d args", argc); + "Entering scummvm_main with %d args", argc); + res = scummvm_main(argc, argv); + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Exiting scummvm_main"); + g_system->quit(); cleanup: nargs--; + for (int i = 0; i < nargs; ++i) { - if (argv[i] == NULL) + if (argv[i] == 0) continue; + jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); - if (arg == NULL) - // Exception already thrown + + // Exception already thrown? + if (arg == 0) return res; + env->ReleaseStringUTFChars(arg, argv[i]); env->DeleteLocalRef(arg); } @@ -1370,93 +1506,105 @@ cleanup: #ifdef DYNAMIC_MODULES void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const { - OSystem_Android* g_system_android = (OSystem_Android*)g_system; + OSystem_Android *g_system_android = (OSystem_Android *)g_system; g_system_android->addPluginDirectories(dirs); } #endif -static void ScummVM_enableZoning(JNIEnv* env, jobject self, jboolean enable) { - OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); +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); +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 }, + (void *)ScummVM_create }, + { "nativeDestroy", "()V", + (void *)ScummVM_nativeDestroy }, { "scummVMMain", "([Ljava/lang/String;)I", - (void*)ScummVM_scummVMMain }, + (void *)ScummVM_scummVMMain }, { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", - (void*)ScummVM_pushEvent }, + (void *)ScummVM_pushEvent }, { "audioMixCallback", "([B)V", - (void*)ScummVM_audioMixCallback }, + (void *)ScummVM_audioMixCallback }, { "setConfMan", "(Ljava/lang/String;I)V", - (void*)ScummVM_setConfManInt }, + (void *)ScummVM_setConfManInt }, { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V", - (void*)ScummVM_setConfManString }, + (void *)ScummVM_setConfManString }, { "enableZoning", "(Z)V", - (void*)ScummVM_enableZoning }, + (void *)ScummVM_enableZoning }, { "setSurfaceSize", "(II)V", - (void*)ScummVM_setSurfaceSize }, + (void *)ScummVM_setSurfaceSize }, }; JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM* jvm, void* reserved) { +JNI_OnLoad(JavaVM *jvm, void *reserved) { cached_jvm = jvm; - JNIEnv* env; - if (jvm->GetEnv((void**)&env, JNI_VERSION_1_2)) + 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 == NULL) + 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 == NULL) + if (FID_ScummVM_nativeScummVM == 0) return JNI_ERR; jclass event = env->FindClass("org/inodes/gus/scummvm/Event"); - if (event == NULL) + if (event == 0) return JNI_ERR; + FID_Event_type = env->GetFieldID(event, "type", "I"); - if (FID_Event_type == NULL) + if (FID_Event_type == 0) return JNI_ERR; + FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z"); - if (FID_Event_synthetic == NULL) + if (FID_Event_synthetic == 0) return JNI_ERR; + FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I"); - if (FID_Event_kbd_keycode == NULL) + if (FID_Event_kbd_keycode == 0) return JNI_ERR; + FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I"); - if (FID_Event_kbd_ascii == NULL) + if (FID_Event_kbd_ascii == 0) return JNI_ERR; + FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I"); - if (FID_Event_kbd_flags == NULL) + if (FID_Event_kbd_flags == 0) return JNI_ERR; + FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I"); - if (FID_Event_mouse_x == NULL) + if (FID_Event_mouse_x == 0) return JNI_ERR; + FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I"); - if (FID_Event_mouse_y == NULL) + if (FID_Event_mouse_y == 0) return JNI_ERR; + FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z"); - if (FID_Event_mouse_relative == NULL) + if (FID_Event_mouse_relative == 0) return JNI_ERR; cls = env->FindClass("java/lang/Object"); - if (cls == NULL) + if (cls == 0) return JNI_ERR; + MID_Object_wait = env->GetMethodID(cls, "wait", "()V"); - if (MID_Object_wait == NULL) + if (MID_Object_wait == 0) return JNI_ERR; return JNI_VERSION_1_2; diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index a99078581e..1bc3c3d21a 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -109,12 +109,12 @@ $(FILE_DEX_PLUGIN): $(CLASSES_PLUGIN) $(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 + --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_STAGE_PREFIX).%/res/drawable/scummvm.png: $(PATH_RESOURCES)/drawable/scummvm.png @$(MKDIR) -p $(@D) @@ -165,7 +165,7 @@ androidrelease: $(addprefix release/, $(APK_MAIN) $(APK_PLUGINS)) androidtest: $(APK_MAIN) $(APK_PLUGINS) @set -e; for apk in $^; do \ - $(ADB) install -r $$apk; \ + $(ADB) install -r $$apk; \ done $(ADB) shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n org.inodes.gus.scummvm/.Unpacker @@ -173,7 +173,9 @@ androidtest: $(APK_MAIN) $(APK_PLUGINS) androiddistdebug: all $(MKDIR) debug $(CP) $(APK_MAIN) $(APK_PLUGINS) debug/ - for i in $(DIST_FILES_DOCS); do sed 's/$$/\r/' < $$i > debug/`basename $$i`.txt; done + for i in $(DIST_FILES_DOCS); do \ + sed 's/$$/\r/' < $$i > debug/`basename $$i`.txt; \ + done .PHONY: androidrelease androidtest diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index bd32847f6a..3197c75b82 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -38,7 +38,7 @@ #include "backends/platform/android/asset-archive.h" -extern JNIEnv* JNU_GetEnv(); +extern JNIEnv *JNU_GetEnv(); // Must match android.content.res.AssetManager.ACCESS_* const jint ACCESS_UNKNOWN = 0; @@ -47,23 +47,43 @@ const jint ACCESS_RANDOM = 1; // This might be useful to someone else. Assumes markSupported() == true. class JavaInputStream : public Common::SeekableReadStream { public: - JavaInputStream(JNIEnv* env, jobject is); + JavaInputStream(JNIEnv *env, jobject is); virtual ~JavaInputStream(); - virtual bool eos() const { return _eos; } - virtual bool err() const { return _err; } - virtual void clearErr() { _eos = _err = false; } + + virtual bool eos() const { + return _eos; + } + + virtual bool err() const { + return _err; + } + + virtual void clearErr() { + _eos = _err = false; + } + virtual uint32 read(void *dataPtr, uint32 dataSize); - virtual int32 pos() const { return _pos; } - virtual int32 size() const { return _len; } + + virtual int32 pos() const { + return _pos; + } + + virtual int32 size() const { + return _len; + } + virtual bool seek(int32 offset, int whence = SEEK_SET); + private: - void close(JNIEnv* env); + void close(JNIEnv *env); + jmethodID MID_mark; jmethodID MID_available; jmethodID MID_close; jmethodID MID_read; jmethodID MID_reset; jmethodID MID_skip; + jobject _input_stream; jsize _buflen; jbyteArray _buf; @@ -73,8 +93,10 @@ private: bool _err; }; -JavaInputStream::JavaInputStream(JNIEnv* env, jobject is) : - _eos(false), _err(false), _pos(0) +JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) : + _eos(false), + _err(false), + _pos(0) { _input_stream = env->NewGlobalRef(is); _buflen = 8192; @@ -97,53 +119,61 @@ JavaInputStream::JavaInputStream(JNIEnv* env, jobject is) : // Mark start of stream, so we can reset back to it. // readlimit is set to something bigger than anything we might // want to seek within. - env->CallVoidMethod(_input_stream, MID_mark, 10*1024*1024); + env->CallVoidMethod(_input_stream, MID_mark, 10 * 1024 * 1024); _len = env->CallIntMethod(_input_stream, MID_available); } JavaInputStream::~JavaInputStream() { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); close(env); + env->DeleteGlobalRef(_buf); env->DeleteGlobalRef(_input_stream); } -void JavaInputStream::close(JNIEnv* env) { +void JavaInputStream::close(JNIEnv *env) { env->CallVoidMethod(_input_stream, MID_close); + if (env->ExceptionCheck()) env->ExceptionClear(); } uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); if (_buflen < dataSize) { _buflen = dataSize; + env->DeleteGlobalRef(_buf); _buf = static_cast<jbyteArray>(env->NewGlobalRef(env->NewByteArray(_buflen))); } jint ret = env->CallIntMethod(_input_stream, MID_read, _buf, 0, dataSize); + if (env->ExceptionCheck()) { warning("Exception during JavaInputStream::read(%p, %d)", dataPtr, dataSize); + env->ExceptionDescribe(); env->ExceptionClear(); + _err = true; ret = -1; } else if (ret == -1) { _eos = true; ret = 0; } else { - env->GetByteArrayRegion(_buf, 0, ret, static_cast<jbyte*>(dataPtr)); + env->GetByteArrayRegion(_buf, 0, ret, static_cast<jbyte *>(dataPtr)); _pos += ret; } + return ret; } bool JavaInputStream::seek(int32 offset, int whence) { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); uint32 newpos; + switch (whence) { case SEEK_SET: newpos = offset; @@ -165,37 +195,47 @@ bool JavaInputStream::seek(int32 offset, int whence) { } else { // Can't skip backwards, so jump back to start and skip from there. env->CallVoidMethod(_input_stream, MID_reset); + if (env->ExceptionCheck()) { warning("Failed to rewind to start of asset stream"); + env->ExceptionDescribe(); env->ExceptionClear(); + return false; } + _pos = 0; skip_bytes = newpos; } while (skip_bytes > 0) { jlong ret = env->CallLongMethod(_input_stream, MID_skip, skip_bytes); + if (env->ExceptionCheck()) { warning("Failed to skip %ld bytes into asset stream", static_cast<long>(skip_bytes)); + env->ExceptionDescribe(); env->ExceptionClear(); + return false; } else if (ret == 0) { warning("InputStream->skip(%ld) didn't skip any bytes. Aborting seek.", static_cast<long>(skip_bytes)); - return false; // No point looping forever... + + // No point looping forever... + return false; } + _pos += ret; skip_bytes -= ret; } + _eos = false; return true; } - // Must match android.content.res.AssetFileDescriptor.UNKNOWN_LENGTH const jlong UNKNOWN_LENGTH = -1; @@ -203,17 +243,36 @@ const jlong UNKNOWN_LENGTH = -1; // worth optimising for. class AssetFdReadStream : public Common::SeekableReadStream { public: - AssetFdReadStream(JNIEnv* env, jobject assetfd); + AssetFdReadStream(JNIEnv *env, jobject assetfd); virtual ~AssetFdReadStream(); - virtual bool eos() const { return _eos; } - virtual bool err() const { return _err; } - virtual void clearErr() { _eos = _err = false; } + + virtual bool eos() const { + return _eos; + } + + virtual bool err() const { + return _err; + } + + virtual void clearErr() { + _eos = _err = false; + } + virtual uint32 read(void *dataPtr, uint32 dataSize); - virtual int32 pos() const { return _pos; } - virtual int32 size() const { return _declared_len; } + + virtual int32 pos() const { + return _pos; + } + + virtual int32 size() const { + return _declared_len; + } + virtual bool seek(int32 offset, int whence = SEEK_SET); + private: - void close(JNIEnv* env); + void close(JNIEnv *env); + int _fd; jmethodID MID_close; jobject _assetfd; @@ -224,8 +283,10 @@ private: bool _err; }; -AssetFdReadStream::AssetFdReadStream(JNIEnv* env, jobject assetfd) : - _eos(false), _err(false), _pos(0) +AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) : + _eos(false), + _err(false), + _pos(0) { _assetfd = env->NewGlobalRef(assetfd); @@ -248,17 +309,21 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv* env, jobject assetfd) : assert(MID_getFileDescriptor); jobject javafd = env->CallObjectMethod(_assetfd, MID_getFileDescriptor); assert(javafd); + jclass fd_cls = env->GetObjectClass(javafd); jfieldID FID_descriptor = env->GetFieldID(fd_cls, "descriptor", "I"); assert(FID_descriptor); + _fd = env->GetIntField(javafd, FID_descriptor); } AssetFdReadStream::~AssetFdReadStream() { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); env->CallVoidMethod(_assetfd, MID_close); + if (env->ExceptionCheck()) env->ExceptionClear(); + env->DeleteGlobalRef(_assetfd); } @@ -268,13 +333,16 @@ uint32 AssetFdReadStream::read(void *dataPtr, uint32 dataSize) { if (dataSize > cap) dataSize = cap; } + int ret = ::read(_fd, dataPtr, dataSize); + if (ret == 0) _eos = true; else if (ret == -1) _err = true; else _pos += ret; + return ret; } @@ -282,42 +350,49 @@ bool AssetFdReadStream::seek(int32 offset, int whence) { if (whence == SEEK_SET) { if (_declared_len != UNKNOWN_LENGTH && offset > _declared_len) offset = _declared_len; + offset += _start_off; } else if (whence == SEEK_END && _declared_len != UNKNOWN_LENGTH) { whence = SEEK_SET; offset = _start_off + _declared_len + offset; } + int ret = lseek(_fd, offset, whence); + if (ret == -1) return false; + _pos = ret - _start_off; _eos = false; + return true; } AndroidAssetArchive::AndroidAssetArchive(jobject am) { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); _am = env->NewGlobalRef(am); jclass cls = env->GetObjectClass(_am); MID_open = env->GetMethodID(cls, "open", "(Ljava/lang/String;I)Ljava/io/InputStream;"); assert(MID_open); + MID_openFd = env->GetMethodID(cls, "openFd", - "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); + "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); assert(MID_openFd); + MID_list = env->GetMethodID(cls, "list", "(Ljava/lang/String;)[Ljava/lang/String;"); assert(MID_list); } AndroidAssetArchive::~AndroidAssetArchive() { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); env->DeleteGlobalRef(_am); } bool AndroidAssetArchive::hasFile(const Common::String &name) { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); jstring path = env->NewStringUTF(name.c_str()); jobject result = env->CallObjectMethod(_am, MID_open, path, ACCESS_UNKNOWN); if (env->ExceptionCheck()) { @@ -326,15 +401,18 @@ bool AndroidAssetArchive::hasFile(const Common::String &name) { //env->ExceptionDescribe(); env->ExceptionClear(); env->DeleteLocalRef(path); + return false; } + env->DeleteLocalRef(result); env->DeleteLocalRef(path); + return true; } int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); Common::List<Common::String> dirlist; dirlist.push_back(""); @@ -345,29 +423,36 @@ int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { jstring jpath = env->NewStringUTF(dir.c_str()); jobjectArray jpathlist = static_cast<jobjectArray>(env->CallObjectMethod(_am, MID_list, jpath)); + if (env->ExceptionCheck()) { warning("Error while calling AssetManager->list(%s). Ignoring.", dir.c_str()); env->ExceptionDescribe(); env->ExceptionClear(); - continue; // May as well keep going ... + + // May as well keep going ... + continue; } + env->DeleteLocalRef(jpath); for (jsize i = 0; i < env->GetArrayLength(jpathlist); ++i) { jstring elem = (jstring)env->GetObjectArrayElement(jpathlist, i); - const char* p = env->GetStringUTFChars(elem, NULL); + const char *p = env->GetStringUTFChars(elem, 0); Common::String thispath = dir; + if (!thispath.empty()) thispath += "/"; + thispath += p; // Assume files have a . in them, and directories don't if (strchr(p, '.')) { member_list.push_back(getMember(thispath)); ++count; - } else + } else { dirlist.push_back(thispath); + } env->ReleaseStringUTFChars(elem, p); env->DeleteLocalRef(elem); @@ -384,14 +469,15 @@ Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &na } Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const { - JNIEnv* env = JNU_GetEnv(); + JNIEnv *env = JNU_GetEnv(); jstring jpath = env->NewStringUTF(path.c_str()); // Try openFd() first ... jobject afd = env->CallObjectMethod(_am, MID_openFd, jpath); + if (env->ExceptionCheck()) env->ExceptionClear(); - else if (afd != NULL) { + else if (afd != 0) { // success :) env->DeleteLocalRef(jpath); return new AssetFdReadStream(env, afd); @@ -399,13 +485,15 @@ Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const // ... and fallback to normal open() if that doesn't work jobject is = env->CallObjectMethod(_am, MID_open, jpath, ACCESS_RANDOM); + if (env->ExceptionCheck()) { // Assume FileNotFoundException //warning("Error opening %s", path.c_str()); //env->ExceptionDescribe(); env->ExceptionClear(); env->DeleteLocalRef(jpath); - return NULL; + + return 0; } return new JavaInputStream(env, is); diff --git a/backends/platform/android/video.cpp b/backends/platform/android/video.cpp index b9c3f9a1f8..f5ec0b45d9 100644 --- a/backends/platform/android/video.cpp +++ b/backends/platform/android/video.cpp @@ -54,7 +54,7 @@ #if 0 #define CHECK_GL_ERROR() checkGlError(__FILE__, __LINE__) -static const char* getGlErrStr(GLenum error) { +static const char *getGlErrStr(GLenum error) { switch (error) { case GL_NO_ERROR: return "GL_NO_ERROR"; case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; @@ -68,7 +68,7 @@ static const char* getGlErrStr(GLenum error) { snprintf(buf, sizeof(buf), "(Unknown GL error code 0x%x)", error); return buf; } -static void checkGlError(const char* file, int line) { +static void checkGlError(const char *file, int line) { GLenum error = glGetError(); if (error != GL_NO_ERROR) warning("%s:%d: GL error: %s", file, line, getGlErrStr(error)); @@ -84,7 +84,7 @@ static bool draw_tex_supported = false; #endif static inline GLfixed xdiv(int numerator, int denominator) { - assert(numerator < (1<<16)); + assert(numerator < (1 << 16)); return (numerator << 16) / denominator; } @@ -93,21 +93,27 @@ static T nextHigher2(T k) { if (k == 0) return 1; --k; - for (uint i = 1; i < sizeof(T)*CHAR_BIT; i <<= 1) + + for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) k = k | k >> i; + return k + 1; } void GLESTexture::initGLExtensions() { - const char* ext_string = - reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); + const char *ext_string = + reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, - "Extensions: %s", ext_string); + "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; @@ -121,11 +127,12 @@ GLESTexture::GLESTexture() : _all_dirty(true) { glGenTextures(1, &_texture_name); + // This all gets reset later in allocBuffer: _surface.w = 0; _surface.h = 0; _surface.pitch = _texture_width; - _surface.pixels = NULL; + _surface.pixels = 0; _surface.bytesPerPixel = 0; } @@ -153,8 +160,8 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _surface.h = h; _surface.bytesPerPixel = bpp; + // Already allocated a sufficiently large buffer? if (w <= _texture_width && h <= _texture_height) - // Already allocated a sufficiently large buffer return; if (npot_supported) { @@ -164,6 +171,7 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { _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 @@ -178,14 +186,15 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECK_GL_ERROR(); glTexImage2D(GL_TEXTURE_2D, 0, glFormat(), - _texture_width, _texture_height, - 0, glFormat(), glType(), NULL); + _texture_width, _texture_height, + 0, glFormat(), glType(), 0); CHECK_GL_ERROR(); } void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, - const void* buf, int pitch) { + const void *buf, int pitch) { ENTER("updateBuffer(%u, %u, %u, %u, %p, %d)", x, y, w, h, buf, pitch); + glBindTexture(GL_TEXTURE_2D, _texture_name); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -202,20 +211,22 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, #if TEXSUBIMAGE_IS_EXPENSIVE byte tmpbuf[w * h * bytesPerPixel()]; - const byte* src = static_cast<const byte*>(buf); - byte* dst = tmpbuf; + const byte *src = static_cast<const byte *>(buf); + byte *dst = tmpbuf; GLuint count = h; + do { memcpy(dst, src, w * bytesPerPixel()); dst += w * bytesPerPixel(); src += pitch; } while (--count); + 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<const byte*>(buf); + const byte *src = static_cast<const byte *>(buf); do { glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, 1, glFormat(), glType(), src); @@ -241,9 +252,13 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { // Still a work-in-progress - disabled for now. if (false && draw_tex_supported && paletteSize() == 0) { //glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - const GLint crop[4] = {0, _surface.h, _surface.w, -_surface.h}; + const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); - glColor4ub(0xff, 0xff, 0xff, 0xff); // Android GLES bug? + + // Android GLES bug? + glColor4ub(0xff, 0xff, 0xff, 0xff); + glDrawTexiOES(x, y, 0, w, h); } else #endif @@ -256,18 +271,20 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { 0, tex_height, tex_width, tex_height, }; + glTexCoordPointer(2, GL_FIXED, 0, texcoords); const GLshort vertices[] = { - x, y, - x+w, y, - x, y+h, - x+w, y+h, + x, y, + x + w, y, + x, y + h, + x + w, y + h, }; + glVertexPointer(2, GL_SHORT, 0, vertices); assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); - glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices)/2); + glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2); } _all_dirty = false; @@ -276,7 +293,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { GLESPaletteTexture::GLESPaletteTexture() : GLESTexture(), - _texture(NULL) + _texture(0) { } @@ -291,8 +308,8 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { _surface.h = h; _surface.bytesPerPixel = bpp; + // Already allocated a sufficiently large buffer? if (w <= _texture_width && h <= _texture_height) - // Already allocated a sufficiently large buffer return; if (npot_supported) { @@ -306,12 +323,14 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { // Texture gets uploaded later (from drawTexture()) - byte* new_buffer = new byte[paletteSize() + + byte *new_buffer = new byte[paletteSize() + _texture_width * _texture_height * bytesPerPixel()]; if (_texture) { - memcpy(new_buffer, _texture, paletteSize()); // preserve palette + // preserve palette + memcpy(new_buffer, _texture, paletteSize()); delete[] _texture; } + _texture = new_buffer; _surface.pixels = _texture + paletteSize(); } @@ -323,12 +342,13 @@ void GLESPaletteTexture::fillBuffer(byte x) { } void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, - GLuint w, GLuint h, - const void* buf, int pitch) { + GLuint w, GLuint h, + const void *buf, int pitch) { _all_dirty = true; - const byte* src = static_cast<const byte*>(buf); - byte* dst = static_cast<byte*>(_surface.getBasePtr(x, y)); + const byte * src = static_cast<const byte *>(buf); + byte *dst = static_cast<byte *>(_surface.getBasePtr(x, y)); + do { memcpy(dst, src, w * bytesPerPixel()); dst += _surface.pitch; @@ -339,9 +359,10 @@ void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, void GLESPaletteTexture::uploadTexture() const { const size_t texture_size = paletteSize() + _texture_width * _texture_height * bytesPerPixel(); + glCompressedTexImage2D(GL_TEXTURE_2D, 0, glType(), - _texture_width, _texture_height, - 0, texture_size, _texture); + _texture_width, _texture_height, + 0, texture_size, _texture); CHECK_GL_ERROR(); } diff --git a/backends/platform/android/video.h b/backends/platform/android/video.h index 4b73508907..1e00f9bd57 100644 --- a/backends/platform/android/video.h +++ b/backends/platform/android/video.h @@ -38,30 +38,54 @@ public: GLESTexture(); virtual ~GLESTexture(); + virtual void reinitGL(); virtual void allocBuffer(GLuint width, GLuint height); - const Graphics::Surface* surface_const() const { return &_surface; } - GLuint width() const { return _surface.w; } - GLuint height() const { return _surface.h; } - GLuint texture_name() const { return _texture_name; } - bool dirty() const { return _all_dirty || !_dirty_rect.isEmpty(); } + + const Graphics::Surface *surface_const() const { + return &_surface; + } + + GLuint width() const { + return _surface.w; + } + + GLuint height() const { + return _surface.h; + } + + GLuint texture_name() const { + return _texture_name; + } + + bool dirty() const { + return _all_dirty || !_dirty_rect.isEmpty(); + } + virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, - const void* buf, int pitch); + const void *buf, int pitch); virtual void fillBuffer(byte x); + virtual void drawTexture() { drawTexture(0, 0, _surface.w, _surface.h); } + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); protected: virtual byte bytesPerPixel() const = 0; virtual GLenum glFormat() const = 0; virtual GLenum glType() const = 0; - virtual size_t paletteSize() const { return 0; }; + + virtual size_t paletteSize() const { + return 0; + } + void setDirty() { _all_dirty = true; _dirty_rect = Common::Rect(); } + void setDirtyRect(const Common::Rect& r) { if (!_all_dirty) { if (_dirty_rect.isEmpty()) @@ -70,28 +94,47 @@ protected: _dirty_rect.extend(r); } } + GLuint _texture_name; Graphics::Surface _surface; GLuint _texture_width; GLuint _texture_height; bool _all_dirty; - Common::Rect _dirty_rect; // Covers dirty area + + // 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; } + 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; } + 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 @@ -99,42 +142,73 @@ 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); - Graphics::Surface* surface() { + const void *buf, int pitch); + + Graphics::Surface *surface() { setDirty(); return &_surface; } - void* pixels() { + + void *pixels() { setDirty(); return _surface.pixels; } - const byte* palette_const() const { return _texture; }; - byte* palette() { + + const byte *palette_const() const { + return _texture; + }; + + byte *palette() { setDirty(); return _texture; }; + virtual void drawTexture() { drawTexture(0, 0, _surface.w, _surface.h); } + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); virtual void fillBuffer(byte x); + 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; }; + 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; + } + virtual void uploadTexture() const; - byte* _texture; + + 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; }; + 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 |