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

backends/platform/android/texture.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 "base/main.h"
00043 #include "graphics/surface.h"
00044 #include "graphics/opengl/shader.h"
00045 #include "graphics/opengl/context.h"
00046 
00047 #include "common/rect.h"
00048 #include "common/array.h"
00049 #include "common/util.h"
00050 
00051 #include "backends/platform/android/texture.h"
00052 #include "backends/platform/android/android.h"
00053 #include "backends/platform/android/jni.h"
00054 
00055 // Supported GL extensions
00056 static bool npot_supported = false;
00057 
00058 OpenGL::Shader * g_box_shader;
00059 GLuint g_verticesVBO;
00060 
00061 static inline GLfixed xdiv(int numerator, int denominator) {
00062     assert(numerator < (1 << 16));
00063     return (numerator << 16) / denominator;
00064 }
00065 
00066 template<class T>
00067 static T nextHigher2(T k) {
00068     if (k == 0)
00069         return 1;
00070     --k;
00071 
00072     for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)
00073         k = k | k >> i;
00074 
00075     return k + 1;
00076 }
00077 
00078 const GLfloat vertices[] = {
00079     0.0, 0.0,
00080     1.0, 0.0,
00081     0.0, 1.0,
00082     1.0, 1.0,
00083 };
00084 
00085 void GLESBaseTexture::initGL() {
00086     npot_supported = OpenGLContext.NPOTSupported;
00087 
00088     const char* attributes[] = { "position", "texcoord", NULL };
00089     g_box_shader = OpenGL::Shader::fromStrings("control", OpenGL::BuiltinShaders::controlVertex, OpenGL::BuiltinShaders::controlFragment, attributes);
00090     g_verticesVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
00091     g_box_shader->enableVertexAttribute("position", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
00092     g_box_shader->enableVertexAttribute("texcoord", g_verticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
00093 }
00094 
00095 GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
00096                                     Graphics::PixelFormat pixelFormat) :
00097     _glFormat(glFormat),
00098     _glType(glType),
00099     _glFilter(GL_NEAREST),
00100     _texture_name(0),
00101     _surface(),
00102     _texture_width(0),
00103     _texture_height(0),
00104     _draw_rect(),
00105     _all_dirty(false),
00106     _dirty_rect(),
00107     _pixelFormat(pixelFormat),
00108     _palettePixelFormat(),
00109     _is_game_texture(false)
00110 {
00111     GLCALL(glGenTextures(1, &_texture_name));
00112 }
00113 
00114 GLESBaseTexture::~GLESBaseTexture() {
00115     release();
00116 }
00117 
00118 void GLESBaseTexture::release() {
00119     if (_texture_name) {
00120         GLCALL(glDeleteTextures(1, &_texture_name));
00121         _texture_name = 0;
00122     }
00123 }
00124 
00125 void GLESBaseTexture::reinit() {
00126     GLCALL(glGenTextures(1, &_texture_name));
00127 
00128     initSize();
00129 
00130     setDirty();
00131 }
00132 
00133 void GLESBaseTexture::initSize() {
00134     // Allocate room for the texture now, but pixel data gets uploaded
00135     // later (perhaps with multiple TexSubImage2D operations).
00136     GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
00137     GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
00138     GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
00139     GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
00140     GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
00141     GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
00142     GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glFormat,
00143                         _texture_width, _texture_height,
00144                         0, _glFormat, _glType, 0));
00145 }
00146 
00147 void GLESBaseTexture::setLinearFilter(bool value) {
00148     if (value)
00149         _glFilter = GL_LINEAR;
00150     else
00151         _glFilter = GL_NEAREST;
00152 
00153     GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
00154 
00155     GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
00156     GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
00157 }
00158 
00159 void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
00160     _surface.w = w;
00161     _surface.h = h;
00162     _surface.format = _pixelFormat;
00163 
00164     if (w == _texture_width && h == _texture_height)
00165         return;
00166 
00167     if (npot_supported) {
00168         _texture_width = _surface.w;
00169         _texture_height = _surface.h;
00170     } else {
00171         _texture_width = nextHigher2(_surface.w);
00172         _texture_height = nextHigher2(_surface.h);
00173     }
00174 
00175     initSize();
00176 }
00177 
00178 void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
00179 //  LOGD("*** Texture %p: Drawing %dx%d rect to (%d,%d)", this, w, h, x, y);
00180 
00181     assert(g_box_shader);
00182     g_box_shader->use();
00183 
00184     GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
00185     const GLfloat offsetX    = float(x) / float(JNI::egl_surface_width);
00186     const GLfloat offsetY    = float(y) / float(JNI::egl_surface_height);
00187     const GLfloat sizeW      = float(w) / float(JNI::egl_surface_width);
00188     const GLfloat sizeH      = float(h) / float(JNI::egl_surface_height);
00189     Math::Vector4d clipV = Math::Vector4d(clip.left, clip.top, clip.right, clip.bottom);
00190     clipV.x() /= _texture_width; clipV.y() /= _texture_height;
00191     clipV.z() /= _texture_width; clipV.w() /= _texture_height;
00192 //  LOGD("*** Drawing at (%f,%f) , size %f x %f", float(x) / float(_surface.w), float(y) / float(_surface.h),  tex_width, tex_height);
00193 
00194     g_box_shader->setUniform("offsetXY", Math::Vector2d(offsetX, offsetY));
00195     g_box_shader->setUniform("sizeWH", Math::Vector2d(sizeW, sizeH));
00196     g_box_shader->setUniform("clip", clipV);
00197     g_box_shader->setUniform("flipY", !_is_game_texture);
00198 
00199     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
00200 
00201     clearDirty();
00202 }
00203 
00204 const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const {
00205     return _pixelFormat;
00206 }
00207 
00208 GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
00209                             Graphics::PixelFormat pixelFormat) :
00210     GLESBaseTexture(glFormat, glType, pixelFormat),
00211     _pixels(0),
00212     _buf(0) {
00213 }
00214 
00215 GLESTexture::~GLESTexture() {
00216     delete[] _buf;
00217     delete[] _pixels;
00218 }
00219 
00220 void GLESTexture::allocBuffer(GLuint w, GLuint h) {
00221     GLuint oldw = _surface.w;
00222     GLuint oldh = _surface.h;
00223 
00224     GLESBaseTexture::allocBuffer(w, h);
00225 
00226     _surface.pitch = w * _pixelFormat.bytesPerPixel;
00227 
00228     if (_surface.w == oldw && _surface.h == oldh) {
00229         fillBuffer(0);
00230         return;
00231     }
00232 
00233     delete[] _buf;
00234     delete[] _pixels;
00235 
00236     _pixels = new byte[w * h * _surface.format.bytesPerPixel];
00237     assert(_pixels);
00238 
00239     _surface.setPixels(_pixels);
00240 
00241     fillBuffer(0);
00242 
00243     _buf = new byte[w * h * _surface.format.bytesPerPixel];
00244     assert(_buf);
00245 }
00246 
00247 void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
00248                                 const void *buf, int pitch_buf) {
00249     setDirtyRect(Common::Rect(x, y, x + w, y + h));
00250 
00251     const byte *src = (const byte *)buf;
00252     byte *dst = _pixels + y * _surface.pitch + x * _surface.format.bytesPerPixel;
00253 
00254     do {
00255         memcpy(dst, src, w * _surface.format.bytesPerPixel);
00256         dst += _surface.pitch;
00257         src += pitch_buf;
00258     } while (--h);
00259 }
00260 
00261 void GLESTexture::fillBuffer(uint32 color) {
00262     assert(_surface.getPixels());
00263 
00264     if (_pixelFormat.bytesPerPixel == 1 ||
00265             ((color & 0xff) == ((color >> 8) & 0xff)))
00266         memset(_pixels, color & 0xff, _surface.pitch * _surface.h);
00267     else
00268         Common::fill(_pixels, _pixels + _surface.pitch * _surface.h,
00269                         (uint16)color);
00270 
00271     setDirty();
00272 }
00273 
00274 void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
00275     if (_all_dirty) {
00276         _dirty_rect.top = 0;
00277         _dirty_rect.left = 0;
00278         _dirty_rect.bottom = _surface.h;
00279         _dirty_rect.right = _surface.w;
00280 
00281         _all_dirty = false;
00282     }
00283 
00284     if (!_dirty_rect.isEmpty()) {
00285         byte *_tex;
00286 
00287         int16 dwidth = _dirty_rect.width();
00288         int16 dheight = _dirty_rect.height();
00289 
00290         if (dwidth == _surface.w) {
00291             _tex = _pixels + _dirty_rect.top * _surface.pitch;
00292         } else {
00293             _tex = _buf;
00294 
00295             byte *src = _pixels + _dirty_rect.top * _surface.pitch +
00296                         _dirty_rect.left * _surface.format.bytesPerPixel;
00297             byte *dst = _buf;
00298 
00299             uint16 l = dwidth * _surface.format.bytesPerPixel;
00300 
00301             for (uint16 i = 0; i < dheight; ++i) {
00302                 memcpy(dst, src, l);
00303                 src += _surface.pitch;
00304                 dst += l;
00305             }
00306         }
00307 
00308         GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
00309         GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
00310 
00311         GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
00312                                 _dirty_rect.left, _dirty_rect.top,
00313                                 dwidth, dheight, _glFormat, _glType, _tex));
00314     }
00315 
00316     GLESBaseTexture::drawTexture(x, y, w, h, clip);
00317 }
00318 
00319 GLES4444Texture::GLES4444Texture() :
00320     GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) {
00321 }
00322 
00323 GLES4444Texture::~GLES4444Texture() {
00324 }
00325 
00326 GLES8888Texture::GLES8888Texture() :
00327     GLESTexture(GL_RGBA, GL_UNSIGNED_BYTE, pixelFormat()) {
00328 }
00329 
00330 GLES8888Texture::~GLES8888Texture() {
00331 }
00332 
00333 GLES5551Texture::GLES5551Texture() :
00334     GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixelFormat()) {
00335 }
00336 
00337 GLES5551Texture::~GLES5551Texture() {
00338 }
00339 
00340 GLES565Texture::GLES565Texture() :
00341     GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixelFormat()) {
00342 }
00343 
00344 GLES565Texture::~GLES565Texture() {
00345 }
00346 
00347 GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
00348                                     Graphics::PixelFormat pixelFormat) :
00349     GLESBaseTexture(glFormat, glType, pixelFormat),
00350     _palette(0),
00351     _pixels(0),
00352     _buf(0)
00353 {
00354     _palettePixelFormat = pixelFormat;
00355     _fake_format = Graphics::PixelFormat::createFormatCLUT8();
00356 
00357     _palette = new uint16[256];
00358     assert(_palette);
00359 
00360     memset(_palette, 0, 256 * 2);
00361 }
00362 
00363 GLESFakePaletteTexture::~GLESFakePaletteTexture() {
00364     delete[] _buf;
00365     delete[] _pixels;
00366     delete[] _palette;
00367 }
00368 
00369 void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
00370     GLuint oldw = _surface.w;
00371     GLuint oldh = _surface.h;
00372 
00373     GLESBaseTexture::allocBuffer(w, h);
00374 
00375     _surface.format = Graphics::PixelFormat::createFormatCLUT8();
00376     _surface.pitch = w;
00377 
00378     if (_surface.w == oldw && _surface.h == oldh) {
00379         fillBuffer(0);
00380         return;
00381     }
00382 
00383     delete[] _buf;
00384     delete[] _pixels;
00385 
00386     _pixels = new byte[w * h];
00387     assert(_pixels);
00388 
00389     // fixup surface, for the outside this is a CLUT8 surface
00390     _surface.setPixels(_pixels);
00391 
00392     fillBuffer(0);
00393 
00394     _buf = new uint16[w * h];
00395     assert(_buf);
00396 }
00397 
00398 void GLESFakePaletteTexture::fillBuffer(uint32 color) {
00399     assert(_surface.getPixels());
00400     memset(_surface.getPixels(), color & 0xff, _surface.pitch * _surface.h);
00401     setDirty();
00402 }
00403 
00404 void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w,
00405                                             GLuint h, const void *buf,
00406                                             int pitch_buf) {
00407     setDirtyRect(Common::Rect(x, y, x + w, y + h));
00408 
00409     const byte *src = (const byte *)buf;
00410     byte *dst = _pixels + y * _surface.pitch + x;
00411 
00412     do {
00413         memcpy(dst, src, w);
00414         dst += _surface.pitch;
00415         src += pitch_buf;
00416     } while (--h);
00417 }
00418 
00419 void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h, const Common::Rect &clip) {
00420     if (_all_dirty) {
00421         _dirty_rect.top = 0;
00422         _dirty_rect.left = 0;
00423         _dirty_rect.bottom = _surface.h;
00424         _dirty_rect.right = _surface.w;
00425 
00426         _all_dirty = false;
00427     }
00428 
00429     if (!_dirty_rect.isEmpty()) {
00430         int16 dwidth = _dirty_rect.width();
00431         int16 dheight = _dirty_rect.height();
00432 
00433         byte *src = _pixels + _dirty_rect.top * _surface.pitch +
00434                     _dirty_rect.left;
00435         uint16 *dst = _buf;
00436         uint pitch_delta = _surface.pitch - dwidth;
00437 
00438         for (uint16 j = 0; j < dheight; ++j) {
00439             for (uint16 i = 0; i < dwidth; ++i)
00440                 *dst++ = _palette[*src++];
00441             src += pitch_delta;
00442         }
00443 
00444         GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
00445 
00446         GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
00447                                 _dirty_rect.left, _dirty_rect.top,
00448                                 dwidth, dheight, _glFormat, _glType, _buf));
00449     }
00450 
00451     GLESBaseTexture::drawTexture(x, y, w, h, clip);
00452 }
00453 
00454 const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const {
00455     return _fake_format;
00456 }
00457 
00458 GLESFakePalette565Texture::GLESFakePalette565Texture() :
00459     GLESFakePaletteTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
00460                             GLES565Texture::pixelFormat()) {
00461 }
00462 
00463 GLESFakePalette565Texture::~GLESFakePalette565Texture() {
00464 }
00465 
00466 GLESFakePalette5551Texture::GLESFakePalette5551Texture() :
00467     GLESFakePaletteTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
00468                             GLES5551Texture::pixelFormat()) {
00469 }
00470 
00471 GLESFakePalette5551Texture::~GLESFakePalette5551Texture() {
00472 }
00473 
00474 #endif


Generated on Sat Mar 16 2019 05:01:56 for ResidualVM by doxygen 1.7.1
curved edge   curved edge