GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/safeopenglimagehelper.cpp Lines: 0 172 0.0 %
Date: 2017-11-29 Branches: 0 127 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "resources/safeopenglimagehelper.h"
24
25
#if defined(USE_OPENGL) && !defined(ANDROID)
26
27
#include "graphicsmanager.h"
28
29
#include "render/mobileopengl2graphics.h"
30
#include "render/mobileopenglgraphics.h"
31
#include "render/modernopenglgraphics.h"
32
#include "render/normalopenglgraphics.h"
33
#include "render/safeopenglgraphics.h"
34
35
#include "render/opengl/mgl.h"
36
#include "render/opengl/mglcheck.h"
37
38
#include "resources/dye/dye.h"
39
#include "resources/dye/dyepalette.h"
40
41
#include "resources/image/image.h"
42
43
#include "utils/sdlcheckutils.h"
44
45
#include "debug.h"
46
47
#ifndef SDL_BIG_ENDIAN
48
#error missing SDL_endian.h
49
#endif  // SDL_BYTEORDER
50
51
int SafeOpenGLImageHelper::mTextureType = 0;
52
int SafeOpenGLImageHelper::mInternalTextureType = GL_RGBA8;
53
int SafeOpenGLImageHelper::mTextureSize = 0;
54
bool SafeOpenGLImageHelper::mBlur = true;
55
bool SafeOpenGLImageHelper::mUseTextureSampler = false;
56
57
SafeOpenGLImageHelper::~SafeOpenGLImageHelper()
58
{
59
    glDeleteTextures(static_cast<GLsizei>(texturesSize - mFreeTextureIndex),
60
        &mTextures[mFreeTextureIndex]);
61
}
62
63
Image *SafeOpenGLImageHelper::load(SDL_RWops *const rw,
64
                                   Dye const &dye)
65
{
66
    SDL_Surface *const tmpImage = loadPng(rw);
67
    if (tmpImage == nullptr)
68
    {
69
        logger->log("Error, image load failed: %s", SDL_GetError());
70
        return nullptr;
71
    }
72
73
    SDL_Surface *const surf = convertTo32Bit(tmpImage);
74
    MSDL_FreeSurface(tmpImage);
75
    if (surf == nullptr)
76
        return nullptr;
77
78
    uint32_t *pixels = static_cast<uint32_t *>(surf->pixels);
79
    const int type = dye.getType();
80
81
    switch (type)
82
    {
83
        case 1:
84
        {
85
            const DyePalette *const pal = dye.getSPalete();
86
            if (pal != nullptr)
87
                DYEPALETTEP(pal, SOGLColor)(pixels, surf->w * surf->h);
88
            break;
89
        }
90
        case 2:
91
        {
92
            const DyePalette *const pal = dye.getAPalete();
93
            if (pal != nullptr)
94
                DYEPALETTEP(pal, AOGLColor)(pixels, surf->w * surf->h);
95
            break;
96
        }
97
        case 0:
98
        default:
99
        {
100
            dye.normalOGLDye(pixels, surf->w * surf->h);
101
            break;
102
        }
103
    }
104
105
    Image *const image = loadSurface(surf);
106
    MSDL_FreeSurface(surf);
107
    return image;
108
}
109
110
Image *SafeOpenGLImageHelper::loadSurface(SDL_Surface *const tmpImage)
111
{
112
    return glLoad(tmpImage);
113
}
114
115
Image *SafeOpenGLImageHelper::createTextSurface(SDL_Surface *const tmpImage,
116
                                                const int width,
117
                                                const int height,
118
                                                const float alpha)
119
{
120
    if (tmpImage == nullptr)
121
        return nullptr;
122
123
    Image *const img = glLoad(tmpImage, width, height);
124
    if (img != nullptr)
125
        img->setAlpha(alpha);
126
    return img;
127
}
128
129
int SafeOpenGLImageHelper::powerOfTwo(const int input)
130
{
131
    int value = 1;
132
    while (value < input && value < mTextureSize)
133
        value <<= 1;
134
    return value >= mTextureSize ? mTextureSize : value;
135
}
136
137
SDL_Surface *SafeOpenGLImageHelper::convertSurfaceNormalize(SDL_Surface
138
                                                            *tmpImage,
139
                                                            int width,
140
                                                            int height)
