1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #if defined(__ANDROID__)
24
25 // Allow use of stuff in <time.h>
26 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h
27
28 // Disable printf override in common/forbidden.h to avoid
29 // clashes with log.h from the Android SDK.
30 // That header file uses
31 // __attribute__ ((format(printf, 3, 4)))
32 // which gets messed up by our override mechanism; this could
33 // be avoided by either changing the Android SDK to use the equally
34 // legal and valid
35 // __attribute__ ((format(printf, 3, 4)))
36 // or by refining our printf override to use a varadic macro
37 // (which then wouldn't be portable, though).
38 // Anyway, for now we just disable the printf override globally
39 // for the Android port
40 #define FORBIDDEN_SYMBOL_EXCEPTION_printf
41
42 #include "common/tokenizer.h"
43 #include "graphics/conversion.h"
44 #include "graphics/opengl/shader.h"
45 #include "graphics/opengl/context.h"
46
47 #include "backends/platform/android3d/android.h"
48 #include "backends/platform/android3d/events.h"
49 #include "backends/platform/android3d/graphics.h"
50 #include "backends/platform/android3d/jni-android.h"
51
AndroidGraphicsManager()52 AndroidGraphicsManager::AndroidGraphicsManager() :
53 _screenChangeID(0),
54 _graphicsMode(0),
55 _opengl(false),
56 _fullscreen(true),
57 _ar_correction(true),
58 _force_redraw(false),
59 _game_texture(0),
60 _game_pbuf(),
61 _frame_buffer(0),
62 _cursorX(0),
63 _cursorY(0),
64 _overlay_texture(0),
65 _show_overlay(false),
66 _mouse_texture(0),
67 _mouse_texture_palette(0),
68 _mouse_texture_rgb(0),
69 _mouse_hotspot(),
70 _mouse_keycolor(0),
71 _show_mouse(false),
72 _use_mouse_palette(false)
73 {
74 _game_texture = new GLESFakePalette565Texture();
75 _overlay_texture = new GLES4444Texture();
76 _mouse_texture_palette = new GLESFakePalette5551Texture();
77 _mouse_texture = _mouse_texture_palette;
78
79 }
80
~AndroidGraphicsManager()81 AndroidGraphicsManager::~AndroidGraphicsManager() {
82 delete _game_texture;
83 delete _overlay_texture;
84 delete _mouse_texture_palette;
85 delete _mouse_texture_rgb;
86
87 }
88
logExtensions()89 static void logExtensions() {
90 const char *ext_string =
91 reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
92
93 LOGI("Extensions:");
94
95 Common::String exts;
96 Common::StringTokenizer tokenizer(ext_string, " ");
97 while (!tokenizer.empty()) {
98 Common::String token = tokenizer.nextToken();
99
100 exts += token + " ";
101 if (exts.size() > 100) {
102 LOGI("\t%s", exts.c_str());
103 exts = "";
104 }
105 }
106
107 if (exts.size() > 0)
108 LOGI("\t%s", exts.c_str());
109 }
110
111
initSurface()112 void AndroidGraphicsManager::initSurface() {
113 LOGD("initializing surface");
114
115 assert(!JNI::haveSurface());
116
117 JNI::initSurface();
118
119 _screenChangeID = JNI::surface_changeid;
120
121 // Initialize OpenGLES context.
122 OpenGLContext.initialize(OpenGL::kOGLContextGLES2);
123 logExtensions();
124 GLESTexture::initGL();
125
126 if (_game_texture)
127 _game_texture->reinit();
128
129 if (_overlay_texture) {
130 _overlay_texture->reinit();
131 initOverlay();
132 }
133
134 if (_mouse_texture)
135 _mouse_texture->reinit();
136
137 initViewport();
138 updateScreenRect();
139 // double buffered, flip twice
140 clearScreen(kClearUpdate, 2);
141 updateEventScale();
142 }
143
deinitSurface()144 void AndroidGraphicsManager::deinitSurface() {
145 if (!JNI::haveSurface())
146 return;
147
148 LOGD("deinitializing surface");
149
150 _screenChangeID = JNI::surface_changeid;
151
152 // release texture resources
153 if (_game_texture)
154 _game_texture->release();
155
156 if (_overlay_texture)
157 _overlay_texture->release();
158
159 if (_mouse_texture)
160 _mouse_texture->release();
161
162 OpenGL::ContextGL::destroy();
163
164 JNI::deinitSurface();
165 }
166
updateScreen()167 void AndroidGraphicsManager::updateScreen() {
168 //ENTER();
169
170 GLTHREADCHECK;
171
172 if (!JNI::haveSurface())
173 return;
174
175 if (_game_pbuf) {
176 int pitch = _game_texture->width() * _game_texture->getPixelFormat().bytesPerPixel;
177 _game_texture->updateBuffer(0, 0, _game_texture->width(), _game_texture->height(),
178 _game_pbuf.getRawBuffer(), pitch);
179 }
180
181 if (!_force_redraw &&
182 !_game_texture->dirty() &&
183 !_overlay_texture->dirty() &&
184 !_mouse_texture->dirty())
185 return;
186
187 _force_redraw = false;
188
189 if (_frame_buffer) {
190 _frame_buffer->detach();
191 glViewport(0,0, JNI::egl_surface_width, JNI::egl_surface_height);
192 }
193
194 // clear pointer leftovers in dead areas
195 clearScreen(kClear);
196
197 _game_texture->drawTextureRect();
198 if (!_show_overlay) {
199 glEnable(GL_BLEND);
200 dynamic_cast<OSystem_Android *>(g_system)->getTouchControls()->draw();
201 }
202
203 int cs = _mouse_targetscale;
204
205 if (_show_overlay) {
206 // ugly, but the modern theme sets a wacko factor, only god knows why
207 cs = 1;
208
209 GLCALL(_overlay_texture->drawTextureRect());
210 }
211
212 if (_show_mouse && !_mouse_texture->isEmpty()) {
213 const Common::Point &mouse = g_system->getEventManager()->getMousePos();
214 if (_show_overlay) {
215 _mouse_texture->drawTexture(mouse.x * cs, mouse.y * cs, _mouse_texture->width(), _mouse_texture->height());
216 }
217 }
218
219 if (!JNI::swapBuffers())
220 LOGW("swapBuffers failed: 0x%x", glGetError());
221
222 if (_frame_buffer)
223 _frame_buffer->attach();
224 }
225
displayMessageOnOSD(const Common::U32String & msg)226 void AndroidGraphicsManager::displayMessageOnOSD(const Common::U32String &msg) {
227 ENTER("%s", msg.encode().c_str());
228
229 JNI::displayMessageOnOSD(msg);
230 }
231
notifyMousePosition(Common::Point & mouse)232 bool AndroidGraphicsManager::notifyMousePosition(Common::Point &mouse) {
233 clipMouse(mouse);
234 setMousePosition(mouse.x, mouse.y);
235 return true;
236 }
237
getSupportedGraphicsModes() const238 const OSystem::GraphicsMode *AndroidGraphicsManager::getSupportedGraphicsModes() const {
239 static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
240 { "default", "Default", 0 },
241 { 0, 0, 0 },
242 };
243
244 return s_supportedGraphicsModes;
245 }
246
getDefaultGraphicsMode() const247 int AndroidGraphicsManager::getDefaultGraphicsMode() const {
248 return 0;
249 }
250
setGraphicsMode(int mode,uint flags)251 bool AndroidGraphicsManager::setGraphicsMode(int mode, uint flags) {
252 return true;
253 }
254
getGraphicsMode() const255 int AndroidGraphicsManager::getGraphicsMode() const {
256 return _graphicsMode;
257 }
258
hasFeature(OSystem::Feature f) const259 bool AndroidGraphicsManager::hasFeature(OSystem::Feature f) const {
260 if (f == OSystem::kFeatureCursorPalette ||
261 f == OSystem::kFeatureFullscreenMode ||
262 f == OSystem::kFeatureAspectRatioCorrection) {
263 return true;
264 }
265 return false;
266 }
267
setFeatureState(OSystem::Feature f,bool enable)268 void AndroidGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
269 switch (f) {
270 case OSystem::kFeatureCursorPalette:
271 _use_mouse_palette = enable;
272 if (!enable)
273 disableCursorPalette();
274 break;
275 case OSystem::kFeatureFullscreenMode:
276 _fullscreen = enable;
277 updateScreenRect();
278 break;
279 case OSystem::kFeatureAspectRatioCorrection:
280 _ar_correction = enable;
281 updateScreenRect();
282 break;
283 default:
284 break;
285 }
286 }
287
getFeatureState(OSystem::Feature f) const288 bool AndroidGraphicsManager::getFeatureState(OSystem::Feature f) const {
289 switch (f) {
290 case OSystem::kFeatureCursorPalette:
291 return _use_mouse_palette;
292 case OSystem::kFeatureFullscreenMode:
293 return _fullscreen;
294 case OSystem::kFeatureAspectRatioCorrection:
295 return _ar_correction;
296 default:
297 return false;
298 }
299 }
300
showOverlay()301 void AndroidGraphicsManager::showOverlay() {
302 ENTER();
303
304 _show_overlay = true;
305 _force_redraw = true;
306
307 updateEventScale();
308
309 warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2);
310
311 GLCALL(glDisable(GL_SCISSOR_TEST));
312 }
313
hideOverlay()314 void AndroidGraphicsManager::hideOverlay() {
315 ENTER();
316
317 _show_overlay = false;
318
319 updateEventScale();
320
321 warpMouse(_game_texture->width() / 2, _game_texture->height() / 2);
322
323 // double buffered, flip twice
324 clearScreen(kClearUpdate, 2);
325
326 GLCALL(glEnable(GL_SCISSOR_TEST));
327 }
328
clearOverlay()329 void AndroidGraphicsManager::clearOverlay() {
330 ENTER();
331
332 GLTHREADCHECK;
333
334 _overlay_texture->fillBuffer(0);
335 }
336
grabOverlay(Graphics::Surface & surface) const337 void AndroidGraphicsManager::grabOverlay(Graphics::Surface &surface) const {
338 GLTHREADCHECK;
339
340 const Graphics::Surface *overlaySurface = _overlay_texture->surface_const();
341
342 assert(surface.w >= overlaySurface->w);
343 assert(surface.h >= overlaySurface->h);
344 assert(surface.format.bytesPerPixel == sizeof(uint16));
345 assert(overlaySurface->format.bytesPerPixel == sizeof(uint16));
346
347 const byte *src = (const byte *)overlaySurface->getPixels();
348 byte *dst = (byte *)surface.getPixels();
349 Graphics::copyBlit(dst, src, surface.pitch, overlaySurface->pitch, surface.w, surface.h, sizeof(uint16));
350 }
351
copyRectToOverlay(const void * buf,int pitch,int x,int y,int w,int h)352 void AndroidGraphicsManager::copyRectToOverlay(const void *buf, int pitch,
353 int x, int y, int w, int h) {
354 ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
355
356 GLTHREADCHECK;
357
358 _overlay_texture->updateBuffer(x, y, w, h, buf, pitch);
359 }
360
getOverlayHeight() const361 int16 AndroidGraphicsManager::getOverlayHeight() const {
362 return _overlay_texture->height();
363 }
364
getOverlayWidth() const365 int16 AndroidGraphicsManager::getOverlayWidth() const {
366 return _overlay_texture->width();
367 }
368
getOverlayFormat() const369 Graphics::PixelFormat AndroidGraphicsManager::getOverlayFormat() const {
370 return _overlay_texture->getPixelFormat();
371 }
372
getHeight() const373 int16 AndroidGraphicsManager::getHeight() const {
374 return _game_texture->height();
375 }
376
getWidth() const377 int16 AndroidGraphicsManager::getWidth() const {
378 return _game_texture->width();
379 }
380
setPalette(const byte * colors,uint start,uint num)381 void AndroidGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
382 ENTER("%p, %u, %u", colors, start, num);
383
384 #ifdef USE_RGB_COLOR
385 assert(_game_texture->hasPalette());
386 #endif
387
388 GLTHREADCHECK;
389
390 if (!_use_mouse_palette)
391 setCursorPaletteInternal(colors, start, num);
392
393 const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
394 byte *p = _game_texture->palette() + start * 2;
395
396 for (uint i = 0; i < num; ++i, colors += 3, p += 2)
397 WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
398 }
399
grabPalette(byte * colors,uint start,uint num) const400 void AndroidGraphicsManager::grabPalette(byte *colors, uint start, uint num) const {
401 ENTER("%p, %u, %u", colors, start, num);
402
403 #ifdef USE_RGB_COLOR
404 assert(_game_texture->hasPalette());
405 #endif
406
407 GLTHREADCHECK;
408
409 const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
410 const byte *p = _game_texture->palette_const() + start * 2;
411
412 for (uint i = 0; i < num; ++i, colors += 3, p += 2)
413 pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]);
414 }
415
lockScreen()416 Graphics::Surface *AndroidGraphicsManager::lockScreen() {
417 ENTER();
418
419 GLTHREADCHECK;
420
421 Graphics::Surface *surface = _game_texture->surface();
422 assert(surface->getPixels());
423
424 return surface;
425 }
426
unlockScreen()427 void AndroidGraphicsManager::unlockScreen() {
428 ENTER();
429
430 GLTHREADCHECK;
431
432 assert(_game_texture->dirty());
433 }
434
fillScreen(uint32 col)435 void AndroidGraphicsManager::fillScreen(uint32 col) {
436 ENTER("%u", col);
437
438 GLTHREADCHECK;
439
440 _game_texture->fillBuffer(col);
441 }
442
copyRectToScreen(const void * buf,int pitch,int x,int y,int w,int h)443 void AndroidGraphicsManager::copyRectToScreen(const void *buf, int pitch,
444 int x, int y, int w, int h) {
445 ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
446
447 GLTHREADCHECK;
448
449 _game_texture->updateBuffer(x, y, w, h, buf, pitch);
450 }
451
initSize(uint width,uint height,const Graphics::PixelFormat * format)452 void AndroidGraphicsManager::initSize(uint width, uint height,
453 const Graphics::PixelFormat *format) {
454 setupScreen(width, height, true, true);
455 }
456
initSizeIntern(uint width,uint height,const Graphics::PixelFormat * format)457 void AndroidGraphicsManager::initSizeIntern(uint width, uint height,
458 const Graphics::PixelFormat *format) {
459 ENTER("%d, %d, %p", width, height, format);
460
461 GLTHREADCHECK;
462
463 #ifdef USE_RGB_COLOR
464 initTexture(&_game_texture, width, height, format);
465 #else
466 _game_texture->allocBuffer(width, height);
467 #endif
468 #ifdef USE_GLES2
469 _frame_buffer = new OpenGL::FrameBuffer(_game_texture->getTextureName(), _game_texture->width(), _game_texture->height(), _game_texture->texWidth(), _game_texture->texHeight());
470 _frame_buffer->attach();
471 #endif
472
473 updateScreenRect();
474 updateEventScale();
475
476 // Don't know mouse size yet - it gets reallocated in
477 // setMouseCursor. We need the palette allocated before
478 // setMouseCursor however, so just take a guess at the desired
479 // size (it's small).
480 _mouse_texture_palette->allocBuffer(20, 20);
481
482 clearScreen(kClear);
483 }
484
getScreenChangeID() const485 int AndroidGraphicsManager::getScreenChangeID() const {
486 return _screenChangeID;
487 }
488
showMouse(bool visible)489 bool AndroidGraphicsManager::showMouse(bool visible) {
490 ENTER("%d", visible);
491
492 _show_mouse = visible;
493
494 return true;
495 }
496
warpMouse(int x,int y)497 void AndroidGraphicsManager::warpMouse(int x, int y) {
498 ENTER("%d, %d", x, y);
499
500 Common::Event e;
501
502 e.type = Common::EVENT_MOUSEMOVE;
503 e.mouse.x = x;
504 e.mouse.y = y;
505
506 clipMouse(e.mouse);
507
508 setMousePosition(e.mouse.x, e.mouse.y);
509
510 dynamic_cast<OSystem_Android *>(g_system)->pushEvent(e);
511 }
512
setMouseCursor(const void * buf,uint w,uint h,int hotspotX,int hotspotY,uint32 keycolor,bool dontScale,const Graphics::PixelFormat * format)513 void AndroidGraphicsManager::setMouseCursor(const void *buf, uint w, uint h,
514 int hotspotX, int hotspotY,
515 uint32 keycolor, bool dontScale,
516 const Graphics::PixelFormat *format) {
517 ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
518 keycolor, dontScale, format);
519
520 GLTHREADCHECK;
521
522 #ifdef USE_RGB_COLOR
523 if (format && format->bytesPerPixel > 1) {
524 if (_mouse_texture != _mouse_texture_rgb) {
525 LOGD("switching to rgb mouse cursor");
526
527 assert(!_mouse_texture_rgb);
528 _mouse_texture_rgb = new GLES5551Texture();
529 _mouse_texture_rgb->setLinearFilter(_graphicsMode == 1);
530 }
531
532 _mouse_texture = _mouse_texture_rgb;
533 } else {
534 if (_mouse_texture != _mouse_texture_palette)
535 LOGD("switching to paletted mouse cursor");
536
537 _mouse_texture = _mouse_texture_palette;
538
539 delete _mouse_texture_rgb;
540 _mouse_texture_rgb = 0;
541 }
542 #endif
543
544 _mouse_texture->allocBuffer(w, h);
545
546 if (_mouse_texture == _mouse_texture_palette) {
547 assert(keycolor < 256);
548
549 byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
550 WRITE_UINT16(p, READ_UINT16(p) | 1);
551
552 _mouse_keycolor = keycolor;
553
554 p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
555 WRITE_UINT16(p, READ_UINT16(p) & ~1);
556 }
557
558 if (w == 0 || h == 0)
559 return;
560
561 if (_mouse_texture == _mouse_texture_palette) {
562 _mouse_texture->updateBuffer(0, 0, w, h, buf, w);
563 } else {
564 uint16 pitch = _mouse_texture->pitch();
565
566 byte *tmp = new byte[pitch * h];
567
568 // meh, a 16bit cursor without alpha bits... this is so silly
569 if (!crossBlit(tmp, (const byte *)buf, pitch, w * 2, w, h,
570 _mouse_texture->getPixelFormat(),
571 *format)) {
572 LOGE("crossblit failed");
573
574 delete[] tmp;
575
576 _mouse_texture->allocBuffer(0, 0);
577
578 return;
579 }
580
581 const uint16 *s = (const uint16 *)buf;
582 uint16 *d = (uint16 *)tmp;
583 for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
584 for (uint16 x = 0; x < w; ++x, d++)
585 if (*s++ == (keycolor & 0xffff))
586 *d = 0;
587
588 _mouse_texture->updateBuffer(0, 0, w, h, tmp, pitch);
589
590 delete[] tmp;
591 }
592
593 _mouse_hotspot = Common::Point(hotspotX, hotspotY);
594 // TODO: Adapt to the new "do not scale" cursor logic.
595 _mouse_targetscale = 1;
596 }
597
setCursorPaletteInternal(const byte * colors,uint start,uint num)598 void AndroidGraphicsManager::setCursorPaletteInternal(const byte *colors,
599 uint start, uint num) {
600 const Graphics::PixelFormat &pf =
601 _mouse_texture_palette->getPalettePixelFormat();
602 byte *p = _mouse_texture_palette->palette() + start * 2;
603
604 for (uint i = 0; i < num; ++i, colors += 3, p += 2)
605 WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
606
607 p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
608 WRITE_UINT16(p, READ_UINT16(p) & ~1);
609 }
610
setCursorPalette(const byte * colors,uint start,uint num)611 void AndroidGraphicsManager::setCursorPalette(const byte *colors,
612 uint start, uint num) {
613 ENTER("%p, %u, %u", colors, start, num);
614
615 GLTHREADCHECK;
616
617 if (!_mouse_texture->hasPalette()) {
618 LOGD("switching to paletted mouse cursor");
619
620 _mouse_texture = _mouse_texture_palette;
621
622 delete _mouse_texture_rgb;
623 _mouse_texture_rgb = 0;
624 }
625
626 setCursorPaletteInternal(colors, start, num);
627 _use_mouse_palette = true;
628 }
629
disableCursorPalette()630 void AndroidGraphicsManager::disableCursorPalette() {
631 // when disabling the cursor palette, and we're running a clut8 game,
632 // it expects the game palette to be used for the cursor
633 if (_game_texture->hasPalette()) {
634 const byte *src = _game_texture->palette_const();
635 byte *dst = _mouse_texture_palette->palette();
636
637 const Graphics::PixelFormat &pf_src =
638 _game_texture->getPalettePixelFormat();
639 const Graphics::PixelFormat &pf_dst =
640 _mouse_texture_palette->getPalettePixelFormat();
641
642 uint8 r, g, b;
643
644 for (uint i = 0; i < 256; ++i, src += 2, dst += 2) {
645 pf_src.colorToRGB(READ_UINT16(src), r, g, b);
646 WRITE_UINT16(dst, pf_dst.RGBToColor(r, g, b));
647 }
648
649 byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
650 WRITE_UINT16(p, READ_UINT16(p) & ~1);
651 }
652 }
653
lockMouse(bool lock)654 bool AndroidGraphicsManager::lockMouse(bool lock) {
655 _show_mouse = lock;
656 return true;
657 }
658
setupScreen(uint screenW,uint screenH,bool fullscreen,bool accel3d)659 void AndroidGraphicsManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) {
660 setupScreen(screenW, screenH, fullscreen, accel3d, true);
661 }
662
setupScreen(uint screenW,uint screenH,bool fullscreen,bool accel3d,bool isGame)663 void AndroidGraphicsManager::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d, bool isGame) {
664 _opengl = accel3d;
665 initViewport();
666
667 if (_opengl) {
668 // resize game texture
669 initSizeIntern(screenW, screenH, 0);
670 if (isGame)
671 _game_texture->setGameTexture();
672 // format is not used by the gfx_opengl driver, use fake format
673 _game_pbuf.set(Graphics::PixelFormat(), 0);
674
675 } else {
676 Graphics::PixelFormat format = GLES565Texture::pixelFormat();
677 initSizeIntern(screenW, screenH, &format);
678 // as there is no support for the texture surface's lock/unlock mechanism in gfx_tinygl/...
679 // do not use _game_texture->surface()->pixels directly
680 _game_pbuf.create(_game_texture->getPixelFormat(),
681 _game_texture->width() * _game_texture->height(), DisposeAfterUse::YES);
682 }
683 }
684
clipMouse(Common::Point & p) const685 void AndroidGraphicsManager::clipMouse(Common::Point &p) const {
686 const GLESBaseTexture *tex = getActiveTexture();
687
688 p.x = CLIP(p.x, tex->getDrawRect().left, tex->getDrawRect().right);
689 p.y = CLIP(p.y, tex->getDrawRect().top, tex->getDrawRect().bottom);
690 }
691
692 #ifdef USE_RGB_COLOR
getScreenFormat() const693 Graphics::PixelFormat AndroidGraphicsManager::getScreenFormat() const {
694 return _game_texture->getPixelFormat();
695 }
696
getSupportedFormats() const697 Common::List<Graphics::PixelFormat> AndroidGraphicsManager::getSupportedFormats() const {
698 Common::List<Graphics::PixelFormat> res;
699 res.push_back(GLES565Texture::pixelFormat());
700 res.push_back(GLES5551Texture::pixelFormat());
701 res.push_back(GLES4444Texture::pixelFormat());
702 res.push_back(Graphics::PixelFormat::createFormatCLUT8());
703
704 return res;
705 }
706 #endif
707
updateScreenRect()708 void AndroidGraphicsManager::updateScreenRect() {
709 Common::Rect rect(0, 0, JNI::egl_surface_width, JNI::egl_surface_height);
710
711 _overlay_texture->setDrawRect(rect);
712
713 uint16 w = _game_texture->width();
714 uint16 h = _game_texture->height();
715
716 if (w && h && _ar_correction) {
717
718 float dpi[2];
719 JNI::getDPI(dpi);
720
721 float screen_ar;
722 if (dpi[0] != 0.0 && dpi[1] != 0.0) {
723 // horizontal orientation
724 screen_ar = (dpi[1] * JNI::egl_surface_width) /
725 (dpi[0] * JNI::egl_surface_height);
726 } else {
727 screen_ar = float(JNI::egl_surface_width) / float(JNI::egl_surface_height);
728 }
729
730 float game_ar = float(w) / float(h);
731
732 if (screen_ar > game_ar) {
733 rect.setWidth(round(JNI::egl_surface_height * game_ar));
734 rect.moveTo((JNI::egl_surface_width - rect.width()) / 2, 0);
735 } else {
736 rect.setHeight(round(JNI::egl_surface_width / game_ar));
737 rect.moveTo((JNI::egl_surface_height - rect.height()) / 2, 0);
738 }
739 }
740
741 _game_texture->setDrawRect(rect);
742 }
743
getActiveTexture() const744 const GLESBaseTexture *AndroidGraphicsManager::getActiveTexture() const {
745 if (_show_overlay)
746 return _overlay_texture;
747 else
748 return _game_texture;
749 }
750
initOverlay()751 void AndroidGraphicsManager::initOverlay() {
752 // minimum of 320x200
753 // (surface can get smaller when opening the virtual keyboard on *QVGA*)
754 int overlay_width = MAX(JNI::egl_surface_width, 320);
755 int overlay_height = MAX(JNI::egl_surface_height, 200);
756
757 // the 'normal' theme layout uses a max height of 400 pixels. if the
758 // surface is too big we use only a quarter of the size so that the widgets
759 // don't get too small. if the surface height has less than 800 pixels, this
760 // enforces the 'lowres' layout, which will be scaled back up by factor 2x,
761 // but this looks way better than the 'normal' layout scaled by some
762 // calculated factors
763 // while (overlay_height > 480) {
764 // overlay_width /= 2;
765 // overlay_height /= 2;
766 // }
767
768 LOGI("overlay size is %ux%u", overlay_width, overlay_height);
769
770 _overlay_texture->allocBuffer(overlay_width, overlay_height);
771 _overlay_texture->setDrawRect(0, 0,
772 JNI::egl_surface_width, JNI::egl_surface_height);
773 }
774
initViewport()775 void AndroidGraphicsManager::initViewport() {
776 LOGD("initializing viewport");
777
778 assert(JNI::haveSurface());
779
780 GLCALL(glDisable(GL_CULL_FACE));
781 GLCALL(glDisable(GL_DEPTH_TEST));
782
783 GLCALL(glEnable(GL_BLEND));
784 GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
785
786 GLCALL(glViewport(0, 0, JNI::egl_surface_width, JNI::egl_surface_height));
787 LOGD("viewport size: %dx%d", JNI::egl_surface_width, JNI::egl_surface_height);
788 }
789
updateEventScale()790 void AndroidGraphicsManager::updateEventScale() {
791 dynamic_cast<OSystem_Android *>(g_system)->updateEventScale(getActiveTexture());
792 }
793
clearScreen(FixupType type,byte count)794 void AndroidGraphicsManager::clearScreen(FixupType type, byte count) {
795 assert(count > 0);
796
797 bool sm = _show_mouse;
798 _show_mouse = false;
799
800 GLCALL(glDisable(GL_SCISSOR_TEST));
801
802 for (byte i = 0; i < count; ++i) {
803 // clear screen
804 GLCALL(glClearColor(0, 0, 0, 1 << 16));
805 if (_opengl) {
806 GLCALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
807 } else {
808 GLCALL(glClear(GL_COLOR_BUFFER_BIT));
809 }
810
811 switch (type) {
812 case kClear:
813 break;
814
815 case kClearSwap:
816 JNI::swapBuffers();
817 break;
818
819 case kClearUpdate:
820 _force_redraw = true;
821 updateScreen();
822 break;
823 }
824 }
825
826 if (!_show_overlay)
827 GLCALL(glEnable(GL_SCISSOR_TEST));
828
829 _show_mouse = sm;
830 _force_redraw = true;
831 }
832
833 #ifdef USE_RGB_COLOR
initTexture(GLESBaseTexture ** texture,uint width,uint height,const Graphics::PixelFormat * format)834 void AndroidGraphicsManager::initTexture(GLESBaseTexture **texture,
835 uint width, uint height,
836 const Graphics::PixelFormat *format) {
837 assert(texture);
838 Graphics::PixelFormat format_clut8 =
839 Graphics::PixelFormat::createFormatCLUT8();
840 Graphics::PixelFormat format_current;
841 Graphics::PixelFormat format_new;
842
843 if (*texture)
844 format_current = (*texture)->getPixelFormat();
845 else
846 format_current = Graphics::PixelFormat();
847
848 if (format)
849 format_new = *format;
850 else
851 format_new = format_clut8;
852
853 if (format_current != format_new) {
854 if (*texture)
855 LOGD("switching pixel format from: %s",
856 (*texture)->getPixelFormat().toString().c_str());
857
858 delete *texture;
859
860 if (format_new == GLES565Texture::pixelFormat())
861 *texture = new GLES565Texture();
862 else if (format_new == GLES5551Texture::pixelFormat())
863 *texture = new GLES5551Texture();
864 else if (format_new == GLES4444Texture::pixelFormat())
865 *texture = new GLES4444Texture();
866 else {
867 // TODO what now?
868 if (format_new != format_clut8)
869 LOGE("unsupported pixel format: %s",
870 format_new.toString().c_str());
871
872 *texture = new GLESFakePalette565Texture;
873 }
874
875 LOGD("new pixel format: %s",
876 (*texture)->getPixelFormat().toString().c_str());
877 }
878
879 (*texture)->allocBuffer(width, height);
880 }
881 #endif
882
883 #endif
884