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