141
{
142
    if (tmpImage == nullptr)
143
        return nullptr;
144
145
    int realWidth = powerOfTwo(width);
146
    int realHeight = powerOfTwo(height);
147
148
    if (realWidth < width || realHeight < height)
149
    {
150
        logger->log("Warning: image too large, cropping to %dx%d texture!",
151
                    tmpImage->w, tmpImage->h);
152
    }
153
154
#ifdef USE_SDL2
155
    SDL_SetSurfaceAlphaMod(tmpImage, SDL_ALPHA_OPAQUE);
156
#else  // USE_SDL2
157
158
    // Make sure the alpha channel is not used, but copied to destination
159
    SDL_SetAlpha(tmpImage, 0, SDL_ALPHA_OPAQUE);
160
#endif  // USE_SDL2
161
162
    // Determine 32-bit masks based on byte order
163
    uint32_t rmask, gmask, bmask, amask;
164
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
165
    rmask = 0xff000000;
166
    gmask = 0x00ff0000;
167
    bmask = 0x0000ff00;
168
    amask = 0x000000ff;
169
#else  // SDL_BYTEORDER == SDL_BIG_ENDIAN
170
171
    rmask = 0x000000ff;
172
    gmask = 0x0000ff00;
173
    bmask = 0x00ff0000;
174
    amask = 0xff000000;
175
#endif  // SDL_BYTEORDER == SDL_BIG_ENDIAN
176
177
    if (tmpImage->format->BitsPerPixel != 32
178
        || realWidth != width || realHeight != height
179
        || rmask != tmpImage->format->Rmask
180
        || gmask != tmpImage->format->Gmask
181
        || amask != tmpImage->format->Amask)
182
    {
183
        SDL_Surface *oldImage = tmpImage;
184
#ifdef USE_SDL2
185
        SDL_SetSurfaceBlendMode(oldImage, SDL_BLENDMODE_NONE);
186
#endif  // USE_SDL2
187
188
        tmpImage = MSDL_CreateRGBSurface(SDL_SWSURFACE, realWidth, realHeight,
189
            32, rmask, gmask, bmask, amask);
190
191
        if (tmpImage == nullptr)
192
        {
193
            logger->log("Error, image convert failed: out of memory");
194
            return nullptr;
195
        }
196
        SDL_BlitSurface(oldImage, nullptr, tmpImage, nullptr);
197
    }
198
    return tmpImage;
199
}
200
201
SDL_Surface *SafeOpenGLImageHelper::convertSurface(SDL_Surface *tmpImage,
202
                                                   int width,
203
                                                   int height)
204
{
205
    if (tmpImage == nullptr)
206
        return nullptr;
207
208
#ifdef USE_SDL2
209
    SDL_SetSurfaceAlphaMod(tmpImage, SDL_ALPHA_OPAQUE);
210
#else  // USE_SDL2
211
212
    // Make sure the alpha channel is not used, but copied to destination
213
    SDL_SetAlpha(tmpImage, 0, SDL_ALPHA_OPAQUE);
214
#endif  // USE_SDL2
215
216
    // Determine 32-bit masks based on byte order
217
    uint32_t rmask, gmask, bmask, amask;
218
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
219
    rmask = 0xff000000;
220
    gmask = 0x00ff0000;
221
    bmask = 0x0000ff00;
222
    amask = 0x000000ff;
223
#else  // SDL_BYTEORDER == SDL_BIG_ENDIAN
224
225
    rmask = 0x000000ff;
226
    gmask = 0x0000ff00;
227
    bmask = 0x00ff0000;
228
    amask = 0xff000000;
229
#endif  // SDL_BYTEORDER == SDL_BIG_ENDIAN
230
231
    if (tmpImage->format->BitsPerPixel != 32
232
        || rmask != tmpImage->format->Rmask
233
        || gmask != tmpImage->format->Gmask
234
        || amask != tmpImage->format->Amask)
235
    {
236
        SDL_Surface *oldImage = tmpImage;
237
#ifdef USE_SDL2
238
        SDL_SetSurfaceBlendMode(oldImage, SDL_BLENDMODE_NONE);
239
#endif  // USE_SDL2
240
241
        tmpImage = MSDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
242
            32, rmask, gmask, bmask, amask);
243
244
        if (tmpImage == nullptr)
245
        {
246
            logger->log("Error, image convert failed: out of memory");
247
            return nullptr;
248
        }
249
        SDL_BlitSurface(oldImage, nullptr, tmpImage, nullptr);
250
    }
