ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

backends/platform/android/gfx.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #if defined(__ANDROID__)
00024 
00025 // Allow use of stuff in <time.h>
00026 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h
00027 
00028 // Disable printf override in common/forbidden.h to avoid
00029 // clashes with log.h from the Android SDK.
00030 // That header file uses
00031 //   __attribute__ ((format(printf, 3, 4)))
00032 // which gets messed up by our override mechanism; this could
00033 // be avoided by either changing the Android SDK to use the equally
00034 // legal and valid
00035 //   __attribute__ ((format(printf, 3, 4)))
00036 // or by refining our printf override to use a varadic macro
00037 // (which then wouldn't be portable, though).
00038 // Anyway, for now we just disable the printf override globally
00039 // for the Android port
00040 #define FORBIDDEN_SYMBOL_EXCEPTION_printf
00041 
00042 #include "common/endian.h"
00043 #include "common/tokenizer.h"
00044 #include "graphics/conversion.h"
00045 #include "graphics/opengl/shader.h"
00046 #include "graphics/opengl/context.h"
00047 
00048 #include "backends/platform/android/android.h"
00049 #include "backends/platform/android/jni.h"
00050 
00051 static inline GLfixed xdiv(int numerator, int denominator) {
00052     assert(numerator < (1 << 16));
00053     return (numerator << 16) / denominator;
00054 }
00055 
00056 // ResidualVM specific method
00057 void OSystem_Android::launcherInitSize(uint w, uint h) {
00058     setupScreen(w, h, true, true, false);
00059 }
00060 
00061 // ResidualVM specific method
00062 bool OSystem_Android::lockMouse(bool lock) {
00063     _show_mouse = lock;
00064     return true;
00065 }
00066 
00067 const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const {
00068     static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
00069         { "default", "Default", 0 },
00070         { "filter", "Linear filtering", 1 },
00071         { 0, 0, 0 },
00072     };
00073 
00074     return s_supportedGraphicsModes;
00075 }
00076 
00077 int OSystem_Android::getDefaultGraphicsMode() const {
00078     return 0;
00079 }
00080 
00081 bool OSystem_Android::setGraphicsMode(int mode) {
00082     ENTER("%d", mode);
00083 
00084     if (_game_texture)
00085         _game_texture->setLinearFilter(mode == 1);
00086 
00087     if (_overlay_texture)
00088         _overlay_texture->setLinearFilter(mode == 1);
00089 
00090     if (_mouse_texture)
00091         _mouse_texture->setLinearFilter(mode == 1);
00092 
00093     _graphicsMode = mode;
00094 
00095     return true;
00096 }
00097 
00098 int OSystem_Android::getGraphicsMode() const {
00099     return _graphicsMode;
00100 }
00101 
00102 #ifdef USE_RGB_COLOR
00103 Graphics::PixelFormat OSystem_Android::getScreenFormat() const {
00104     return _game_texture->getPixelFormat();
00105 }
00106 
00107 Common::List<Graphics::PixelFormat> OSystem_Android::getSupportedFormats() const {
00108     Common::List<Graphics::PixelFormat> res;
00109     res.push_back(GLES565Texture::pixelFormat());
00110     res.push_back(GLES5551Texture::pixelFormat());
00111     res.push_back(GLES4444Texture::pixelFormat());
00112     res.push_back(Graphics::PixelFormat::createFormatCLUT8());
00113 
00114     return res;
00115 }
00116 
00117 Common::String OSystem_Android::getPixelFormatName(const Graphics::PixelFormat &format) const {
00118     if (format.bytesPerPixel == 1)
00119         return "CLUT8";
00120 
00121     if (format.aLoss == 8)
00122         return Common::String::format("RGB%u%u%u",
00123                                         8 - format.rLoss,
00124                                         8 - format.gLoss,
00125                                         8 - format.bLoss);
00126 
00127     return Common::String::format("RGBA%u%u%u%u",
00128                                     8 - format.rLoss,
00129                                     8 - format.gLoss,
00130                                     8 - format.bLoss,
00131                                     8 - format.aLoss);
00132 }
00133 
00134 void OSystem_Android::initTexture(GLESBaseTexture **texture,
00135                                     uint width, uint height,
00136                                     const Graphics::PixelFormat *format) {
00137     assert(texture);
00138     Graphics::PixelFormat format_clut8 =
00139         Graphics::PixelFormat::createFormatCLUT8();
00140     Graphics::PixelFormat format_current;
00141     Graphics::PixelFormat format_new;
00142 
00143     if (*texture)
00144         format_current = (*texture)->getPixelFormat();
00145     else
00146         format_current = Graphics::PixelFormat();
00147 
00148     if (format)
00149         format_new = *format;
00150     else
00151         format_new = format_clut8;
00152 
00153     if (format_current != format_new) {
00154         if (*texture)
00155             LOGD("switching pixel format from: %s",
00156                     getPixelFormatName((*texture)->getPixelFormat()).c_str());
00157 
00158         delete *texture;
00159 
00160         if (format_new == GLES565Texture::pixelFormat())
00161             *texture = new GLES565Texture();
00162         else if (format_new == GLES5551Texture::pixelFormat())
00163             *texture = new GLES5551Texture();
00164         else if (format_new == GLES4444Texture::pixelFormat())
00165             *texture = new GLES4444Texture();
00166         else {
00167             // TODO what now?
00168             if (format_new != format_clut8)
00169                 LOGE("unsupported pixel format: %s",
00170                     getPixelFormatName(format_new).c_str());
00171 
00172             *texture = new GLESFakePalette565Texture;
00173         }
00174 
00175         LOGD("new pixel format: %s",
00176                 getPixelFormatName((*texture)->getPixelFormat()).c_str());
00177     }
00178 
00179     (*texture)->allocBuffer(width, height);
00180 }
00181 #endif
00182 
00183 static void logExtensions() {
00184     const char *ext_string =
00185         reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
00186 
00187     LOGI("Extensions:");
00188 
00189     Common::String exts;
00190     Common::StringTokenizer tokenizer(ext_string, " ");
00191     while (!tokenizer.empty()) {
00192         Common::String token = tokenizer.nextToken();
00193 
00194         exts += token + " ";
00195         if (exts.size() > 100) {
00196             LOGI("\t%s", exts.c_str());
00197             exts = "";
00198         }
00199     }
00200 
00201     if (exts.size() > 0)
00202         LOGI("\t%s", exts.c_str());
00203 }
00204 
00205 void OSystem_Android::initSurface() {
00206     LOGD("initializing surface");
00207 
00208     assert(!JNI::haveSurface());
00209 
00210     _screen_changeid = JNI::surface_changeid;
00211     _egl_surface_width = JNI::egl_surface_width;
00212     _egl_surface_height = JNI::egl_surface_height;
00213 
00214     assert(_egl_surface_width > 0 && _egl_surface_height > 0);
00215 
00216     JNI::initSurface();
00217 
00218     // Initialize OpenGLES context.
00219     OpenGLContext.initialize(OpenGL::kContextGLES2);
00220     logExtensions();
00221     GLESTexture::initGL();
00222 
00223     if (_game_texture)
00224         _game_texture->reinit();
00225 
00226     if (_overlay_texture) {
00227         _overlay_texture->reinit();
00228         initOverlay();
00229     }
00230 
00231     if (_mouse_texture)
00232         _mouse_texture->reinit();
00233 }
00234 
00235 void OSystem_Android::deinitSurface() {
00236     if (!JNI::haveSurface())
00237         return;
00238 
00239     LOGD("deinitializing surface");
00240 
00241     _screen_changeid = JNI::surface_changeid;
00242     _egl_surface_width = 0;
00243     _egl_surface_height = 0;
00244 
00245     // release texture resources
00246     if (_game_texture)
00247         _game_texture->release();
00248 
00249     if (_overlay_texture)
00250         _overlay_texture->release();
00251 
00252     if (_mouse_texture)
00253         _mouse_texture->release();
00254 
00255     OpenGL::Context::destroy();
00256 
00257     JNI::deinitSurface();
00258 }
00259 
00260 void OSystem_Android::initViewport() {
00261     LOGD("initializing viewport");
00262 
00263     assert(JNI::haveSurface());
00264 
00265     GLCALL(glDisable(GL_CULL_FACE));
00266     GLCALL(glDisable(GL_DEPTH_TEST));
00267 
00268     GLCALL(glEnable(GL_BLEND));
00269     GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
00270 
00271     GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height));
00272     LOGD("viewport size: %dx%d", _egl_surface_width, _egl_surface_height);
00273 
00274     clearFocusRectangle();
00275 }
00276 
00277 void OSystem_Android::initOverlay() {
00278     // minimum of 320x200
00279     // (surface can get smaller when opening the virtual keyboard on *QVGA*)
00280     int overlay_width = MAX(_egl_surface_width, 320);
00281     int overlay_height = MAX(_egl_surface_height, 200);
00282 
00283     // the 'normal' theme layout uses a max height of 400 pixels. if the
00284     // surface is too big we use only a quarter of the size so that the widgets
00285     // don't get too small. if the surface height has less than 800 pixels, this
00286     // enforces the 'lowres' layout, which will be scaled back up by factor 2x,
00287     // but this looks way better than the 'normal' layout scaled by some
00288     // calculated factors
00289 //  while (overlay_height > 480) {
00290 //      overlay_width /= 2;
00291 //      overlay_height /= 2;
00292 //  }
00293 
00294     LOGI("overlay size is %ux%u", overlay_width, overlay_height);
00295 
00296     _overlay_texture->allocBuffer(overlay_width, overlay_height);
00297     _overlay_texture->setDrawRect(0, 0,
00298                                     _egl_surface_width, _egl_surface_height);
00299 }
00300 
00301 void OSystem_Android::initSize(uint width, uint height,
00302                                 const Graphics::PixelFormat *format) {
00303     ENTER("%d, %d, %p", width, height, format);
00304 
00305     GLTHREADCHECK;
00306 
00307 #ifdef USE_RGB_COLOR
00308     initTexture(&_game_texture, width, height, format);
00309 #else
00310     _game_texture->allocBuffer(width, height);
00311 #endif
00312 #ifdef USE_GLES2
00313     _frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight());
00314     _frame_buffer->attach();
00315 #endif
00316 
00317     updateScreenRect();
00318     updateEventScale();
00319 
00320     // Don't know mouse size yet - it gets reallocated in
00321     // setMouseCursor.  We need the palette allocated before
00322     // setMouseCursor however, so just take a guess at the desired
00323     // size (it's small).
00324     _mouse_texture_palette->allocBuffer(20, 20);
00325 
00326     clearScreen(kClear);
00327 }
00328 
00329 void OSystem_Android::clearScreen(FixupType type, byte count) {
00330     assert(count > 0);
00331 
00332     bool sm = _show_mouse;
00333     _show_mouse = false;
00334 
00335     GLCALL(glDisable(GL_SCISSOR_TEST));
00336 
00337     for (byte i = 0; i < count; ++i) {
00338         // clear screen
00339         GLCALL(glClearColor(0, 0, 0, 1 << 16));
00340         if (_opengl) {
00341             GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
00342         } else {
00343             GLCALL(glClear(GL_COLOR_BUFFER_BIT));
00344         }
00345 
00346         switch (type) {
00347         case kClear:
00348             break;
00349 
00350         case kClearSwap:
00351             JNI::swapBuffers();
00352             break;
00353 
00354         case kClearUpdate:
00355             _force_redraw = true;
00356             updateScreen();
00357             break;
00358         }
00359     }
00360 
00361     if (!_show_overlay)
00362         GLCALL(glEnable(GL_SCISSOR_TEST));
00363 
00364     _show_mouse = sm;
00365     _force_redraw = true;
00366 }
00367 
00368 void OSystem_Android::updateScreenRect() {
00369     Common::Rect rect(0, 0, _egl_surface_width, _egl_surface_height);
00370 
00371     _overlay_texture->setDrawRect(rect);
00372 
00373     uint16 w = _game_texture->width();
00374     uint16 h = _game_texture->height();
00375 
00376     if (w && h && _ar_correction) {
00377 
00378         float dpi[2];
00379         JNI::getDPI(dpi);
00380 
00381         float screen_ar;
00382         if (dpi[0] != 0.0 && dpi[1] != 0.0) {
00383             // horizontal orientation
00384             screen_ar = (dpi[1] * _egl_surface_width) /
00385                         (dpi[0] * _egl_surface_height);
00386         } else {
00387             screen_ar = float(_egl_surface_width) / float(_egl_surface_height);
00388         }
00389 
00390         float game_ar = float(w) / float(h);
00391 
00392         if (screen_ar > game_ar) {
00393             rect.setWidth(round(_egl_surface_height * game_ar));
00394             rect.moveTo((_egl_surface_width - rect.width()) / 2, 0);
00395         } else {
00396             rect.setHeight(round(_egl_surface_width / game_ar));
00397             rect.moveTo((_egl_surface_height - rect.height()) / 2, 0);
00398         }
00399     }
00400 
00401     _game_texture->setDrawRect(rect);
00402 }
00403 
00404 int OSystem_Android::getScreenChangeID() const {
00405     return _screen_changeid;
00406 }
00407 
00408 int16 OSystem_Android::getHeight() {
00409     return _game_texture->height();
00410 }
00411 
00412 int16 OSystem_Android::getWidth() {
00413     return _game_texture->width();
00414 }
00415 
00416 void OSystem_Android::setPalette(const byte *colors, uint start, uint num) {
00417     ENTER("%p, %u, %u", colors, start, num);
00418 
00419 #ifdef USE_RGB_COLOR
00420     assert(_game_texture->hasPalette());
00421 #endif
00422 
00423     GLTHREADCHECK;
00424 
00425     if (!_use_mouse_palette)
00426         setCursorPaletteInternal(colors, start, num);
00427 
00428     const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
00429     byte *p = _game_texture->palette() + start * 2;
00430 
00431     for (uint i = 0; i < num; ++i, colors += 3, p += 2)
00432         WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
00433 }
00434 
00435 void OSystem_Android::grabPalette(byte *colors, uint start, uint num) const {
00436     ENTER("%p, %u, %u", colors, start, num);
00437 
00438 #ifdef USE_RGB_COLOR
00439     assert(_game_texture->hasPalette());
00440 #endif
00441 
00442     GLTHREADCHECK;
00443 
00444     const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
00445     const byte *p = _game_texture->palette_const() + start * 2;
00446 
00447     for (uint i = 0; i < num; ++i, colors += 3, p += 2)
00448         pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]);
00449 }
00450 
00451 void OSystem_Android::copyRectToScreen(const void *buf, int pitch,
00452                                         int x, int y, int w, int h) {
00453     ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
00454 
00455     GLTHREADCHECK;
00456 
00457     _game_texture->updateBuffer(x, y, w, h, buf, pitch);
00458 }
00459 
00460 
00461 // ResidualVM specific method
00462 void OSystem_Android::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame) {
00463     _opengl = accel3d;
00464     initViewport();
00465 
00466     _touchControls.init(this, _egl_surface_width, _egl_surface_height);
00467 
00468     if (_opengl) {
00469         // resize game texture
00470         initSize(screenW, screenH, 0);
00471         if (isGame)
00472             _game_texture->setGameTexture();
00473         // format is not used by the gfx_opengl driver, use fake format
00474         _game_pbuf.set(Graphics::PixelFormat(), 0);
00475 
00476     } else {
00477         Graphics::PixelFormat format = GLES565Texture::pixelFormat();
00478         initSize(screenW, screenH, &format);
00479         // as there is no support for the texture surface's lock/unlock mechanism in gfx_tinygl/...
00480         // do not use _game_texture->surface()->pixels directly
00481         _game_pbuf.create(_game_texture->getPixelFormat(),
00482                 _game_texture->width() * _game_texture->height(), DisposeAfterUse::YES);
00483     }
00484 
00485 }
00486 
00487 Graphics::PixelBuffer OSystem_Android::getScreenPixelBuffer() {
00488     return _game_pbuf;
00489 }
00490 
00491 void OSystem_Android::updateScreen() {
00492     //ENTER();
00493 
00494     GLTHREADCHECK;
00495 
00496     if (!JNI::haveSurface())
00497         return;
00498 
00499         if (_game_pbuf) {
00500             int pitch = _game_texture->width() * _game_texture->getPixelFormat().bytesPerPixel;
00501             _game_texture->updateBuffer(0, 0, _game_texture->width(), _game_texture->height(),
00502                     _game_pbuf.getRawBuffer(), pitch);
00503         }
00504 
00505         if (!_force_redraw &&
00506                 !_game_texture->dirty() &&
00507                 !_overlay_texture->dirty() &&
00508                 !_mouse_texture->dirty())
00509             return;
00510 
00511         _force_redraw = false;
00512 
00513         if (_frame_buffer) {
00514             _frame_buffer->detach();
00515             glViewport(0,0, _egl_surface_width, _egl_surface_height);
00516         }
00517 
00518         // clear pointer leftovers in dead areas
00519         clearScreen(kClear);
00520 
00521     // TODO this doesnt work on those sucky drivers, do it differently
00522     //  if (_show_overlay)
00523     //      GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f));
00524 
00525         if (true || _focus_rect.isEmpty()) {
00526             _game_texture->drawTextureRect();
00527             drawVirtControls();
00528         } else {
00529 // TODO what is this and do we have engines using it?
00530 #if 0
00531             GLCALL(glPushMatrix());
00532 
00533             GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()),
00534                             xdiv(_egl_surface_height, _focus_rect.height()),
00535                             1 << 16));
00536             GLCALL(glTranslatex(-_focus_rect.left << 16,
00537                                 -_focus_rect.top << 16, 0));
00538             GLCALL(glScalex(xdiv(_game_texture->width(), _egl_surface_width),
00539                             xdiv(_game_texture->height(), _egl_surface_height),
00540                             1 << 16));
00541 
00542             _game_texture->drawTextureRect();
00543 
00544             GLCALL(glPopMatrix());
00545 #endif
00546         }
00547 
00548         int cs = _mouse_targetscale;
00549 
00550         if (_show_overlay) {
00551     // TODO see above
00552     //      GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff));
00553 
00554             // ugly, but the modern theme sets a wacko factor, only god knows why
00555             cs = 1;
00556 
00557             GLCALL(_overlay_texture->drawTextureRect());
00558         }
00559 
00560         if (_show_mouse && !_mouse_texture->isEmpty()) {
00561             const Common::Point &mouse = getEventManager()->getMousePos();
00562             if (_show_overlay) {
00563                 _mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height());
00564             }
00565 // TODO: Port the non-overlay code as well?
00566 #if 0
00567             if (_show_overlay) {
00568             } else {
00569                 const Common::Rect &r = _game_texture->getDrawRect();
00570 
00571                 GLCALL(glTranslatex(r.left << 16,
00572                                     r.top << 16,
00573                                     0));
00574                 GLCALL(glScalex(xdiv(r.width(), _game_texture->width()),
00575                                 xdiv(r.height(), _game_texture->height()),
00576                                 1 << 16));
00577             }
00578 
00579             GLCALL(glTranslatex((-_mouse_hotspot.x * cs) << 16,
00580                                 (-_mouse_hotspot.y * cs) << 16,
00581                                 0));
00582 
00583 #endif
00584     }
00585 
00586     if (!JNI::swapBuffers())
00587         LOGW("swapBuffers failed: 0x%x", glGetError());
00588 
00589     if (_frame_buffer)
00590         _frame_buffer->attach();
00591 }
00592 
00593 void OSystem_Android::drawVirtControls() {
00594     if (_show_overlay)
00595         return;
00596 
00597     glEnable(GL_BLEND);
00598     _touchControls.draw();
00599 }
00600 
00601 Graphics::Surface *OSystem_Android::lockScreen() {
00602     ENTER();
00603 
00604     GLTHREADCHECK;
00605 
00606     Graphics::Surface *surface = _game_texture->surface();
00607     assert(surface->getPixels());
00608 
00609     return surface;
00610 }
00611 
00612 void OSystem_Android::unlockScreen() {
00613     ENTER();
00614 
00615     GLTHREADCHECK;
00616 
00617     assert(_game_texture->dirty());
00618 }
00619 
00620 void OSystem_Android::setShakePos(int shake_offset) {
00621     /* not used in any engine */
00622 }
00623 
00624 void OSystem_Android::fillScreen(uint32 col) {
00625     ENTER("%u", col);
00626 
00627     GLTHREADCHECK;
00628 
00629     _game_texture->fillBuffer(col);
00630 }
00631 
00632 void OSystem_Android::setFocusRectangle(const Common::Rect& rect) {
00633     ENTER("%d, %d, %d, %d", rect.left, rect.top, rect.right, rect.bottom);
00634 
00635     if (_enable_zoning) {
00636         _focus_rect = rect;
00637         _force_redraw = true;
00638     }
00639 }
00640 
00641 void OSystem_Android::clearFocusRectangle() {
00642     ENTER();
00643 
00644     if (_enable_zoning) {
00645         _focus_rect = Common::Rect();
00646         _force_redraw = true;
00647     }
00648 }
00649 
00650 void OSystem_Android::showOverlay() {
00651     ENTER();
00652 
00653     _show_overlay = true;
00654     _force_redraw = true;
00655 
00656     updateEventScale();
00657 
00658     warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2);
00659 
00660     GLCALL(glDisable(GL_SCISSOR_TEST));
00661 }
00662 
00663 void OSystem_Android::hideOverlay() {
00664     ENTER();
00665 
00666     _show_overlay = false;
00667 
00668     updateEventScale();
00669 
00670     warpMouse(_game_texture->width() / 2, _game_texture->height() / 2);
00671 
00672     // double buffered, flip twice
00673     clearScreen(kClearUpdate, 2);
00674 
00675     GLCALL(glEnable(GL_SCISSOR_TEST));
00676 }
00677 
00678 void OSystem_Android::clearOverlay() {
00679     ENTER();
00680 
00681     GLTHREADCHECK;
00682 
00683     _overlay_texture->fillBuffer(0);
00684 }
00685 
00686 void OSystem_Android::grabOverlay(void *buf, int pitch) {
00687     ENTER("%p, %d", buf, pitch);
00688 
00689     GLTHREADCHECK;
00690 
00691     const Graphics::Surface *surface = _overlay_texture->surface_const();
00692     assert(surface->format.bytesPerPixel == sizeof(uint16));
00693 
00694     byte *dst = (byte *)buf;
00695     const byte *src = (const byte *)surface->getPixels();
00696     uint h = surface->h;
00697 
00698     do {
00699         memcpy(dst, src, surface->w * surface->format.bytesPerPixel);
00700         src += surface->pitch;
00701         dst += pitch;
00702     } while (--h);
00703 }
00704 
00705 void OSystem_Android::copyRectToOverlay(const void *buf, int pitch,
00706                                         int x, int y, int w, int h) {
00707     ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
00708 
00709     GLTHREADCHECK;
00710 
00711     _overlay_texture->updateBuffer(x, y, w, h, buf, pitch);
00712 }
00713 
00714 int16 OSystem_Android::getOverlayHeight() {
00715     return _overlay_texture->height();
00716 }
00717 
00718 int16 OSystem_Android::getOverlayWidth() {
00719     return _overlay_texture->width();
00720 }
00721 
00722 Graphics::PixelFormat OSystem_Android::getOverlayFormat() const {
00723     return _overlay_texture->getPixelFormat();
00724 }
00725 
00726 bool OSystem_Android::showMouse(bool visible) {
00727     ENTER("%d", visible);
00728 
00729     _show_mouse = visible;
00730 
00731     return true;
00732 }
00733 
00734 void OSystem_Android::setMouseCursor(const void *buf, uint w, uint h,
00735                                         int hotspotX, int hotspotY,
00736                                         uint32 keycolor, bool dontScale,
00737                                         const Graphics::PixelFormat *format) {
00738     ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
00739             keycolor, dontScale, format);
00740 
00741     GLTHREADCHECK;
00742 
00743 #ifdef USE_RGB_COLOR
00744     if (format && format->bytesPerPixel > 1) {
00745         if (_mouse_texture != _mouse_texture_rgb) {
00746             LOGD("switching to rgb mouse cursor");
00747 
00748             assert(!_mouse_texture_rgb);
00749             _mouse_texture_rgb = new GLES5551Texture();
00750             _mouse_texture_rgb->setLinearFilter(_graphicsMode == 1);
00751         }
00752 
00753         _mouse_texture = _mouse_texture_rgb;
00754     } else {
00755         if (_mouse_texture != _mouse_texture_palette)
00756             LOGD("switching to paletted mouse cursor");
00757 
00758         _mouse_texture = _mouse_texture_palette;
00759 
00760         delete _mouse_texture_rgb;
00761         _mouse_texture_rgb = 0;
00762     }
00763 #endif
00764 
00765     _mouse_texture->allocBuffer(w, h);
00766 
00767     if (_mouse_texture == _mouse_texture_palette) {
00768         assert(keycolor < 256);
00769 
00770         byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
00771         WRITE_UINT16(p, READ_UINT16(p) | 1);
00772 
00773         _mouse_keycolor = keycolor;
00774 
00775         p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
00776         WRITE_UINT16(p, READ_UINT16(p) & ~1);
00777     }
00778 
00779     if (w == 0 || h == 0)
00780         return;
00781 
00782     if (_mouse_texture == _mouse_texture_palette) {
00783         _mouse_texture->updateBuffer(0, 0, w, h, buf, w);
00784     } else {
00785         uint16 pitch = _mouse_texture->pitch();
00786 
00787         byte *tmp = new byte[pitch * h];
00788 
00789         // meh, a 16bit cursor without alpha bits... this is so silly
00790         if (!crossBlit(tmp, (const byte *)buf, pitch, w * 2, w, h,
00791                         _mouse_texture->getPixelFormat(),
00792                         *format)) {
00793             LOGE("crossblit failed");
00794 
00795             delete[] tmp;
00796 
00797             _mouse_texture->allocBuffer(0, 0);
00798 
00799             return;
00800         }
00801 
00802         const uint16 *s = (const uint16 *)buf;
00803         uint16 *d = (uint16 *)tmp;
00804         for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
00805             for (uint16 x = 0; x < w; ++x, d++)
00806                 if (*s++ == (keycolor & 0xffff))
00807                     *d = 0;
00808 
00809         _mouse_texture->updateBuffer(0, 0, w, h, tmp, pitch);
00810 
00811         delete[] tmp;
00812     }
00813 
00814     _mouse_hotspot = Common::Point(hotspotX, hotspotY);
00815     // TODO: Adapt to the new "do not scale" cursor logic.
00816     _mouse_targetscale = 1;
00817 }
00818 
00819 void OSystem_Android::setCursorPaletteInternal(const byte *colors,
00820                                                 uint start, uint num) {
00821     const Graphics::PixelFormat &pf =
00822         _mouse_texture_palette->getPalettePixelFormat();
00823     byte *p = _mouse_texture_palette->palette() + start * 2;
00824 
00825     for (uint i = 0; i < num; ++i, colors += 3, p += 2)
00826         WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
00827 
00828     p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
00829     WRITE_UINT16(p, READ_UINT16(p) & ~1);
00830 }
00831 
00832 void OSystem_Android::setCursorPalette(const byte *colors,
00833                                         uint start, uint num) {
00834     ENTER("%p, %u, %u", colors, start, num);
00835 
00836     GLTHREADCHECK;
00837 
00838     if (!_mouse_texture->hasPalette()) {
00839         LOGD("switching to paletted mouse cursor");
00840 
00841         _mouse_texture = _mouse_texture_palette;
00842 
00843         delete _mouse_texture_rgb;
00844         _mouse_texture_rgb = 0;
00845     }
00846 
00847     setCursorPaletteInternal(colors, start, num);
00848     _use_mouse_palette = true;
00849 }
00850 
00851 void OSystem_Android::disableCursorPalette() {
00852     // when disabling the cursor palette, and we're running a clut8 game,
00853     // it expects the game palette to be used for the cursor
00854     if (_game_texture->hasPalette()) {
00855         const byte *src = _game_texture->palette_const();
00856         byte *dst = _mouse_texture_palette->palette();
00857 
00858         const Graphics::PixelFormat &pf_src =
00859             _game_texture->getPalettePixelFormat();
00860         const Graphics::PixelFormat &pf_dst =
00861             _mouse_texture_palette->getPalettePixelFormat();
00862 
00863         uint8 r, g, b;
00864 
00865         for (uint i = 0; i < 256; ++i, src += 2, dst += 2) {
00866             pf_src.colorToRGB(READ_UINT16(src), r, g, b);
00867             WRITE_UINT16(dst, pf_dst.RGBToColor(r, g, b));
00868         }
00869 
00870         byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
00871         WRITE_UINT16(p, READ_UINT16(p) & ~1);
00872     }
00873 }
00874 
00875 #endif


Generated on Sat Feb 16 2019 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge