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 "base/main.h"
43 #include "graphics/surface.h"
44 #include "graphics/opengl/shader.h"
45 #include "graphics/opengl/context.h"
46 
47 #include "common/rect.h"
48 #include "common/array.h"
49 #include "common/util.h"
50 
51 #include "backends/platform/android3d/texture.h"
52 #include "backends/platform/android3d/android.h"
53 #include "backends/platform/android3d/jni-android.h"
54 
55 // Supported GL extensions
56 static bool npot_supported = false;
57 
58 OpenGL::ShaderGL * g_box_shader;
59 GLuint g_verticesVBO;
60 
61 template<class T>
nextHigher2(T k)62 static T nextHigher2(T k) {
63 	if (k == 0)
64 		return 1;
65 	--k;
66 
67 	for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)
68 		k = k | k >> i;
69 
70 	return k + 1;
71 }
72 
73 const GLfloat vertices[] = {
74 	0.0, 0.0,
75 	1.0, 0.0,
76 	0.0, 1.0,
77 	1.0, 1.0,
78 };
79 
initGL()80 void GLESBaseTexture::initGL() {
81 	npot_supported = OpenGLContext.NPOTSupported;
82 
83 	const char* attributes[] = { "position", "texcoord", NULL };
84 	g_box_shader = OpenGL::ShaderGL::fromStrings("control", OpenGL::BuiltinShaders::controlVertex, OpenGL::BuiltinShaders::controlFragment, attributes);
85 	g_verticesVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
86 	g_box_shader->enableVertexAttribute("position", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
87 	g_box_shader->enableVertexAttribute("texcoord", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
88 }
89 
GLESBaseTexture(GLenum glFormat,GLenum glType,Graphics::PixelFormat pixelFormat)90 GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
91 									Graphics::PixelFormat pixelFormat) :
92 	_glFormat(glFormat),
93 	_glType(glType),
94 	_glFilter(GL_NEAREST),
95 	_texture_name(0),
96 	_surface(),
97 	_texture_width(0),
98 	_texture_height(0),
99 	_draw_rect(),
100 	_all_dirty(false),
101 	_dirty_rect(),
102 	_pixelFormat(pixelFormat),
103 	_palettePixelFormat(),
104 	_is_game_texture(false)
105 {
106 	GLCALL(glGenTextures(1, &_texture_name));
107 }
108 
~GLESBaseTexture()109 GLESBaseTexture::~GLESBaseTexture() {
110 	release();
111 }
112 
release()113 void GLESBaseTexture::release() {
114 	if (_texture_name) {
115 		GLCALL(glDeleteTextures(1, &_texture_name));
116 		_texture_name = 0;
117 	}
118 }
119 
reinit()120 void GLESBaseTexture::reinit() {
121 	GLCALL(glGenTextures(1, &_texture_name));
122 
123 	initSize();
124 
125 	setDirty();
126 }
127 
initSize()128 void GLESBaseTexture::initSize() {
129 	// Allocate room for the texture now, but pixel data gets uploaded
130 	// later (perhaps with multiple TexSubImage2D operations).
131 	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
132 	GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
133 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
134 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
135 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
136 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
137 	GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glFormat,
138 						_texture_width, _texture_height,
139 						0, _glFormat, _glType, 0));
140 }
141 
setLinearFilter(bool value)142 void GLESBaseTexture::setLinearFilter(bool value) {
143 	if (value)
144 		_glFilter = GL_LINEAR;
145 	else
146 		_glFilter = GL_NEAREST;
147 
148 	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
149 
150 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
151 	GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
152 }
153 
allocBuffer(GLuint w,GLuint h)154 void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
155 	_surface.w = w;
156 	_surface.h = h;
157 	_surface.format = _pixelFormat;
158 
159 	if (w == _texture_width && h == _texture_height)
160 		return;
161 
162 	if (npot_supported) {
163 		_texture_width = _surface.w;
164 		_texture_height = _surface.h;
165 	} else {
166 		_texture_width = nextHigher2(_surface.w);
167 		_texture_height = nextHigher2(_surface.h);
168 	}
169 
170 	initSize();
171 }
172 
drawTexture(GLshort x,GLshort y,GLshort w,GLshort h,const Common::Rect & clip)173 void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
174 //	LOGD("*** Texture %p: Drawing %dx%d rect to (%d,%d)", this, w, h, x, y);
175 
176 	assert(g_box_shader);
177 	g_box_shader->use();
178 
179 	GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
180 	const GLfloat offsetX    = float(x) / float(JNI::egl_surface_width);
181 	const GLfloat offsetY    = float(y) / float(JNI::egl_surface_height);
182 	const GLfloat sizeW      = float(w) / float(JNI::egl_surface_width);
183 	const GLfloat sizeH      = float(h) / float(JNI::egl_surface_height);
184 	Math::Vector4d clipV = Math::Vector4d(clip.left, clip.top, clip.right, clip.bottom);
185 	clipV.x() /= _texture_width; clipV.y() /= _texture_height;
186 	clipV.z() /= _texture_width; clipV.w() /= _texture_height;
187 //	LOGD("*** Drawing at (%f,%f) , size %f x %f", float(x) / float(_surface.w), float(y) / float(_surface.h),  tex_width, tex_height);
188 
189 	g_box_shader->setUniform("offsetXY", Math::Vector2d(offsetX, offsetY));
190 	g_box_shader->setUniform("sizeWH", Math::Vector2d(sizeW, sizeH));
191 	g_box_shader->setUniform("clip", clipV);
192 	g_box_shader->setUniform("flipY", !_is_game_texture);
193 
194 	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
195 
196 	clearDirty();
197 }
198 
getPixelFormat() const199 const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const {
200 	return _pixelFormat;
201 }
202 
GLESTexture(GLenum glFormat,GLenum glType,Graphics::PixelFormat pixelFormat)203 GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
204 							Graphics::PixelFormat pixelFormat) :
205 	GLESBaseTexture(glFormat, glType, pixelFormat),
206 	_pixels(0),
207 	_buf(0) {
208 }
209 
~GLESTexture()210 GLESTexture::~GLESTexture() {
211 	delete[] _buf;
212 	delete[] _pixels;
213 }
214 
allocBuffer(GLuint w,GLuint h)215 void GLESTexture::allocBuffer(GLuint w, GLuint h) {
216 	GLuint oldw = _surface.w;
217 	GLuint oldh = _surface.h;
218 
219 	GLESBaseTexture::allocBuffer(w, h);
220 
221 	_surface.pitch = w * _pixelFormat.bytesPerPixel;
222 
223 	if (_surface.w == oldw && _surface.h == oldh) {
224 		fillBuffer(0);
225 		return;
226 	}
227 
228 	delete[] _buf;
229 	delete[] _pixels;
230 
231 	_pixels = new byte[w * h * _surface.format.bytesPerPixel];
232 	assert(_pixels);
233 
234 	_surface.setPixels(_pixels);
235 
236 	fillBuffer(0);
237 
238 	_buf = new byte[w * h * _surface.format.bytesPerPixel];
239 	assert(_buf);
240 }
241 
updateBuffer(GLuint x,GLuint y,GLuint w,GLuint h,const void * buf,int pitch_buf)242 void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
243 								const void *buf, int pitch_buf) {
244 	setDirtyRect(Common::Rect(x, y, x + w, y + h));
245 
246 	const byte *src = (const byte *)buf;
247 	byte *dst = _pixels + y * _surface.pitch + x * _surface.format.bytesPerPixel;
248 
249 	do {
250 		memcpy(dst, src, w * _surface.format.bytesPerPixel);
251 		dst += _surface.pitch;
252 		src += pitch_buf;
253 	} while (--h);
254 }
255 
fillBuffer(uint32 color)256 void GLESTexture::fillBuffer(uint32 color) {
257 	assert(_surface.getPixels());
258 
259 	if (_pixelFormat.bytesPerPixel == 1 ||
260 			((color & 0xff) == ((color >> 8) & 0xff)))
261 		memset(_pixels, color & 0xff, _surface.pitch * _surface.h);
262 	else
263 		Common::fill(_pixels, _pixels + _surface.pitch * _surface.h,
264 						(uint16)color);
265 
266 	setDirty();
267 }
268 
drawTexture(GLshort x,GLshort y,GLshort w,GLshort h,const Common::Rect & clip)269 void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
270 	if (_all_dirty) {
271 		_dirty_rect.top = 0;
272 		_dirty_rect.left = 0;
273 		_dirty_rect.bottom = _surface.h;
274 		_dirty_rect.right = _surface.w;
275 
276 		_all_dirty = false;
277 	}
278 
279 	if (!_dirty_rect.isEmpty()) {
280 		byte *_tex;
281 
282 		int16 dwidth = _dirty_rect.width();
283 		int16 dheight = _dirty_rect.height();
284 
285 		if (dwidth == _surface.w) {
286 			_tex = _pixels + _dirty_rect.top * _surface.pitch;
287 		} else {
288 			_tex = _buf;
289 
290 			byte *src = _pixels + _dirty_rect.top * _surface.pitch +
291 						_dirty_rect.left * _surface.format.bytesPerPixel;
292 			byte *dst = _buf;
293 
294 			uint16 l = dwidth * _surface.format.bytesPerPixel;
295 
296 			for (uint16 i = 0; i < dheight; ++i) {
297 				memcpy(dst, src, l);
298 				src += _surface.pitch;
299 				dst += l;
300 			}
301 		}
302 
303 		GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
304 		GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
305 
306 		GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
307 								_dirty_rect.left, _dirty_rect.top,
308 								dwidth, dheight, _glFormat, _glType, _tex));
309 	}
310 
311 	GLESBaseTexture::drawTexture(x, y, w, h, clip);
312 }
313 
GLES4444Texture()314 GLES4444Texture::GLES4444Texture() :
315 	GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) {
316 }
317 
~GLES4444Texture()318 GLES4444Texture::~GLES4444Texture() {
319 }
320 
GLES8888Texture()321 GLES8888Texture::GLES8888Texture() :
322 	GLESTexture(GL_RGBA, GL_UNSIGNED_BYTE, pixelFormat()) {
323 }
324 
~GLES8888Texture()325 GLES8888Texture::~GLES8888Texture() {
326 }
327 
GLES5551Texture()328 GLES5551Texture::GLES5551Texture() :
329 	GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixelFormat()) {
330 }
331 
~GLES5551Texture()332 GLES5551Texture::~GLES5551Texture() {
333 }
334 
GLES565Texture()335 GLES565Texture::GLES565Texture() :
336 	GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixelFormat()) {
337 }
338 
~GLES565Texture()339 GLES565Texture::~GLES565Texture() {
340 }
341 
GLESFakePaletteTexture(GLenum glFormat,GLenum glType,Graphics::PixelFormat pixelFormat)342 GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
343 									Graphics::PixelFormat pixelFormat) :
344 	GLESBaseTexture(glFormat, glType, pixelFormat),
345 	_palette(0),
346 	_pixels(0),
347 	_buf(0)
348 {
349 	_palettePixelFormat = pixelFormat;
350 	_fake_format = Graphics::PixelFormat::createFormatCLUT8();
351 
352 	_palette = new uint16[256];
353 	assert(_palette);
354 
355 	memset(_palette, 0, 256 * 2);
356 }
357 
~GLESFakePaletteTexture()358 GLESFakePaletteTexture::~GLESFakePaletteTexture() {
359 	delete[] _buf;
360 	delete[] _pixels;
361 	delete[] _palette;
362 }
363 
allocBuffer(GLuint w,GLuint h)364 void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
365 	GLuint oldw = _surface.w;
366 	GLuint oldh = _surface.h;
367 
368 	GLESBaseTexture::allocBuffer(w, h);
369 
370 	_surface.format = Graphics::PixelFormat::createFormatCLUT8();
371 	_surface.pitch = w;
372 
373 	if (_surface.w == oldw && _surface.h == oldh) {
374 		fillBuffer(0);
375 		return;
376 	}
377 
378 	delete[] _buf;
379 	delete[] _pixels;
380 
381 	_pixels = new byte[w * h];
382 	assert(_pixels);
383 
384 	// fixup surface, for the outside this is a CLUT8 surface
385 	_surface.setPixels(_pixels);
386 
387 	fillBuffer(0);
388 
389 	_buf = new uint16[w * h];
390 	assert(_buf);
391 }
392 
fillBuffer(uint32 color)393 void GLESFakePaletteTexture::fillBuffer(uint32 color) {
394 	assert(_surface.getPixels());
395 	memset(_surface.getPixels(), color & 0xff, _surface.pitch * _surface.h);
396 	setDirty();
397 }
398 
updateBuffer(GLuint x,GLuint y,GLuint w,GLuint h,const void * buf,int pitch_buf)399 void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w,
400 											GLuint h, const void *buf,
401 											int pitch_buf) {
402 	setDirtyRect(Common::Rect(x, y, x + w, y + h));
403 
404 	const byte *src = (const byte *)buf;
405 	byte *dst = _pixels + y * _surface.pitch + x;
406 
407 	do {
408 		memcpy(dst, src, w);
409 		dst += _surface.pitch;
410 		src += pitch_buf;
411 	} while (--h);
412 }
413 
drawTexture(GLshort x,GLshort y,GLshort w,GLshort h,const Common::Rect & clip)414 void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
415 	if (_all_dirty) {
416 		_dirty_rect.top = 0;
417 		_dirty_rect.left = 0;
418 		_dirty_rect.bottom = _surface.h;
419 		_dirty_rect.right = _surface.w;
420 
421 		_all_dirty = false;
422 	}
423 
424 	if (!_dirty_rect.isEmpty()) {
425 		int16 dwidth = _dirty_rect.width();
426 		int16 dheight = _dirty_rect.height();
427 
428 		byte *src = _pixels + _dirty_rect.top * _surface.pitch +
429 					_dirty_rect.left;
430 		uint16 *dst = _buf;
431 		uint pitch_delta = _surface.pitch - dwidth;
432 
433 		for (uint16 j = 0; j < dheight; ++j) {
434 			for (uint16 i = 0; i < dwidth; ++i)
435 				*dst++ = _palette[*src++];
436 			src += pitch_delta;
437 		}
438 
439 		GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
440 
441 		GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
442 								_dirty_rect.left, _dirty_rect.top,
443 								dwidth, dheight, _glFormat, _glType, _buf));
444 	}
445 
446 	GLESBaseTexture::drawTexture(x, y, w, h, clip);
447 }
448 
getPixelFormat() const449 const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const {
450 	return _fake_format;
451 }
452 
GLESFakePalette565Texture()453 GLESFakePalette565Texture::GLESFakePalette565Texture() :
454 	GLESFakePaletteTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
455 							GLES565Texture::pixelFormat()) {
456 }
457 
~GLESFakePalette565Texture()458 GLESFakePalette565Texture::~GLESFakePalette565Texture() {
459 }
460 
GLESFakePalette5551Texture()461 GLESFakePalette5551Texture::GLESFakePalette5551Texture() :
462 	GLESFakePaletteTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
463 							GLES5551Texture::pixelFormat()) {
464 }
465 
~GLESFakePalette5551Texture()466 GLESFakePalette5551Texture::~GLESFakePalette5551Texture() {
467 }
468 
469 #endif
470