251
    return tmpImage;
252
}
253
254
void SafeOpenGLImageHelper::bindTexture(const GLuint texture)
255
{
256
    switch (mUseOpenGL)
257
    {
258
#ifdef __native_client__
259
        case RENDER_NORMAL_OPENGL:
260
        case RENDER_MODERN_OPENGL:
261
        case RENDER_GLES_OPENGL:
262
            break;
263
        case RENDER_SAFE_OPENGL:
264
            SafeOpenGLGraphics::bindTexture(mTextureType, texture);
265
            break;
266
        case RENDER_GLES2_OPENGL:
267
            MobileOpenGL2Graphics::bindTexture(mTextureType, texture);
268
            break;
269
#elif defined(ANDROID)
270
        case RENDER_NORMAL_OPENGL:
271
        case RENDER_MODERN_OPENGL:
272
        case RENDER_SAFE_OPENGL:
273
        case RENDER_GLES2_OPENGL:
274
            break;
275
        case RENDER_GLES_OPENGL:
276
            MobileOpenGLGraphics::bindTexture(mTextureType, texture);
277
            break;
278
#else  // __native_client__
279
        case RENDER_NORMAL_OPENGL:
280
            NormalOpenGLGraphics::bindTexture(mTextureType, texture);
281
            break;
282
        case RENDER_MODERN_OPENGL:
283
            ModernOpenGLGraphics::bindTexture(mTextureType, texture);
284
            break;
285
        case RENDER_SAFE_OPENGL:
286
            SafeOpenGLGraphics::bindTexture(mTextureType, texture);
287
            break;
288
        case RENDER_GLES_OPENGL:
289
            MobileOpenGLGraphics::bindTexture(mTextureType, texture);
290
            break;
291
        case RENDER_GLES2_OPENGL:
292
            MobileOpenGL2Graphics::bindTexture(mTextureType, texture);
293
            break;
294
#endif  // __native_client__
295
        case RENDER_SOFTWARE:
296
        case RENDER_SDL2_DEFAULT:
297
        case RENDER_NULL:
298
        case RENDER_LAST:
299
        default:
300
            logger->log("Unknown OpenGL backend: %d", mUseOpenGL);
301
            break;
302
    }
303
}
304
305
Image *SafeOpenGLImageHelper::glLoad(SDL_Surface *tmpImage,
306
                                     int width,
307
                                     int height)
