From 7823e94c18bf6952fecd3fdfbc76dd3ef963b62b Mon Sep 17 00:00:00 2001 From: Dries Harnie Date: Mon, 1 Jun 2020 13:49:59 +0200 Subject: [PATCH] ANDROID: Shift graphics code to graphics.cpp This brings our port more in line with ScummVM. Much of the code there now is analogous to graphics/opengl/opengl-graphics.h --- backends/platform/android/android.cpp | 77 +- backends/platform/android/android.h | 119 +-- backends/platform/android/events.cpp | 102 +- .../android/{gfx.cpp => graphics.cpp} | 921 ++++++++++-------- backends/platform/android/graphics.h | 168 ++++ backends/platform/android/module.mk | 2 +- backends/platform/android/texture.cpp | 5 - 7 files changed, 722 insertions(+), 672 deletions(-) rename backends/platform/android/{gfx.cpp => graphics.cpp} (73%) create mode 100755 backends/platform/android/graphics.h diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index df5100d0073..939a61ae8d4 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -60,6 +60,7 @@ #include "backends/platform/android/jni-android.h" #include "backends/platform/android/android.h" +#include "backends/platform/android/graphics.h" const char *android_log_tag = "ResidualVM"; @@ -115,22 +116,6 @@ 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), - _game_pbuf(), - _overlay_texture(0), - _opengl(false), - _mouse_texture(0), - _mouse_texture_palette(0), - _mouse_texture_rgb(0), - _mouse_hotspot(), - _mouse_keycolor(0), - _use_mouse_palette(false), - _graphicsMode(0), - _fullscreen(true), - _ar_correction(true), - _show_mouse(false), - _show_overlay(false), _mixer(0), _queuedEventTime(0), _event_queue_lock(0), @@ -148,18 +133,14 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _fsFactory = new POSIXFilesystemFactory(); - Common::String mf = getSystemProperty("ro.product.manufacturer"); - LOGI("Running on: [%s] [%s] [%s] [%s] [%s] SDK:%s ABI:%s", - mf.c_str(), + getSystemProperty("ro.product.manufacturer").c_str(), getSystemProperty("ro.product.model").c_str(), getSystemProperty("ro.product.brand").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()); - - mf.toLowercase(); } OSystem_Android::~OSystem_Android() { @@ -376,15 +357,9 @@ void OSystem_Android::initBackend() { _audio_thread_exit = false; pthread_create(&_audio_thread, 0, audioThreadFunc, this); - initSurface(); - initViewport(); + _graphicsManager = new AndroidGraphicsManager(); - _game_texture = new GLESFakePalette565Texture(); - _overlay_texture = new GLES4444Texture(); - _mouse_texture_palette = new GLESFakePalette5551Texture(); - _mouse_texture = _mouse_texture_palette; - - initOverlay(); + dynamic_cast(_graphicsManager)->initSurface(); // renice this thread to boost the audio thread if (setpriority(PRIO_PROCESS, 0, 19) < 0) @@ -400,39 +375,23 @@ bool OSystem_Android::hasFeature(Feature f) { f == kFeatureOpenUrl || f == kFeatureTouchpadMode || f == kFeatureOnScreenControl || - f == kFeatureFullscreenMode || f == kFeatureClipboardSupport || - f == kFeatureAspectRatioCorrection || - f == kFeatureCursorPalette || f == kFeatureOpenGL || f == kFeatureOverlaySupportsAlpha || f == kFeatureClipboardSupport) { return true; } - return false; + return ModularBackend::hasFeature(f); } 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); break; - case kFeatureCursorPalette: - _use_mouse_palette = enable; - if (!enable) - disableCursorPalette(); - break; case kFeatureTouchpadMode: ConfMan.setBool("touchpad_mouse_mode", enable); _touchpad_mode = enable; @@ -442,29 +401,29 @@ void OSystem_Android::setFeatureState(Feature f, bool enable) { JNI::showKeyboardControl(enable); break; default: + ModularBackend::setFeatureState(f, enable); break; } } bool OSystem_Android::getFeatureState(Feature f) { switch (f) { - case kFeatureFullscreenMode: - return _fullscreen; - case kFeatureAspectRatioCorrection: - return _ar_correction; case kFeatureVirtualKeyboard: return _virtkeybd_on; - case kFeatureCursorPalette: - return _use_mouse_palette; case kFeatureTouchpadMode: return ConfMan.getBool("touchpad_mouse_mode"); case kFeatureOnScreenControl: return ConfMan.getBool("onscreen_control"); default: - return false; + return ModularBackend::getFeatureState(f); } } +// ResidualVM specific method +void OSystem_Android::launcherInitSize(uint w, uint h) { + dynamic_cast(_graphicsManager)->setupScreen(w, h, true, true, false); +} + uint32 OSystem_Android::getMillis(bool skipRecord) { timeval curTime; @@ -489,12 +448,7 @@ void OSystem_Android::quit() { _timer_thread_exit = true; pthread_join(_timer_thread, 0); - delete _game_texture; - delete _overlay_texture; - delete _mouse_texture_palette; - delete _mouse_texture_rgb; - - deinitSurface(); + dynamic_cast(_graphicsManager)->deinitSurface(); } void OSystem_Android::setWindowCaption(const char *caption) { @@ -503,11 +457,6 @@ void OSystem_Android::setWindowCaption(const char *caption) { JNI::setWindowCaption(caption); } -void OSystem_Android::displayMessageOnOSD(const char *msg) { - ENTER("%s", msg); - - JNI::displayMessageOnOSD(msg); -} void OSystem_Android::showVirtualKeyboard(bool enable) { ENTER("%d", enable); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 297eb814f51..0f688bab0ea 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -25,6 +25,7 @@ #if defined(__ANDROID__) +#include "backends/platform/android/portdefs.h" #include "common/fs.h" #include "common/archive.h" #include "audio/mixer_intern.h" @@ -39,6 +40,7 @@ #include "backends/platform/android/events.h" #include "backends/platform/android/texture.h" +#include "backends/platform/android/graphics.h" #include "backends/platform/android/touchcontrols.h" #include @@ -98,7 +100,7 @@ extern void checkGlError(const char *expr, const char *file, int line); #define GLTHREADCHECK do { } while (false) #endif -class OSystem_Android : public ModularBackend, public PaletteManager, Common::EventSource { +class OSystem_Android : public ModularBackend, Common::EventSource { private: // passed from the dark side int _audio_sample_rate; @@ -106,33 +108,6 @@ private: int _screen_changeid; - bool _force_redraw; - - bool _opengl; - - // Game layer - GLESBaseTexture *_game_texture; - Graphics::PixelBuffer _game_pbuf; - OpenGL::FrameBuffer *_frame_buffer; - - // Overlay layer - GLES4444Texture *_overlay_texture; - bool _show_overlay; - - // Mouse layer - GLESBaseTexture *_mouse_texture; - GLESBaseTexture *_mouse_texture_palette; - GLES5551Texture *_mouse_texture_rgb; - Common::Point _mouse_hotspot; - uint32 _mouse_keycolor; - int _mouse_targetscale; - bool _show_mouse; - bool _use_mouse_palette; - - int _graphicsMode; - bool _fullscreen; - bool _ar_correction; - pthread_t _main_thread; bool _timer_thread_exit; @@ -150,19 +125,7 @@ private: Common::String getSystemProperty(const char *name) const; - void initSurface(); - void deinitSurface(); - void initViewport(); - - void initOverlay(); - -#ifdef USE_RGB_COLOR - void initTexture(GLESBaseTexture **texture, uint width, uint height, - const Graphics::PixelFormat *format); -#endif - void setupKeymapper(); - void setCursorPaletteInternal(const byte *colors, uint start, uint num); protected: virtual Common::EventSource *getDefaultEventSource() { return this; } @@ -177,35 +140,8 @@ public: virtual void setFeatureState(OSystem::Feature f, bool enable); virtual bool getFeatureState(OSystem::Feature f); - virtual const GraphicsMode *getSupportedGraphicsModes() const; - virtual int getDefaultGraphicsMode() const; - 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); - - enum FixupType { - kClear = 0, // glClear - kClearSwap, // glClear + swapBuffers - kClearUpdate // glClear + updateScreen - }; - - void clearScreen(FixupType type, byte count = 1); - - void updateScreenRect(); - virtual int getScreenChangeID() const; - - virtual int16 getHeight(); - virtual int16 getWidth(); - - virtual PaletteManager *getPaletteManager() { - return this; + virtual PaletteManager *getPaletteManager() override { + return dynamic_cast(_graphicsManager); } public: @@ -228,46 +164,12 @@ private: int _fingersDown; void clipMouse(Common::Point &p); - void scaleMouse(Common::Point &p, int x, int y, bool deductDrawRect = true, bool touchpadMode = false); - void updateEventScale(); + void scaleMouse(Common::Point &p, int x, int y, bool touchpadMode = false); void disableCursorPalette(); TouchControls _touchControls; - void drawVirtControls(); - -protected: - // PaletteManager API - virtual void setPalette(const byte *colors, uint start, uint num); - virtual void grabPalette(byte *colors, uint start, uint num) const; - public: - virtual void copyRectToScreen(const void *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 shakeXOffset, int shakeYOffset); - virtual void fillScreen(uint32 col); - - virtual void showOverlay(); - virtual void hideOverlay(); - virtual void clearOverlay(); - virtual void grabOverlay(void *buf, int pitch); - virtual void copyRectToOverlay(const void *buf, int pitch, - int x, int y, int w, int h); - virtual int16 getOverlayHeight(); - virtual int16 getOverlayWidth(); - virtual Graphics::PixelFormat getOverlayFormat() const; - - virtual bool showMouse(bool visible); - - virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, - int hotspotY, uint32 keycolor, - bool dontScale, - const Graphics::PixelFormat *format); - virtual void setCursorPalette(const byte *colors, uint start, uint num); virtual void pushEvent(const Common::Event &event); virtual void pushKeyPressEvent(Common::Event &event); @@ -278,7 +180,6 @@ public: virtual void quit(); virtual void setWindowCaption(const char *caption); - virtual void displayMessageOnOSD(const char *msg); virtual void showVirtualKeyboard(bool enable); virtual Audio::Mixer *getMixer(); @@ -295,12 +196,8 @@ public: // ResidualVM specific method virtual void launcherInitSize(uint w, uint h); - bool lockMouse(bool lock); - void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) { - setupScreen(screenW, screenH, fullscreen, accel3d, true); - } - void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame); - Graphics::PixelBuffer getScreenPixelBuffer(); + void updateEventScale(const GLESBaseTexture *tex); + TouchControls* getTouchControls() { return &_touchControls; } }; #endif diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 93fb576740d..1156d422772 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -41,6 +41,7 @@ #include "backends/platform/android/android.h" #include "backends/platform/android/events.h" +#include "backends/platform/android/graphics.h" #include "backends/platform/android/jni-android.h" #include "engines/engine.h" @@ -79,40 +80,13 @@ void OSystem_Android::setupKeymapper() { #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); - - pushEvent(e); -} - 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() - 1)); - p.y = CLIP(p.y, int16(0), int16(tex->height() - 1)); + dynamic_cast(_graphicsManager)->clipMouse(p); } -void OSystem_Android::scaleMouse(Common::Point &p, int x, int y, - bool deductDrawRect, bool touchpadMode) { - const GLESBaseTexture *tex; - - if (_show_overlay) - tex = _overlay_texture; - else - tex = _game_texture; +void OSystem_Android::scaleMouse(Common::Point &p, int x, int y, bool touchpadMode) { + const GLESBaseTexture *tex = + dynamic_cast(_graphicsManager)->getActiveTexture(); const Common::Rect &r = tex->getDrawRect(); @@ -121,23 +95,11 @@ void OSystem_Android::scaleMouse(Common::Point &p, int x, int y, 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; - +void OSystem_Android::updateEventScale(const GLESBaseTexture *tex) { _eventScaleY = 100 * 480 / tex->height(); _eventScaleX = 100 * 640 / tex->width(); } @@ -429,12 +391,10 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, } scaleMouse(e.mouse, arg3 - _touch_pt_scroll.x, - arg4 - _touch_pt_scroll.y, false, true); + arg4 - _touch_pt_scroll.y, true); e.mouse += _touch_pt_down; - clipMouse(e.mouse); } else { scaleMouse(e.mouse, arg3, arg4); - clipMouse(e.mouse); } pushEvent(e); @@ -462,7 +422,6 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, e.mouse = getEventManager()->getMousePos(); } else { scaleMouse(e.mouse, arg1, arg2); - clipMouse(e.mouse); } { @@ -515,7 +474,6 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, e.mouse = getEventManager()->getMousePos(); } else { scaleMouse(e.mouse, arg1, arg2); - clipMouse(e.mouse); } { @@ -542,10 +500,8 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, if (_touchpad_mode) { scaleMouse(e.mouse, arg1 - _touch_pt_dt.x, - arg2 - _touch_pt_dt.y, false, true); + arg2 - _touch_pt_dt.y, true); e.mouse += _touch_pt_down; - - clipMouse(e.mouse); } break; @@ -653,9 +609,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case JE_MOUSE_MOVE: e.type = Common::EVENT_MOUSEMOVE; - scaleMouse(e.mouse, arg1, arg2); - clipMouse(e.mouse); pushEvent(e); @@ -663,9 +617,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case JE_LMB_DOWN: e.type = Common::EVENT_LBUTTONDOWN; - scaleMouse(e.mouse, arg1, arg2); - clipMouse(e.mouse); pushEvent(e); @@ -673,9 +625,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case JE_LMB_UP: e.type = Common::EVENT_LBUTTONUP; - scaleMouse(e.mouse, arg1, arg2); - clipMouse(e.mouse); pushEvent(e); @@ -683,9 +633,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case JE_RMB_DOWN: e.type = Common::EVENT_RBUTTONDOWN; - scaleMouse(e.mouse, arg1, arg2); - clipMouse(e.mouse); pushEvent(e); @@ -693,9 +641,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, case JE_RMB_UP: e.type = Common::EVENT_RBUTTONUP; - scaleMouse(e.mouse, arg1, arg2); - clipMouse(e.mouse); pushEvent(e); @@ -732,29 +678,23 @@ bool OSystem_Android::pollEvent(Common::Event &event) { if (pthread_self() == _main_thread) { if (_screen_changeid != JNI::surface_changeid) { + _screen_changeid = JNI::surface_changeid; if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { // surface changed - JNI::deinitSurface(); - initSurface(); - initViewport(); - updateScreenRect(); - updateEventScale(); - - // double buffered, flip twice - clearScreen(kClearUpdate, 2); + dynamic_cast(_graphicsManager)->deinitSurface(); + dynamic_cast(_graphicsManager)->initSurface(); + _touchControls.init(JNI::egl_surface_width, JNI::egl_surface_height); event.type = Common::EVENT_SCREEN_CHANGED; return true; } else { // surface lost - deinitSurface(); + dynamic_cast(_graphicsManager)->deinitSurface(); } } if (JNI::pause) { - deinitSurface(); - LOGD("main thread going to sleep"); sem_wait(&JNI::pause_sem); LOGD("main thread woke up"); @@ -779,11 +719,17 @@ bool OSystem_Android::pollEvent(Common::Event &event) { unlockMutex(_event_queue_lock); - if (event.type == Common::EVENT_MOUSEMOVE) { - const Common::Point &m = getEventManager()->getMousePos(); - - if (m != event.mouse) - _force_redraw = true; + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + if (_graphicsManager) + return dynamic_cast(_graphicsManager)->notifyMousePosition(event.mouse); + break; + default: + break; } return true; diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/graphics.cpp similarity index 73% rename from backends/platform/android/gfx.cpp rename to backends/platform/android/graphics.cpp index 5af54d0bd69..ead0f1bfe9b 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/graphics.cpp @@ -39,130 +39,52 @@ // for the Android port #define FORBIDDEN_SYMBOL_EXCEPTION_printf -#include "common/endian.h" #include "common/tokenizer.h" #include "graphics/conversion.h" #include "graphics/opengl/shader.h" #include "graphics/opengl/context.h" #include "backends/platform/android/android.h" +#include "backends/platform/android/events.h" +#include "backends/platform/android/graphics.h" #include "backends/platform/android/jni-android.h" -static inline GLfixed xdiv(int numerator, int denominator) { - assert(numerator < (1 << 16)); - return (numerator << 16) / denominator; +AndroidGraphicsManager::AndroidGraphicsManager() : + _screenChangeID(0), + _graphicsMode(0), + _opengl(false), + _fullscreen(true), + _ar_correction(true), + _force_redraw(false), + _game_texture(0), + _game_pbuf(), + _cursorX(0), + _cursorY(0), + _overlay_texture(0), + _show_overlay(false), + _mouse_texture(0), + _mouse_texture_palette(0), + _mouse_texture_rgb(0), + _mouse_hotspot(), + _mouse_keycolor(0), + _show_mouse(false), + _use_mouse_palette(false) +{ + _game_texture = new GLESFakePalette565Texture(); + _overlay_texture = new GLES4444Texture(); + _mouse_texture_palette = new GLESFakePalette5551Texture(); + _mouse_texture = _mouse_texture_palette; + } -// ResidualVM specific method -void OSystem_Android::launcherInitSize(uint w, uint h) { - setupScreen(w, h, true, true, false); +AndroidGraphicsManager::~AndroidGraphicsManager() { + delete _game_texture; + delete _overlay_texture; + delete _mouse_texture_palette; + delete _mouse_texture_rgb; + } -// ResidualVM specific method -bool OSystem_Android::lockMouse(bool lock) { - _show_mouse = lock; - return true; -} - -const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const { - static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { - { "default", "Default", 0 }, - { "filter", "Linear filtering", 1 }, - { 0, 0, 0 }, - }; - - return s_supportedGraphicsModes; -} - -int OSystem_Android::getDefaultGraphicsMode() const { - 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); - - if (_mouse_texture) - _mouse_texture->setLinearFilter(mode == 1); - - _graphicsMode = mode; - - return true; -} - -int OSystem_Android::getGraphicsMode() const { - return _graphicsMode; -} - -#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::pixelFormat()); - res.push_back(GLES5551Texture::pixelFormat()); - res.push_back(GLES4444Texture::pixelFormat()); - res.push_back(Graphics::PixelFormat::createFormatCLUT8()); - - return res; -} - -void OSystem_Android::initTexture(GLESBaseTexture **texture, - uint width, uint height, - const Graphics::PixelFormat *format) { - assert(texture); - Graphics::PixelFormat format_clut8 = - Graphics::PixelFormat::createFormatCLUT8(); - Graphics::PixelFormat format_current; - Graphics::PixelFormat format_new; - - if (*texture) - format_current = (*texture)->getPixelFormat(); - else - format_current = Graphics::PixelFormat(); - - if (format) - format_new = *format; - else - format_new = format_clut8; - - if (format_current != format_new) { - if (*texture) - LOGD("switching pixel format from: %s", - (*texture)->getPixelFormat().toString().c_str()); - - delete *texture; - - if (format_new == GLES565Texture::pixelFormat()) - *texture = new GLES565Texture(); - else if (format_new == GLES5551Texture::pixelFormat()) - *texture = new GLES5551Texture(); - else if (format_new == GLES4444Texture::pixelFormat()) - *texture = new GLES4444Texture(); - else { - // TODO what now? - if (format_new != format_clut8) - LOGE("unsupported pixel format: %s", - format_new.toString().c_str()); - - *texture = new GLESFakePalette565Texture; - } - - LOGD("new pixel format: %s", - (*texture)->getPixelFormat().toString().c_str()); - } - - (*texture)->allocBuffer(width, height); -} -#endif - static void logExtensions() { const char *ext_string = reinterpret_cast(glGetString(GL_EXTENSIONS)); @@ -185,15 +107,16 @@ static void logExtensions() { LOGI("\t%s", exts.c_str()); } -void OSystem_Android::initSurface() { + +void AndroidGraphicsManager::initSurface() { LOGD("initializing surface"); assert(!JNI::haveSurface()); - _screen_changeid = JNI::surface_changeid; - JNI::initSurface(); + _screenChangeID = JNI::surface_changeid; + // Initialize OpenGLES context. OpenGLContext.initialize(OpenGL::kContextGLES2); logExtensions(); @@ -209,15 +132,21 @@ void OSystem_Android::initSurface() { if (_mouse_texture) _mouse_texture->reinit(); + + initViewport(); + updateScreenRect(); + // double buffered, flip twice + clearScreen(kClearUpdate, 2); + updateEventScale(); } -void OSystem_Android::deinitSurface() { +void AndroidGraphicsManager::deinitSurface() { if (!JNI::haveSurface()) return; LOGD("deinitializing surface"); - _screen_changeid = JNI::surface_changeid; + _screenChangeID = JNI::surface_changeid; // release texture resources if (_game_texture) @@ -234,236 +163,7 @@ void OSystem_Android::deinitSurface() { JNI::deinitSurface(); } -void OSystem_Android::initViewport() { - LOGD("initializing viewport"); - - assert(JNI::haveSurface()); - - GLCALL(glDisable(GL_CULL_FACE)); - GLCALL(glDisable(GL_DEPTH_TEST)); - - GLCALL(glEnable(GL_BLEND)); - GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - - GLCALL(glViewport(0, 0, JNI::egl_surface_width, JNI::egl_surface_height)); - LOGD("viewport size: %dx%d", JNI::egl_surface_width, JNI::egl_surface_height); -} - -void OSystem_Android::initOverlay() { - // minimum of 320x200 - // (surface can get smaller when opening the virtual keyboard on *QVGA*) - int overlay_width = MAX(JNI::egl_surface_width, 320); - int overlay_height = MAX(JNI::egl_surface_height, 200); - - // the 'normal' theme layout uses a max height of 400 pixels. if the - // surface is too big we use only a quarter of the size so that the widgets - // don't get too small. if the surface height has less than 800 pixels, this - // enforces the 'lowres' layout, which will be scaled back up by factor 2x, - // but this looks way better than the 'normal' layout scaled by some - // calculated factors -// while (overlay_height > 480) { -// overlay_width /= 2; -// overlay_height /= 2; -// } - - LOGI("overlay size is %ux%u", overlay_width, overlay_height); - - _overlay_texture->allocBuffer(overlay_width, overlay_height); - _overlay_texture->setDrawRect(0, 0, - JNI::egl_surface_width, JNI::egl_surface_height); -} - -void 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); -#else - _game_texture->allocBuffer(width, height); -#endif -#ifdef USE_GLES2 - _frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight()); - _frame_buffer->attach(); -#endif - - updateScreenRect(); - updateEventScale(); - - // Don't know mouse size yet - it gets reallocated in - // setMouseCursor. We need the palette allocated before - // setMouseCursor however, so just take a guess at the desired - // size (it's small). - _mouse_texture_palette->allocBuffer(20, 20); - - clearScreen(kClear); -} - -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) { - // clear screen - GLCALL(glClearColor(0, 0, 0, 1 << 16)); - if (_opengl) { - GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); - } else { - GLCALL(glClear(GL_COLOR_BUFFER_BIT)); - } - - switch (type) { - case kClear: - break; - - case kClearSwap: - JNI::swapBuffers(); - break; - - case kClearUpdate: - _force_redraw = true; - updateScreen(); - break; - } - } - - if (!_show_overlay) - GLCALL(glEnable(GL_SCISSOR_TEST)); - - _show_mouse = sm; - _force_redraw = true; -} - -void OSystem_Android::updateScreenRect() { - Common::Rect rect(0, 0, JNI::egl_surface_width, JNI::egl_surface_height); - - _overlay_texture->setDrawRect(rect); - - uint16 w = _game_texture->width(); - uint16 h = _game_texture->height(); - - if (w && h && _ar_correction) { - - float dpi[2]; - JNI::getDPI(dpi); - - float screen_ar; - if (dpi[0] != 0.0 && dpi[1] != 0.0) { - // horizontal orientation - screen_ar = (dpi[1] * JNI::egl_surface_width) / - (dpi[0] * JNI::egl_surface_height); - } else { - screen_ar = float(JNI::egl_surface_width) / float(JNI::egl_surface_height); - } - - float game_ar = float(w) / float(h); - - if (screen_ar > game_ar) { - rect.setWidth(round(JNI::egl_surface_height * game_ar)); - rect.moveTo((JNI::egl_surface_width - rect.width()) / 2, 0); - } else { - rect.setHeight(round(JNI::egl_surface_width / game_ar)); - rect.moveTo((JNI::egl_surface_height - rect.height()) / 2, 0); - } - } - - _game_texture->setDrawRect(rect); -} - -int OSystem_Android::getScreenChangeID() const { - return _screen_changeid; -} - -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); - -#ifdef USE_RGB_COLOR - assert(_game_texture->hasPalette()); -#endif - - GLTHREADCHECK; - - if (!_use_mouse_palette) - setCursorPaletteInternal(colors, start, num); - - const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat(); - byte *p = _game_texture->palette() + start * 2; - - for (uint i = 0; i < num; ++i, colors += 3, p += 2) - WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2])); -} - -void OSystem_Android::grabPalette(byte *colors, uint start, uint num) const { - ENTER("%p, %u, %u", colors, start, num); - -#ifdef USE_RGB_COLOR - assert(_game_texture->hasPalette()); -#endif - - GLTHREADCHECK; - - const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat(); - const byte *p = _game_texture->palette_const() + start * 2; - - for (uint i = 0; i < num; ++i, colors += 3, p += 2) - pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]); -} - -void OSystem_Android::copyRectToScreen(const void *buf, int pitch, - int x, int y, int w, int h) { - ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); - - GLTHREADCHECK; - - _game_texture->updateBuffer(x, y, w, h, buf, pitch); -} - - -// ResidualVM specific method -void OSystem_Android::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame) { - _opengl = accel3d; - initViewport(); - - _touchControls.init(JNI::egl_surface_width, JNI::egl_surface_height); - - if (_opengl) { - // resize game texture - initSize(screenW, screenH, 0); - if (isGame) - _game_texture->setGameTexture(); - // format is not used by the gfx_opengl driver, use fake format - _game_pbuf.set(Graphics::PixelFormat(), 0); - - } else { - Graphics::PixelFormat format = GLES565Texture::pixelFormat(); - initSize(screenW, screenH, &format); - // as there is no support for the texture surface's lock/unlock mechanism in gfx_tinygl/... - // do not use _game_texture->surface()->pixels directly - _game_pbuf.create(_game_texture->getPixelFormat(), - _game_texture->width() * _game_texture->height(), DisposeAfterUse::YES); - } - -} - -Graphics::PixelBuffer OSystem_Android::getScreenPixelBuffer() { - return _game_pbuf; -} - -void OSystem_Android::updateScreen() { +void AndroidGraphicsManager::updateScreen() { //ENTER(); GLTHREADCHECK; @@ -493,19 +193,15 @@ void OSystem_Android::updateScreen() { // clear pointer leftovers in dead areas clearScreen(kClear); - // TODO this doesnt work on those sucky drivers, do it differently - // if (_show_overlay) - // GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f)); - _game_texture->drawTextureRect(); - drawVirtControls(); + if (!_show_overlay) { + glEnable(GL_BLEND); + static_cast(g_system)->getTouchControls()->draw(); + } int cs = _mouse_targetscale; if (_show_overlay) { - // TODO see above - // GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); - // ugly, but the modern theme sets a wacko factor, only god knows why cs = 1; @@ -513,29 +209,10 @@ void OSystem_Android::updateScreen() { } if (_show_mouse && !_mouse_texture->isEmpty()) { - const Common::Point &mouse = getEventManager()->getMousePos(); + const Common::Point &mouse = g_system->getEventManager()->getMousePos(); if (_show_overlay) { _mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height()); } -// TODO: Port the non-overlay code as well? -#if 0 - if (_show_overlay) { - } else { - 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(glTranslatex((-_mouse_hotspot.x * cs) << 16, - (-_mouse_hotspot.y * cs) << 16, - 0)); - -#endif } if (!JNI::swapBuffers()) @@ -545,46 +222,99 @@ void OSystem_Android::updateScreen() { _frame_buffer->attach(); } -void OSystem_Android::drawVirtControls() { - if (_show_overlay) - return; +void AndroidGraphicsManager::displayMessageOnOSD(const char *msg) { + ENTER("%s", msg); - glEnable(GL_BLEND); - _touchControls.draw(); + JNI::displayMessageOnOSD(msg); } -Graphics::Surface *OSystem_Android::lockScreen() { - ENTER(); - - GLTHREADCHECK; - - Graphics::Surface *surface = _game_texture->surface(); - assert(surface->getPixels()); - - return surface; +bool AndroidGraphicsManager::notifyMousePosition(Common::Point &mouse) { + clipMouse(mouse); + setMousePosition(mouse.x, mouse.y); + return true; } -void OSystem_Android::unlockScreen() { - ENTER(); +const OSystem::GraphicsMode *AndroidGraphicsManager::getSupportedGraphicsModes() const { + static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + { "default", "Default", 0 }, + { "filter", "Linear filtering", 1 }, + { 0, 0, 0 }, + }; - GLTHREADCHECK; - - assert(_game_texture->dirty()); + return s_supportedGraphicsModes; } -void OSystem_Android::setShakePos(int shakeXOffset, int shakeYOffset) { - /* not used in any engine */ +int AndroidGraphicsManager::getDefaultGraphicsMode() const { + return 0; } -void OSystem_Android::fillScreen(uint32 col) { - ENTER("%u", col); +bool AndroidGraphicsManager::setGraphicsMode(int mode) { + ENTER("%d", mode); - GLTHREADCHECK; + if (_game_texture) + _game_texture->setLinearFilter(mode == 1); - _game_texture->fillBuffer(col); + if (_overlay_texture) + _overlay_texture->setLinearFilter(mode == 1); + + if (_mouse_texture) + _mouse_texture->setLinearFilter(mode == 1); + + _graphicsMode = mode; + + return true; } -void OSystem_Android::showOverlay() { +void AndroidGraphicsManager::resetGraphicsScale() { +} + +int AndroidGraphicsManager::getGraphicsMode() const { + return _graphicsMode; +} + +bool AndroidGraphicsManager::hasFeature(OSystem::Feature f) const { + if (f == OSystem::kFeatureCursorPalette || + f == OSystem::kFeatureFullscreenMode || + f == OSystem::kFeatureAspectRatioCorrection) { + return true; + } + return false; +} + +void AndroidGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { + switch (f) { + case OSystem::kFeatureCursorPalette: + _use_mouse_palette = enable; + if (!enable) + disableCursorPalette(); + break; + case OSystem::kFeatureFullscreenMode: + _fullscreen = enable; + updateScreenRect(); + break; + case OSystem::kFeatureAspectRatioCorrection: + _ar_correction = enable; + updateScreenRect(); + break; + default: + break; + } +} + +bool AndroidGraphicsManager::getFeatureState(OSystem::Feature f) const { + switch (f) { + case OSystem::kFeatureCursorPalette: + return _use_mouse_palette; + case OSystem::kFeatureFullscreenMode: + return _fullscreen; + case OSystem::kFeatureAspectRatioCorrection: + return _ar_correction; + default: + return false; + } +} + +void AndroidGraphicsManager::showOverlay() { ENTER(); _show_overlay = true; @@ -597,7 +327,7 @@ void OSystem_Android::showOverlay() { GLCALL(glDisable(GL_SCISSOR_TEST)); } -void OSystem_Android::hideOverlay() { +void AndroidGraphicsManager::hideOverlay() { ENTER(); _show_overlay = false; @@ -612,7 +342,7 @@ void OSystem_Android::hideOverlay() { GLCALL(glEnable(GL_SCISSOR_TEST)); } -void OSystem_Android::clearOverlay() { +void AndroidGraphicsManager::clearOverlay() { ENTER(); GLTHREADCHECK; @@ -620,7 +350,7 @@ void OSystem_Android::clearOverlay() { _overlay_texture->fillBuffer(0); } -void OSystem_Android::grabOverlay(void *buf, int pitch) { +void AndroidGraphicsManager::grabOverlay(void *buf, int pitch) const { ENTER("%p, %d", buf, pitch); GLTHREADCHECK; @@ -639,7 +369,7 @@ void OSystem_Android::grabOverlay(void *buf, int pitch) { } while (--h); } -void OSystem_Android::copyRectToOverlay(const void *buf, int pitch, +void AndroidGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); @@ -648,19 +378,130 @@ void OSystem_Android::copyRectToOverlay(const void *buf, int pitch, _overlay_texture->updateBuffer(x, y, w, h, buf, pitch); } -int16 OSystem_Android::getOverlayHeight() { +int16 AndroidGraphicsManager::getOverlayHeight() const { return _overlay_texture->height(); } -int16 OSystem_Android::getOverlayWidth() { +int16 AndroidGraphicsManager::getOverlayWidth() const { return _overlay_texture->width(); } -Graphics::PixelFormat OSystem_Android::getOverlayFormat() const { +Graphics::PixelFormat AndroidGraphicsManager::getOverlayFormat() const { return _overlay_texture->getPixelFormat(); } -bool OSystem_Android::showMouse(bool visible) { +int16 AndroidGraphicsManager::getHeight() const { + return _game_texture->height(); +} + +int16 AndroidGraphicsManager::getWidth() const { + return _game_texture->width(); +} + +void AndroidGraphicsManager::setPalette(const byte *colors, uint start, uint num) { + ENTER("%p, %u, %u", colors, start, num); + +#ifdef USE_RGB_COLOR + assert(_game_texture->hasPalette()); +#endif + + GLTHREADCHECK; + + if (!_use_mouse_palette) + setCursorPaletteInternal(colors, start, num); + + const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat(); + byte *p = _game_texture->palette() + start * 2; + + for (uint i = 0; i < num; ++i, colors += 3, p += 2) + WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2])); +} + +void AndroidGraphicsManager::grabPalette(byte *colors, uint start, uint num) const { + ENTER("%p, %u, %u", colors, start, num); + +#ifdef USE_RGB_COLOR + assert(_game_texture->hasPalette()); +#endif + + GLTHREADCHECK; + + const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat(); + const byte *p = _game_texture->palette_const() + start * 2; + + for (uint i = 0; i < num; ++i, colors += 3, p += 2) + pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]); +} + +Graphics::Surface *AndroidGraphicsManager::lockScreen() { + ENTER(); + + GLTHREADCHECK; + + Graphics::Surface *surface = _game_texture->surface(); + assert(surface->getPixels()); + + return surface; +} + +void AndroidGraphicsManager::unlockScreen() { + ENTER(); + + GLTHREADCHECK; + + assert(_game_texture->dirty()); +} + +void AndroidGraphicsManager::fillScreen(uint32 col) { + ENTER("%u", col); + + GLTHREADCHECK; + + _game_texture->fillBuffer(col); +} + +void AndroidGraphicsManager::copyRectToScreen(const void *buf, int pitch, + int x, int y, int w, int h) { + ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); + + GLTHREADCHECK; + + _game_texture->updateBuffer(x, y, w, h, buf, pitch); +} + +void AndroidGraphicsManager::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); +#else + _game_texture->allocBuffer(width, height); +#endif +#ifdef USE_GLES2 + _frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight()); + _frame_buffer->attach(); +#endif + + updateScreenRect(); + updateEventScale(); + + // Don't know mouse size yet - it gets reallocated in + // setMouseCursor. We need the palette allocated before + // setMouseCursor however, so just take a guess at the desired + // size (it's small). + _mouse_texture_palette->allocBuffer(20, 20); + + clearScreen(kClear); +} + +int AndroidGraphicsManager::getScreenChangeID() const { + return _screenChangeID; +} + +bool AndroidGraphicsManager::showMouse(bool visible) { ENTER("%d", visible); _show_mouse = visible; @@ -668,7 +509,23 @@ bool OSystem_Android::showMouse(bool visible) { return true; } -void OSystem_Android::setMouseCursor(const void *buf, uint w, uint h, +void AndroidGraphicsManager::warpMouse(int x, int y) { + ENTER("%d, %d", x, y); + + Common::Event e; + + e.type = Common::EVENT_MOUSEMOVE; + e.mouse.x = x; + e.mouse.y = y; + + clipMouse(e.mouse); + + setMousePosition(e.mouse.x, e.mouse.y); + + static_cast(g_system)->pushEvent(e); +} + +void AndroidGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { @@ -753,7 +610,7 @@ void OSystem_Android::setMouseCursor(const void *buf, uint w, uint h, _mouse_targetscale = 1; } -void OSystem_Android::setCursorPaletteInternal(const byte *colors, +void AndroidGraphicsManager::setCursorPaletteInternal(const byte *colors, uint start, uint num) { const Graphics::PixelFormat &pf = _mouse_texture_palette->getPalettePixelFormat(); @@ -766,7 +623,7 @@ void OSystem_Android::setCursorPaletteInternal(const byte *colors, WRITE_UINT16(p, READ_UINT16(p) & ~1); } -void OSystem_Android::setCursorPalette(const byte *colors, +void AndroidGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) { ENTER("%p, %u, %u", colors, start, num); @@ -785,7 +642,7 @@ void OSystem_Android::setCursorPalette(const byte *colors, _use_mouse_palette = true; } -void OSystem_Android::disableCursorPalette() { +void AndroidGraphicsManager::disableCursorPalette() { // when disabling the cursor palette, and we're running a clut8 game, // it expects the game palette to be used for the cursor if (_game_texture->hasPalette()) { @@ -809,4 +666,242 @@ void OSystem_Android::disableCursorPalette() { } } +bool AndroidGraphicsManager::lockMouse(bool lock) { + _show_mouse = lock; + return true; +} + +void AndroidGraphicsManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) { + setupScreen(screenW, screenH, fullscreen, accel3d, true); +} + +void AndroidGraphicsManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame) { + _opengl = accel3d; + initViewport(); + + if (_opengl) { + // resize game texture + initSize(screenW, screenH, 0); + if (isGame) + _game_texture->setGameTexture(); + // format is not used by the gfx_opengl driver, use fake format + _game_pbuf.set(Graphics::PixelFormat(), 0); + + } else { + Graphics::PixelFormat format = GLES565Texture::pixelFormat(); + initSize(screenW, screenH, &format); + // as there is no support for the texture surface's lock/unlock mechanism in gfx_tinygl/... + // do not use _game_texture->surface()->pixels directly + _game_pbuf.create(_game_texture->getPixelFormat(), + _game_texture->width() * _game_texture->height(), DisposeAfterUse::YES); + } +} + +Graphics::PixelBuffer AndroidGraphicsManager::getScreenPixelBuffer() { + return _game_pbuf; +} + + +void AndroidGraphicsManager::suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right) { + // TODO +} + +void AndroidGraphicsManager::clipMouse(Common::Point &p) const { + const GLESBaseTexture *tex = getActiveTexture(); + + p.x = CLIP(p.x, tex->getDrawRect().left, tex->getDrawRect().right); + p.y = CLIP(p.y, tex->getDrawRect().top, tex->getDrawRect().bottom); +} + +#ifdef USE_RGB_COLOR +Graphics::PixelFormat AndroidGraphicsManager::getScreenFormat() const { + return _game_texture->getPixelFormat(); +} + +Common::List AndroidGraphicsManager::getSupportedFormats() const { + Common::List res; + res.push_back(GLES565Texture::pixelFormat()); + res.push_back(GLES5551Texture::pixelFormat()); + res.push_back(GLES4444Texture::pixelFormat()); + res.push_back(Graphics::PixelFormat::createFormatCLUT8()); + + return res; +} +#endif + +void AndroidGraphicsManager::updateScreenRect() { + Common::Rect rect(0, 0, JNI::egl_surface_width, JNI::egl_surface_height); + + _overlay_texture->setDrawRect(rect); + + uint16 w = _game_texture->width(); + uint16 h = _game_texture->height(); + + if (w && h && _ar_correction) { + + float dpi[2]; + JNI::getDPI(dpi); + + float screen_ar; + if (dpi[0] != 0.0 && dpi[1] != 0.0) { + // horizontal orientation + screen_ar = (dpi[1] * JNI::egl_surface_width) / + (dpi[0] * JNI::egl_surface_height); + } else { + screen_ar = float(JNI::egl_surface_width) / float(JNI::egl_surface_height); + } + + float game_ar = float(w) / float(h); + + if (screen_ar > game_ar) { + rect.setWidth(round(JNI::egl_surface_height * game_ar)); + rect.moveTo((JNI::egl_surface_width - rect.width()) / 2, 0); + } else { + rect.setHeight(round(JNI::egl_surface_width / game_ar)); + rect.moveTo((JNI::egl_surface_height - rect.height()) / 2, 0); + } + } + + _game_texture->setDrawRect(rect); +} + +const GLESBaseTexture *AndroidGraphicsManager::getActiveTexture() const { + if (_show_overlay) + return _overlay_texture; + else + return _game_texture; +} + +void AndroidGraphicsManager::initOverlay() { + // minimum of 320x200 + // (surface can get smaller when opening the virtual keyboard on *QVGA*) + int overlay_width = MAX(JNI::egl_surface_width, 320); + int overlay_height = MAX(JNI::egl_surface_height, 200); + + // the 'normal' theme layout uses a max height of 400 pixels. if the + // surface is too big we use only a quarter of the size so that the widgets + // don't get too small. if the surface height has less than 800 pixels, this + // enforces the 'lowres' layout, which will be scaled back up by factor 2x, + // but this looks way better than the 'normal' layout scaled by some + // calculated factors +// while (overlay_height > 480) { +// overlay_width /= 2; +// overlay_height /= 2; +// } + + LOGI("overlay size is %ux%u", overlay_width, overlay_height); + + _overlay_texture->allocBuffer(overlay_width, overlay_height); + _overlay_texture->setDrawRect(0, 0, + JNI::egl_surface_width, JNI::egl_surface_height); +} + +void AndroidGraphicsManager::initViewport() { + LOGD("initializing viewport"); + + assert(JNI::haveSurface()); + + GLCALL(glDisable(GL_CULL_FACE)); + GLCALL(glDisable(GL_DEPTH_TEST)); + + GLCALL(glEnable(GL_BLEND)); + GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + GLCALL(glViewport(0, 0, JNI::egl_surface_width, JNI::egl_surface_height)); + LOGD("viewport size: %dx%d", JNI::egl_surface_width, JNI::egl_surface_height); +} + +void AndroidGraphicsManager::updateEventScale() { + static_cast(g_system)->updateEventScale(getActiveTexture()); +} + +void AndroidGraphicsManager::clearScreen(FixupType type, byte count) { + assert(count > 0); + + bool sm = _show_mouse; + _show_mouse = false; + + GLCALL(glDisable(GL_SCISSOR_TEST)); + + for (byte i = 0; i < count; ++i) { + // clear screen + GLCALL(glClearColor(0, 0, 0, 1 << 16)); + if (_opengl) { + GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); + } else { + GLCALL(glClear(GL_COLOR_BUFFER_BIT)); + } + + switch (type) { + case kClear: + break; + + case kClearSwap: + JNI::swapBuffers(); + break; + + case kClearUpdate: + _force_redraw = true; + updateScreen(); + break; + } + } + + if (!_show_overlay) + GLCALL(glEnable(GL_SCISSOR_TEST)); + + _show_mouse = sm; + _force_redraw = true; +} + +#ifdef USE_RGB_COLOR +void AndroidGraphicsManager::initTexture(GLESBaseTexture **texture, + uint width, uint height, + const Graphics::PixelFormat *format) { + assert(texture); + Graphics::PixelFormat format_clut8 = + Graphics::PixelFormat::createFormatCLUT8(); + Graphics::PixelFormat format_current; + Graphics::PixelFormat format_new; + + if (*texture) + format_current = (*texture)->getPixelFormat(); + else + format_current = Graphics::PixelFormat(); + + if (format) + format_new = *format; + else + format_new = format_clut8; + + if (format_current != format_new) { + if (*texture) + LOGD("switching pixel format from: %s", + (*texture)->getPixelFormat().toString().c_str()); + + delete *texture; + + if (format_new == GLES565Texture::pixelFormat()) + *texture = new GLES565Texture(); + else if (format_new == GLES5551Texture::pixelFormat()) + *texture = new GLES5551Texture(); + else if (format_new == GLES4444Texture::pixelFormat()) + *texture = new GLES4444Texture(); + else { + // TODO what now? + if (format_new != format_clut8) + LOGE("unsupported pixel format: %s", + format_new.toString().c_str()); + + *texture = new GLESFakePalette565Texture; + } + + LOGD("new pixel format: %s", + (*texture)->getPixelFormat().toString().c_str()); + } + + (*texture)->allocBuffer(width, height); +} +#endif + #endif diff --git a/backends/platform/android/graphics.h b/backends/platform/android/graphics.h new file mode 100755 index 00000000000..b6b01458470 --- /dev/null +++ b/backends/platform/android/graphics.h @@ -0,0 +1,168 @@ +/* ResidualVM - Graphic Adventure Engine + * + * ResidualVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ANDROID_GRAPHICS_H +#define ANDROID_GRAPHICS_H + +#include "common/scummsys.h" +#include "backends/graphics/resvm-graphics.h" + +class AndroidGraphicsManager : public ResVmGraphicsManager { +public: + AndroidGraphicsManager(); + virtual ~AndroidGraphicsManager(); + + void initSurface(); + void deinitSurface(); + + void updateScreen() override; + + void displayMessageOnOSD(const char *msg); + + bool notifyMousePosition(Common::Point &mouse); + Common::Point getMousePosition() { return Common::Point(_cursorX, _cursorY); } + void setMousePosition(int x, int y) { _cursorX = x; _cursorY = y; } + + virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override; + virtual int getDefaultGraphicsMode() const override; + virtual bool setGraphicsMode(int mode) override; + virtual void resetGraphicsScale() override; + virtual int getGraphicsMode() const override; + + virtual bool hasFeature(OSystem::Feature f) const override; + virtual void setFeatureState(OSystem::Feature f, bool enable) override; + virtual bool getFeatureState(OSystem::Feature f) const override; + + virtual void showOverlay() override; + virtual void hideOverlay() override; + virtual void clearOverlay() override; + virtual void grabOverlay(void *buf, int pitch) const override; + virtual void copyRectToOverlay(const void *buf, int pitch, + int x, int y, int w, int h) override; + virtual int16 getOverlayHeight() const override; + virtual int16 getOverlayWidth() const override; + virtual Graphics::PixelFormat getOverlayFormat() const override; + + virtual int16 getHeight() const override; + virtual int16 getWidth() const override; + + // PaletteManager API + virtual void setPalette(const byte *colors, uint start, uint num) override; + virtual void grabPalette(byte *colors, uint start, uint num) const override; + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, + int w, int h) override; + virtual Graphics::Surface *lockScreen() override; + virtual void unlockScreen() override; + virtual void fillScreen(uint32 col); + + virtual void initSize(uint width, uint height, + const Graphics::PixelFormat *format) override; + virtual int getScreenChangeID() const override; + + virtual bool showMouse(bool visible) override; + virtual void warpMouse(int x, int y) override; + virtual bool lockMouse(bool lock) override; + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, + int hotspotY, uint32 keycolor, + bool dontScale, + const Graphics::PixelFormat *format) override; + virtual void setCursorPalette(const byte *colors, uint start, uint num) override; + + + void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) override; + + // ResidualVM specific method + void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame); + virtual Graphics::PixelBuffer getScreenPixelBuffer() override; + virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right) override; + void updateScreenRect(); + const GLESBaseTexture *getActiveTexture() const; + void clipMouse(Common::Point &p) const; + +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const override; + virtual Common::List getSupportedFormats() const override; +#endif + +protected: + void setSystemMousePosition(int x, int y) {} + + bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format); + + void refreshScreen(); + + void *getProcAddress(const char *name) const; + +// ResidualVM specific code +private: + void setCursorPaletteInternal(const byte *colors, uint start, uint num); + void disableCursorPalette(); + void initOverlay(); + void initViewport(); + void updateEventScale(); + + enum FixupType { + kClear = 0, // glClear + kClearSwap, // glClear + swapBuffers + kClearUpdate // glClear + updateScreen + }; + + void clearScreen(FixupType type, byte count = 1); +#ifdef USE_RGB_COLOR + void initTexture(GLESBaseTexture **texture, uint width, uint height, + const Graphics::PixelFormat *format); +#endif + +private: + int _screenChangeID; + int _graphicsMode; + bool _opengl; + bool _fullscreen; + bool _ar_correction; + bool _force_redraw; + + // Game layer + GLESBaseTexture *_game_texture; + Graphics::PixelBuffer _game_pbuf; + OpenGL::FrameBuffer *_frame_buffer; + + /** + * The position of the mouse cursor, in window coordinates. + */ + int _cursorX, _cursorY; + + // Overlay layer + GLES4444Texture *_overlay_texture; + bool _show_overlay; + + // Mouse layer + GLESBaseTexture *_mouse_texture; + GLESBaseTexture *_mouse_texture_palette; + GLES5551Texture *_mouse_texture_rgb; + Common::Point _mouse_hotspot; + uint32 _mouse_keycolor; + int _mouse_targetscale; + bool _show_mouse; + bool _use_mouse_palette; +}; + +#endif diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk index 498c7f3dfdc..7859298ef52 100644 --- a/backends/platform/android/module.mk +++ b/backends/platform/android/module.mk @@ -5,7 +5,7 @@ MODULE_OBJS := \ texture.o \ asset-archive.o \ android.o \ - gfx.o \ + graphics.o \ events.o \ snprintf.o \ touchcontrols.o diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 4b0665c9fac..9ff43d2322b 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -58,11 +58,6 @@ static bool npot_supported = false; OpenGL::Shader * g_box_shader; GLuint g_verticesVBO; -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)