美文网首页
cocos2d源码分析(六):Texture2D

cocos2d源码分析(六):Texture2D

作者: 奔向火星005 | 来源:发表于2019-01-11 17:52 被阅读0次

Texture2D管理一个OpenGL纹理的相关信息,主要的成员如下:

class CC_DLL Texture2D : public Ref
{
public:
//...
protected:
    Texture2D::PixelFormat _pixelFormat;  //像素格式
    int _pixelsWide;  //图像的像素宽
    int _pixelsHigh;   //图像的像素高

    GLuint _name;   //纹理名称,由glGenTextures生成
    GLfloat _maxS;  //最大纹理横轴坐标,默认为1
    GLfloat _maxT;  //最大纹理纵轴坐标,默认为1

    Size _contentSize;  //图像大小
    bool _hasPremultipliedAlpha;  //是预乘了透明通道
    bool _hasMipmaps;  //是否有mipmaps

    //关联的着色器
    GLProgram* _shaderProgram; //对应SHADER_NAME_POSITION_TEXTURE

    static const PixelFormatInfoMap _pixelFormatInfoTables;

    bool _antialiasEnabled;  //是否抗锯齿
    NinePatchInfo* _ninePatchInfo;

    bool _valid;
    std::string _filePath;  //图像文件路径

    Texture2D* _alphaTexture;  //还没用过
}

下面简单过一下它的初始化流程:

bool Texture2D::initWithImage(Image *image, PixelFormat format)
{
    if (image == nullptr)
    {
        CCLOG("cocos2d: Texture2D. Can't create Texture. UIImage is nil");
        return false;
    }

    int imageWidth = image->getWidth();
    int imageHeight = image->getHeight();
    this->_filePath = image->getFilePath();
    Configuration *conf = Configuration::getInstance();

    //返回当前机型支持的最大尺寸图片,用glGetIntegerv(GL_MAX_TEXTURE_SIZE, &_maxTextureSize);获取
    int maxTextureSize = conf->getMaxTextureSize();
    //若图片超过OpenGL允许的最大纹理尺寸,则失败返回
    if (imageWidth > maxTextureSize || imageHeight > maxTextureSize) 
    {
        CCLOG("cocos2d: WARNING: Image (%u x %u) is bigger than the supported %u x %u", imageWidth, imageHeight, maxTextureSize, maxTextureSize);
        return false;
    }

    unsigned char*   tempData = image->getData();
    Size             imageSize = Size((float)imageWidth, (float)imageHeight);
    PixelFormat      pixelFormat = ((PixelFormat::NONE == format) || (PixelFormat::AUTO == format)) ? image->getRenderFormat() : format;
    PixelFormat      renderFormat = image->getRenderFormat();
    size_t           tempDataLen = image->getDataLen();


    if (image->getNumberOfMipmaps() > 1)  //是否有mipmaps
    {
        if (pixelFormat != image->getRenderFormat())
        {
            CCLOG("cocos2d: WARNING: This image has more than 1 mipmaps and we will not convert the data format");
        }

        initWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getRenderFormat(), imageWidth, imageHeight);
        
        // set the premultiplied tag
        _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
        
        return true;
    }
    else if (image->isCompressed())  //是否是压缩格式
    {
        if (pixelFormat != image->getRenderFormat())
        {
            CCLOG("cocos2d: WARNING: This image is compressed and we can't convert it for now");
        }

        initWithData(tempData, tempDataLen, image->getRenderFormat(), imageWidth, imageHeight, imageSize);
        
        // set the premultiplied tag
        _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
        
        return true;
    }
    else
    {
        unsigned char* outTempData = nullptr;
        ssize_t outTempDataLen = 0;

        pixelFormat = convertDataToFormat(tempData, tempDataLen, renderFormat, pixelFormat, &outTempData, &outTempDataLen);  //将源数据转换为目标格式的数据

        initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize);


        if (outTempData != nullptr && outTempData != tempData)
        {

            free(outTempData);
        }

        // set the premultiplied tag
        _hasPremultipliedAlpha = image->hasPremultipliedAlpha();  //最后又赋值
        
        return true;
    }
}

initWithMipmaps的代码为:

bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, PixelFormat pixelFormat, int pixelsWide, int pixelsHigh)
{
    //the pixelFormat must be a certain value 
    CCASSERT(pixelFormat != PixelFormat::NONE && pixelFormat != PixelFormat::AUTO, "the \"pixelFormat\" param must be a certain value!");
    CCASSERT(pixelsWide>0 && pixelsHigh>0, "Invalid size");

    if (mipmapsNum <= 0)
    {
        CCLOG("cocos2d: WARNING: mipmap number is less than 1");
        return false;
    }
    

    auto formatItr = _pixelFormatInfoTables.find(pixelFormat);
    if(formatItr == _pixelFormatInfoTables.end())
    {
        CCLOG("cocos2d: WARNING: unsupported pixelformat: %lx", (unsigned long)pixelFormat );
        return false;
    }

    const PixelFormatInfo& info = formatItr->second;

    if (info.compressed && !Configuration::getInstance()->supportsPVRTC()
                        && !Configuration::getInstance()->supportsETC()
                        && !Configuration::getInstance()->supportsS3TC()
                        && !Configuration::getInstance()->supportsATITC())
    {
        CCLOG("cocos2d: WARNING: PVRTC/ETC images are not supported");
        return false;
    }

    //Set the row align only when mipmapsNum == 1 and the data is uncompressed
    if (mipmapsNum == 1 && !info.compressed)
    {
        unsigned int bytesPerRow = pixelsWide * info.bpp / 8;

        if(bytesPerRow % 8 == 0)  //根据图片的宽来决定纹理数据对齐
        {
            glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
        }
        else if(bytesPerRow % 4 == 0)
        {
            glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        }
        else if(bytesPerRow % 2 == 0)
        {
            glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
        }
        else
        {
            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        }
    }else
    {
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    }

    if(_name != 0)
    {
        GL::deleteTexture(_name);
        _name = 0;
    }

    glGenTextures(1, &_name);  //生成纹理名称
    GL::bindTexture2D(_name);  //调用activeTexture和glBindTexture,绑定_name到纹理单元0,如果有_alphaTexture,则将它绑定到纹理单元1

    if (mipmapsNum == 1)
    {
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _antialiasEnabled ? GL_LINEAR : GL_NEAREST);
    }else
    {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _antialiasEnabled ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST);
    }
    
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _antialiasEnabled ? GL_LINEAR : GL_NEAREST );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

#if CC_ENABLE_CACHE_TEXTURE_DATA
    if (_antialiasEnabled)
    {
        TexParams texParams = {(GLuint)(_hasMipmaps?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR),GL_LINEAR,GL_NONE,GL_NONE};
        VolatileTextureMgr::setTexParameters(this, texParams);
    } 
    else
    {
        TexParams texParams = {(GLuint)(_hasMipmaps?GL_NEAREST_MIPMAP_NEAREST:GL_NEAREST),GL_NEAREST,GL_NONE,GL_NONE};
        VolatileTextureMgr::setTexParameters(this, texParams);
    }
#endif

    // clean possible GL error
    GLenum err = glGetError();
    if (err != GL_NO_ERROR)
    {
        cocos2d::log("OpenGL error 0x%04X in %s %s %d\n", err, __FILE__, __FUNCTION__, __LINE__);
    }
    
    // Specify OpenGL texture image
    int width = pixelsWide;
    int height = pixelsHigh;
    
    for (int i = 0; i < mipmapsNum; ++i)
    {
        unsigned char *data = mipmaps[i].address;
        GLsizei datalen = mipmaps[i].len;

        if (info.compressed)
        {
            glCompressedTexImage2D(GL_TEXTURE_2D, i, info.internalFormat, (GLsizei)width, (GLsizei)height, 0, datalen, data);
        }
        else
        {
            glTexImage2D(GL_TEXTURE_2D, i, info.internalFormat, (GLsizei)width, (GLsizei)height, 0, info.format, info.type, data);
        }

        if (i > 0 && (width != height || ccNextPOT(width) != width ))
        {
            CCLOG("cocos2d: Texture2D. WARNING. Mipmap level %u is not squared. Texture won't render correctly. width=%d != height=%d", i, width, height);
        }

        err = glGetError();
        if (err != GL_NO_ERROR)
        {
            CCLOG("cocos2d: Texture2D: Error uploading compressed texture level: %u . glError: 0x%04X", i, err);
            return false;
        }

        width = MAX(width >> 1, 1);
        height = MAX(height >> 1, 1);
    }

    _contentSize = Size((float)pixelsWide, (float)pixelsHigh);
    _pixelsWide = pixelsWide;
    _pixelsHigh = pixelsHigh;
    _pixelFormat = pixelFormat;
    _maxS = 1;
    _maxT = 1;

    _hasPremultipliedAlpha = false;
    _hasMipmaps = mipmapsNum > 1;

    // shader
    setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE));
    return true;
}

相关文章

网友评论

      本文标题:cocos2d源码分析(六):Texture2D

      本文链接:https://www.haomeiwen.com/subject/dcxxdqtx.html