308
{
309
    if (tmpImage == nullptr)
310
        return nullptr;
311
312
    BLOCK_START("SafeOpenGLImageHelper::glLoad")
313
    // Flush current error flag.
314
    graphicsManager.getLastError();
315
316
    if (width == 0)
317
        width = tmpImage->w;
318
    if (height == 0)
319
        height = tmpImage->h;
320
321
    SDL_Surface *oldImage = tmpImage;
322
    tmpImage = convertSurfaceNormalize(tmpImage, width, height);
323
    if (tmpImage == nullptr)
324
        return nullptr;
325
326
    const int realWidth = tmpImage->w;
327
    const int realHeight = tmpImage->h;
328
329
    const GLuint texture = getNewTexture();
330
    bindTexture(texture);
331
332
    if (SDL_MUSTLOCK(tmpImage))
333
        SDL_LockSurface(tmpImage);
334
335
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
336
337
    if (!mUseTextureSampler)
338
    {
339
        if (mBlur)
340
        {
341
            glTexParameteri(mTextureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
342
            glTexParameteri(mTextureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
343
        }
344
        else
345
        {
346
            glTexParameteri(mTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
347
            glTexParameteri(mTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
348
        }
349
    }
350
#ifndef ANDROID
351
    glTexParameteri(mTextureType, GL_TEXTURE_MAX_LEVEL, 0);
352
#endif  // ANDROID
353
354
    glTexImage2D(mTextureType, 0, mInternalTextureType,
355
        tmpImage->w, tmpImage->h,
356
        0, GL_RGBA, GL_UNSIGNED_BYTE, tmpImage->pixels);
357
358
#ifdef DEBUG_OPENGL
359
/*
360
    disabled for now, because debugger can't show it
361
    if (isGLNotNull(mglLabelObject))
362
    {
363
        const char *const text = "image text";
364
        mglLabelObject(GL_TEXTURE, texture, strlen(text), text);
365
    }
366
*/
367
#endif  // DEBUG_OPENGL
368
369
/*
370
    GLint compressed;
371
    glGetTexLevelParameteriv(mTextureType, 0,
372
        GL_TEXTURE_COMPRESSED_ARB, &compressed);
373
    if (compressed)
374
        logger->log("image compressed");
375
    else
376
        logger->log("image not compressed");
377
*/
378
379
#ifdef DEBUG_OPENGL_LEAKS
380
    textures_count ++;
381
#endif  // DEBUG_OPENGL_LEAKS
382
383
    if (SDL_MUSTLOCK(tmpImage))
384
        SDL_UnlockSurface(tmpImage);
385
386
    if (oldImage != tmpImage)
387
        MSDL_FreeSurface(tmpImage);
388
389
    GLenum error = graphicsManager.getLastError();
390
    if (error != 0u)
391
    {
392
        std::string errmsg = GraphicsManager::errorToString(error);
393
        logger->log("Error: Image GL import failed: %s (%u)",
394
            errmsg.c_str(), error);
395
//        return nullptr;
396
    }
397
398
    BLOCK_END("SafeOpenGLImageHelper::glLoad")
399
    return new Image(texture, width, height, realWidth, realHeight);
400
}
401
402
void SafeOpenGLImageHelper::initTextureSampler(const GLint id)
403
{
404
    if (mBlur)
405
    {
406
        mglSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
407
        mglSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
408
    }
409
    else
410
    {
411
        mglSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
412
        mglSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
413
    }
414
}
415
416
SDL_Surface *SafeOpenGLImageHelper::create32BitSurface(int width,
417
                                                       int height) const
418
{
419
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
420
    const int rmask = 0xff000000;
421
    const int gmask = 0x00ff0000;
422
    const int bmask = 0x0000ff00;
423
    const int amask = 0x000000ff;
424
#else  // SDL_BYTEORDER == SDL_BIG_ENDIAN
425
426
    const int rmask = 0x000000ff;
427
    const int gmask = 0x0000ff00;
428
    const int bmask = 0x00ff0000;
429
    const int amask = 0xff000000;
430
#endif  // SDL_BYTEORDER == SDL_BIG_ENDIAN
431
432
    width = powerOfTwo(width);
433
    height = powerOfTwo(height);
434
435
    return MSDL_CreateRGBSurface(SDL_SWSURFACE,
436
        width, height, 32, rmask, gmask, bmask, amask);
437
}
438
439
GLuint SafeOpenGLImageHelper::getNewTexture()
440
{
441
    GLuint texture = mTextures[mFreeTextureIndex];
442
    mFreeTextureIndex ++;
443
    if (mFreeTextureIndex == texturesSize)
444
    {
445
        mFreeTextureIndex = 0;
446
        postInit();
447
    }
448
    return texture;
449
}
450
451
void SafeOpenGLImageHelper::postInit()
452
{
453
    glGenTextures(texturesSize, &mTextures[mFreeTextureIndex]);
454
}
455
456
void SafeOpenGLImageHelper::invalidate(const GLuint textureId)
457
{
458
    if (isGLNotNull(mglInvalidateTexImage))
459
    {
460
        logger->log("invalidate: %u", textureId);
461
        mglInvalidateTexImage(textureId, 0);
462
    }
463
}
464
465
void SafeOpenGLImageHelper::copySurfaceToImage(const Image *const image,
466
                                               const int x,
467
                                               const int y,
468
                                               SDL_Surface *surface) const
469
{
470
    if (surface == nullptr || image == nullptr)
471
        return;
472
473
    SDL_Surface *const oldSurface = surface;
474
    surface = convertSurface(surface, surface->w, surface->h);
475
    if (surface == nullptr)
476
        return;
477
478
    // +++ probably need combine
479
    // mglTextureSubImage2D and mglTextureSubImage2DEXT
480
    if (mglTextureSubImage2D != nullptr)
481
    {
482
        mglTextureSubImage2D(image->mGLImage,
483
            0,
484
            x, y,
485
            surface->w, surface->h,
486
            GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
487
    }
488
    else
489
    {
490
        mglTextureSubImage2DEXT(image->mGLImage,
491
            mTextureType, 0,
492
            x, y,
493
            surface->w, surface->h,
494
            GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
495
    }
496
497
    if (surface != oldSurface)
498
        MSDL_FreeSurface(surface);
499
}
500
501
#endif  // defined(USE_OPENGL) && !defined(ANDROID)