cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

texturemanager.mm (15769B)


      1/*
      2 * Gearboy - Nintendo Game Boy Emulator
      3 * Copyright (C) 2012  Ignacio Sanchez
      4 
      5 * This program is free software: you can redistribute it and/or modify
      6 * it under the terms of the GNU General Public License as published by
      7 * the Free Software Foundation, either version 3 of the License, or
      8 * any later version.
      9 
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13 * GNU General Public License for more details.
     14 
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program.  If not, see http://www.gnu.org/licenses/
     17 *
     18 */
     19
     20#include "texturemanager.h"
     21#import "../../../src/gearboy.h"
     22#include <OpenGLES/ES1/glext.h>
     23
     24//////////////////////////
     25//////////////////////////
     26
     27TextureManager::TextureManager()
     28{
     29}
     30
     31//////////////////////////
     32//////////////////////////
     33
     34TextureManager::~TextureManager()
     35{
     36    UnloadAll();
     37}
     38
     39//////////////////////////
     40//////////////////////////
     41
     42bool TextureManager::LoadTexture(Texture* pTexture, bool mipmaps)
     43{
     44    Log("+++ TextureManager::LoadTexture Loading texture: %s\n", pTexture->m_strName);
     45
     46    char* ind = strrchr(pTexture->m_strName, '/');
     47    char* szName = ind + 1;
     48    char szPath[256] = {0};
     49    strncpy(szPath, pTexture->m_strName, ind - pTexture->m_strName);
     50    szPath[ind - pTexture->m_strName] = 0;
     51
     52    NSString * OCname = [NSString stringWithCString : szName encoding : [NSString defaultCStringEncoding]];
     53    NSString * OCpath = [NSString stringWithCString : szPath encoding : [NSString defaultCStringEncoding]];
     54
     55    NSString * RSCpath = [[NSBundle mainBundle] pathForResource : OCname ofType : @"pvr" inDirectory : OCpath];
     56
     57    FILE* pFile = fopen([RSCpath cStringUsingEncoding : 1], "r");
     58
     59    if (pFile != NULL)
     60    {
     61        pTexture->m_bIsCompressed = true;
     62
     63        fseek(pFile, 0, SEEK_END);
     64        int len = (int)ftell(pFile);
     65        fseek(pFile, 0, SEEK_SET);
     66
     67        GLubyte* pBuffer = new GLubyte[len];
     68        fread(pBuffer, sizeof(GLubyte), len, pFile);
     69
     70        fclose(pFile);
     71
     72        int size = 0;
     73        GLenum internalformat = 0;
     74
     75        for (int i = 16; i <= 1024; i *= 2)
     76        {
     77            if (((i * i) / 2) == len)
     78            {
     79                size = i;
     80                internalformat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
     81                break;
     82            }
     83
     84            if (((i * i) / 4) == len)
     85            {
     86                size = i;
     87                internalformat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
     88                break;
     89            }
     90        }
     91
     92        if (size != 0)
     93        {
     94            pTexture->m_iWidth = size;
     95            pTexture->m_iHeight = size;
     96
     97            glGenTextures(1, &pTexture->m_theTexture);
     98            glBindTexture(GL_TEXTURE_2D, pTexture->m_theTexture);
     99            glCompressedTexImage2D(GL_TEXTURE_2D, 0, internalformat, size, size, 0, len, pBuffer);
    100        }
    101        else
    102        {
    103            Log("@@@ TextureManager::LoadTexture PVR incorrect size: %s.pvr\n", pTexture->m_strName);
    104            SafeDeleteArray(pBuffer);
    105            return false;
    106        }
    107        
    108        SafeDeleteArray(pBuffer);
    109
    110        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    111        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    112
    113        Log("+++ TextureManager::LoadTexture size %dx%d\n", pTexture->m_iWidth, pTexture->m_iHeight);
    114        Log("+++ TextureManager::LoadTexture PVR texture loaded: %s.pvr\n", pTexture->m_strName);
    115
    116        return true;
    117    }
    118    else
    119    {
    120        Log("@@@ TextureManager::LoadTexture Unable to load PVR: %s.pvr\n", pTexture->m_strName);
    121
    122        pTexture->m_bIsCompressed = false;
    123
    124        char szPathPNG[256] = {0};
    125		strcpy(szPathPNG, "/");
    126        strcat(szPathPNG, pTexture->m_strName);
    127        strcat(szPathPNG, ".png");
    128
    129        CGImageRef spriteImage;
    130        CGContextRef spriteContext;
    131        GLubyte *spriteData;
    132        int width, height;
    133		
    134		char pathSize[2048] = {0};
    135		
    136		
    137		NSString* path =[[NSBundle mainBundle]resourcePath];	
    138		
    139		[path getCString:pathSize maxLength:2048 encoding:NSUTF8StringEncoding];
    140		
    141		strcat(pathSize, szPathPNG);			
    142		
    143		// Creates a Core Graphics image from an image file
    144		spriteImage = [UIImage imageWithContentsOfFile : [NSString stringWithUTF8String:pathSize]].CGImage;	
    145       
    146
    147        if (spriteImage)
    148        {
    149            // Get the width and height of the image
    150            pTexture->m_iWidth = width = (int)CGImageGetWidth(spriteImage);
    151            pTexture->m_iHeight = height = (int)CGImageGetHeight(spriteImage);
    152            // Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
    153            // you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.
    154
    155            // Allocated memory needed for the bitmap context
    156            spriteData = (GLubyte *) calloc(width * height * 4, 1);
    157            // Uses the bitmatp creation function provided by the Core Graphics framework.
    158            spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
    159            // After you create the context, you can draw the sprite image to the context.
    160            CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat) width, (CGFloat) height), spriteImage);
    161            // You don't need the context at this point, so you need to release it to avoid memory leaks.
    162            CGContextRelease(spriteContext);
    163
    164            // Use OpenGL ES to generate a name for the texture.
    165            glGenTextures(1, &pTexture->m_theTexture);
    166            // Bind the texture name.
    167            glBindTexture(GL_TEXTURE_2D, pTexture->m_theTexture);
    168            // Speidfy a 2D texture image, provideing the a pointer to the image data in memory          
    169            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    170            // Release the image data
    171
    172            if (mipmaps)
    173            {
    174                Log("+++ TextureManager::LoadTexture generating mipmaps...\n");
    175
    176                GLubyte *prevImage = 0;
    177                GLubyte *newImage = 0;
    178
    179                int level = 1;
    180                prevImage = &spriteData[0];
    181
    182                while (width > 1 && height > 1)
    183                {
    184                    int newWidth, newHeight;
    185
    186                    // Generate the next mipmap level
    187                    GenMipMap2D(prevImage, &newImage, width, height,
    188                            &newWidth, &newHeight, level);
    189
    190                    // Load the mipmap level
    191                    glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA,
    192                            newWidth, newHeight, 0, GL_RGBA,
    193                            GL_UNSIGNED_BYTE, newImage);
    194
    195                    // Free the previous image
    196                    free(prevImage);
    197
    198                    // Set the previous image for the next iteration
    199                    prevImage = newImage;
    200                    level++;
    201
    202                    // Half the width and height
    203                    width = newWidth;
    204                    height = newHeight;
    205                }
    206
    207                free(newImage);
    208                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    209            }
    210            else
    211            {
    212                free(spriteData);
    213                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    214            }
    215
    216            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    217
    218            Log("+++ TextureManager::LoadTexture size %dx%d\n", pTexture->m_iWidth, pTexture->m_iHeight);
    219            Log("+++ TextureManager::LoadTexture PNG texture loaded: %s.png\n", pTexture->m_strName);
    220            return true;
    221        }
    222        else
    223        {
    224            Log("@@@ TextureManager::LoadTexture Unable to load texture: %s\n", pTexture->m_strName);
    225            Log("@@@ TextureManager::LoadTexture Defaulting to missing texture\n");
    226
    227            pTexture->m_bIsCompressed = false;
    228
    229            CGImageRef spriteImage;
    230            CGContextRef spriteContext;
    231            GLubyte *spriteData;
    232            int width, height;
    233
    234            // Creates a Core Graphics image from an image file
    235            spriteImage = [UIImage imageNamed : [NSString stringWithCString : "missing_texture.png" encoding : [NSString defaultCStringEncoding]]].CGImage;
    236
    237            if (spriteImage)
    238            {
    239                // Get the width and height of the image
    240                pTexture->m_iWidth = width = (int)CGImageGetWidth(spriteImage);
    241                pTexture->m_iHeight = height = (int)CGImageGetHeight(spriteImage);
    242                // Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
    243                // you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.
    244
    245                // Allocated memory needed for the bitmap context
    246                spriteData = (GLubyte *) calloc(width * height * 4, 1);
    247                // Uses the bitmatp creation function provided by the Core Graphics framework.
    248                spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
    249                // After you create the context, you can draw the sprite image to the context.
    250                CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat) width, (CGFloat) height), spriteImage);
    251                // You don't need the context at this point, so you need to release it to avoid memory leaks.
    252                CGContextRelease(spriteContext);
    253
    254                // Use OpenGL ES to generate a name for the texture.
    255                glGenTextures(1, &pTexture->m_theTexture);
    256                // Bind the texture name.
    257                glBindTexture(GL_TEXTURE_2D, pTexture->m_theTexture);
    258                // Speidfy a 2D texture image, provideing the a pointer to the image data in memory
    259                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    260                // Release the image data
    261
    262                free(spriteData);
    263                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    264                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    265
    266                Log("+++ TextureManager::LoadTexture missing_texture.png loaded\n");
    267                return true;
    268            }
    269            else
    270            {
    271                Log("@@@ TextureManager::LoadTexture Unable to load default missing texture: missing_texture.png\n");
    272
    273                return false;
    274            }
    275        }
    276    }
    277}
    278
    279//////////////////////////
    280//////////////////////////
    281
    282GLboolean TextureManager::GenMipMap2D(GLubyte *src, GLubyte **dst, int srcWidth, int srcHeight, int *dstWidth, int *dstHeight, int level)
    283{
    284    int x, y;
    285    int texelSize = 4;
    286
    287    *dstWidth = srcWidth / 2;
    288    if (*dstWidth <= 0)
    289        *dstWidth = 1;
    290
    291    *dstHeight = srcHeight / 2;
    292    if (*dstHeight <= 0)
    293        *dstHeight = 1;
    294
    295    *dst = (GLubyte*) malloc(sizeof(GLubyte) * texelSize * (*dstWidth) * (*dstHeight));
    296    if (*dst == NULL)
    297        return GL_FALSE;
    298
    299    for (y = 0; y < *dstHeight; y++)
    300    {
    301        for (x = 0; x < *dstWidth; x++)
    302        {
    303            int srcIndex[4];
    304            float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
    305            int sample;
    306
    307            // Compute the offsets for 2x2 grid of pixels in previous
    308            // image to perform box filter
    309            srcIndex[0] = (((y * 2) * srcWidth) + (x * 2)) * texelSize;
    310            srcIndex[1] = (((y * 2) * srcWidth) + (x * 2 + 1)) * texelSize;
    311            srcIndex[2] = ((((y * 2) + 1) * srcWidth) + (x * 2)) * texelSize;
    312            srcIndex[3] = ((((y * 2) + 1) * srcWidth) + (x * 2 + 1)) * texelSize;
    313
    314            // Sum all pixels
    315            for (sample = 0; sample < 4; sample++)
    316            {
    317                r += src[srcIndex[sample]];
    318                g += src[srcIndex[sample] + 1];
    319                b += src[srcIndex[sample] + 2];
    320                a += src[srcIndex[sample] + 3];
    321            }
    322
    323            // Average results
    324            r /= 4.0;
    325            g /= 4.0;
    326            b /= 4.0;
    327            a /= 4.0;
    328
    329            // Store resulting pixels
    330            (*dst)[ (y * (*dstWidth) + x) * texelSize ] = (GLubyte) (r);
    331            (*dst)[ (y * (*dstWidth) + x) * texelSize + 1] = (GLubyte) (g);
    332            (*dst)[ (y * (*dstWidth) + x) * texelSize + 2] = (GLubyte) (b);
    333            (*dst)[ (y * (*dstWidth) + x) * texelSize + 3] = (GLubyte) (a);
    334        }
    335    }
    336
    337    Log("+++ TextureManager::GenMipMap2D level %d: %dx%d\n", level, *dstWidth, *dstHeight);
    338
    339    return GL_TRUE;
    340}
    341
    342//////////////////////////
    343//////////////////////////
    344
    345Texture* TextureManager::GetTexture(const char* strTextureName, bool mipmaps)
    346{
    347    Log("+++ TextureManager::GetTexture Searching for %s\n", strTextureName);
    348
    349    std::string stringTextureName(strTextureName);
    350
    351    TTextureMapIterator lowerBound = m_TextureMap.lower_bound(stringTextureName);
    352
    353    ///--- ya estaba
    354    if (lowerBound != m_TextureMap.end() &&
    355            !(m_TextureMap.key_comp()(stringTextureName, lowerBound->first)))
    356    {
    357        Log("+++ TextureManager::GetTexture Already in use\n");
    358
    359        return lowerBound->second;
    360    }
    361        ///--- no estaba
    362    else
    363    {
    364        Texture* temp = new Texture();
    365        strcpy(temp->m_strName, strTextureName);
    366
    367        if (LoadTexture(temp, mipmaps))
    368        {
    369            TTextureMapPair insertPair(stringTextureName, temp);
    370
    371            TTextureMapIterator result = m_TextureMap.insert(lowerBound, insertPair);
    372
    373            if (result->second)
    374            {
    375                ////--- se ha insertado la textura
    376                Log("+++ TextureManager::GetTexture New texture inserted\n");
    377                return temp;
    378            }
    379            else
    380            {
    381                ///--- ya existía??? nunca debe entrar aqui
    382                Log("@@@ TextureManager::GetTexture FATAL ERROR @@@\n");
    383            }
    384        }
    385        else
    386        {
    387            ///--- no se pudo cargar la textura
    388            Log("@@@ TextureManager::GetTexture Unable to load texture %s\n", strTextureName);
    389        }
    390
    391        SafeDelete(temp);
    392        return NULL;
    393    }
    394}
    395
    396//////////////////////////
    397//////////////////////////
    398
    399bool TextureManager::UnloadTexture(const char* strTextureName)
    400{
    401    std::string stringTextureName(strTextureName);
    402
    403    TTextureMapIterator itor = m_TextureMap.find(stringTextureName);
    404
    405    ///--- estaba
    406    if (itor != m_TextureMap.end())
    407    {
    408        Log("+++ TextureManager::UnloadTexture Deleting texture: %s\n", itor->second->m_strName);
    409
    410        glDeleteTextures(1, &itor->second->m_theTexture);
    411
    412        SafeDelete(itor->second);
    413
    414        m_TextureMap.erase(itor);
    415
    416        return true;
    417    }
    418        ///--- no estaba
    419    else
    420    {
    421        Log("@@@ TextureManager::UnloadTexture The texture was not found\n");
    422        return false;
    423    }
    424}
    425
    426//////////////////////////
    427//////////////////////////
    428
    429bool TextureManager::UnloadTexture(Texture* pTexture)
    430{
    431    return UnloadTexture(pTexture->m_strName);
    432}
    433
    434//////////////////////////
    435//////////////////////////
    436
    437int TextureManager::UnloadAll(void)
    438{
    439    for (TTextureMapIterator i = m_TextureMap.begin(); i != m_TextureMap.end(); i++)
    440    {
    441        Log("+++ TextureManager::UnloadAll Deleting texture: %s\n", i->second->m_strName);
    442
    443        glDeleteTextures(1, &i->second->m_theTexture);
    444
    445        SafeDelete(i->second);
    446    }
    447
    448    m_TextureMap.clear();
    449
    450    return 0;
    451}
    452