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