cocos2d源码分析(七):Sprite初始化函数

Sprite,精灵,主要用来显示一张2D纹理图片。它内部主要有Texture2D类型的成员_texture,用于定义位置及大小的成员如_originalContentSize,_rect等,用于OpenGL渲染,有顶点坐标,纹理坐标信息的_polyInfo,_trianglesCommand等。它的类图大致如下:


5994163-8dee70799f9bb16a.png

下面看下它的初始化函数:

bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated)
{
    bool result = false;
    if (Node::init())
    {
        //设一堆默认值
        _batchNode = nullptr;
        _recursiveDirty = false;
        setDirty(false);
        _opacityModifyRGB = true;
        _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
        _flippedX = _flippedY = false;

        // default transform anchor: center
        setAnchorPoint(Vec2::ANCHOR_MIDDLE);

        // zwoptex default values
        _offsetPosition.setZero();

        // clean the Quad
        memset(&_quad, 0, sizeof(_quad));

        // Atlas: Color
        _quad.bl.colors = Color4B::WHITE;
        _quad.br.colors = Color4B::WHITE;
        _quad.tl.colors = Color4B::WHITE;
        _quad.tr.colors = Color4B::WHITE;

        // update texture (calls updateBlendFunc)
        setTexture(texture);
        setTextureRect(rect, rotated, rect.size);

        setBatchNode(nullptr);
        result = true;
    }

    _recursiveDirty = true;
    setDirty(true);

    return result;
}

initWithTexture函数里主要设置了一些默认值,并调用setTexture和setTextureRect函数,现在看下setTexture函数:

void Sprite::setTexture(Texture2D *texture)
{
    if(_glProgramState == nullptr)
    {        
//设置_glProgramState,对应的是SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP的着色器
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture));
    }

    //省了一些断言..

    //如果texture为null
    if (texture == nullptr)
    {
        //省略...
    }

    if ((_renderMode != RenderMode::QUAD_BATCHNODE) && (_texture != texture))
    {
        CC_SAFE_RETAIN(texture);
        CC_SAFE_RELEASE(_texture);  //释放旧的_texture
        _texture = texture;  //赋值
        updateBlendFunc();  //根据是否预乘透明通道,设置_blendFunc
    } 
}

setTexture函数主要对_glProgramState,_texture和_blendFunc进行赋值,值得一提的是,_glProgramState对应的枚举是SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP,在这顺便把它对应的着色器代码记录下:

//顶点着色器
const char* ccPositionTextureColor_noMVP_vert = R"(
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;

#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif

void main()
{
    gl_Position = CC_PMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;
}
)";

//片元着色器
const char* ccPositionTextureColor_noMVP_frag = R"(
#ifdef GL_ES
precision lowp float;
#endif

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

void main()
{
    gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}

setTextureRect函数如下:

void Sprite::setTextureRect(const Rect& rect, bool rotated, const Size& untrimmedSize)
{
    _rectRotated = rotated;  //是否旋转

    Node::setContentSize(untrimmedSize);  //设置在父类Node的_contentSize,以Point为单位
    _originalContentSize = untrimmedSize; //设置自身的初始大小_originalContentSize

    setVertexRect(rect);  //设置_rect
    updateStretchFactor(); //根据_contentSize和_originalContentSize设置缩放因子_stretchFactor
    updatePoly();
}

再看updatePoly函数,

void Sprite::updatePoly()
{
    // There are 3 cases:
    //
    // A) a non 9-sliced, non stretched
    //    contentsize doesn't not affect the stretching, since there is no stretching
    //    this was the original behavior, and we keep it for backwards compatibility reasons
    //    When non-stretching is enabled, we have to change the offset in order to "fill the empty" space at the
    //    left-top of the texture
    // B) non 9-sliced, stretched
    //    the texture is stretched to the content size
    // C) 9-sliced, stretched
    //    the sprite is 9-sliced and stretched.
    if (_renderMode == RenderMode::QUAD || _renderMode == RenderMode::QUAD_BATCHNODE) {
        Rect copyRect;
        if (_stretchEnabled) {  //判断缩放使能
            // case B)
            copyRect = Rect(0, 0, _rect.size.width * _stretchFactor.x, _rect.size.height * _stretchFactor.y);
        } else {
            // case A)
            // modify origin to put the sprite in the correct offset
            copyRect = Rect((_contentSize.width - _originalContentSize.width) / 2.0f,
                            (_contentSize.height - _originalContentSize.height) / 2.0f,
                            _rect.size.width,
                            _rect.size.height);
        }
        setTextureCoords(_rect, &_quad);  //根据_rect对_quad赋值
        setVertexCoords(copyRect, &_quad);  //如果缩放,顶点坐标用的是copyRect
        _polyInfo.setQuad(&_quad);  //设置_polyInfo

    } else if (_renderMode == RenderMode::SLICE9) {  //SLICE9类型,暂时还没分析
        //先省略了...
    }
}

updatePoly函数主要用于更新几何体信息_polyInfo,看注释可见有三种情况,A是非9-sliced,没有缩放;B是非9-sliced,缩放;C是9-sliced,9-sliced的情况还没仔细看过,暂不分析。我们看到A,B情况,主要是根据_rect和缩放因子,对_quad进行赋值,然后用_quad对_polyInfo进行赋值。
setTextureCoords函数如下:

void Sprite::setTextureCoords(const Rect& rectInPoints, V3F_C4B_T2F_Quad* outQuad)
{
    Texture2D *tex = (_renderMode == RenderMode::QUAD_BATCHNODE) ? _textureAtlas->getTexture() : _texture;
    if (tex == nullptr)
    {
        return;
    }
    //Point单位转到以像素为单位
    const auto rectInPixels = CC_RECT_POINTS_TO_PIXELS(rectInPoints);

    const float atlasWidth = (float)tex->getPixelsWide();
    const float atlasHeight = (float)tex->getPixelsHigh();

    float rw = rectInPixels.size.width;
    float rh = rectInPixels.size.height;

    // if the rect is rotated, it means that the frame is rotated 90 degrees (clockwise) and:
    //  - rectInpoints: origin will be the bottom-left of the frame (and not the top-right)
    //  - size: represents the unrotated texture size
    //
    // so what we have to do is:
    //  - swap texture width and height
    //  - take into account the origin
    //  - flip X instead of Y when flipY is enabled
    //  - flip Y instead of X when flipX is enabled

    if (_rectRotated)
        std::swap(rw, rh);

#if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
    float left    = (2*rectInPixels.origin.x+1) / (2*atlasWidth);
    float right   = left+(rw*2-2) / (2*atlasWidth);
    float top     = (2*rectInPixels.origin.y+1) / (2*atlasHeight);
    float bottom  = top+(rh*2-2) / (2*atlasHeight);
#else
    float left    = rectInPixels.origin.x / atlasWidth;
    float right   = (rectInPixels.origin.x + rw) / atlasWidth;
    float top     = rectInPixels.origin.y / atlasHeight;
    float bottom  = (rectInPixels.origin.y + rh) / atlasHeight;
#endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL


    if ((!_rectRotated && _flippedX) || (_rectRotated && _flippedY))
    {
        std::swap(left, right);
    }

    if ((!_rectRotated && _flippedY) || (_rectRotated && _flippedX))
    {
        std::swap(top, bottom);
    }

    if (_rectRotated)
    {
        outQuad->bl.texCoords.u = left;
        outQuad->bl.texCoords.v = top;
        outQuad->br.texCoords.u = left;
        outQuad->br.texCoords.v = bottom;
        outQuad->tl.texCoords.u = right;
        outQuad->tl.texCoords.v = top;
        outQuad->tr.texCoords.u = right;
        outQuad->tr.texCoords.v = bottom;
    }
    else
    {
        outQuad->bl.texCoords.u = left;
        outQuad->bl.texCoords.v = bottom;
        outQuad->br.texCoords.u = right;
        outQuad->br.texCoords.v = bottom;
        outQuad->tl.texCoords.u = left;
        outQuad->tl.texCoords.v = top;
        outQuad->tr.texCoords.u = right;
        outQuad->tr.texCoords.v = top;
    }
}

setVertexCoords函数如下:

void Sprite::setVertexCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad)
{
    float relativeOffsetX = _unflippedOffsetPositionFromCenter.x;
    float relativeOffsetY = _unflippedOffsetPositionFromCenter.y;

    // issue #732
    if (_flippedX)
    {
        relativeOffsetX = -relativeOffsetX;
    }
    if (_flippedY)
    {
        relativeOffsetY = -relativeOffsetY;
    }

    _offsetPosition.x = relativeOffsetX + (_originalContentSize.width - _rect.size.width) / 2;
    _offsetPosition.y = relativeOffsetY + (_originalContentSize.height - _rect.size.height) / 2;

    // FIXME: Stretching should be applied to the "offset" as well
    // but probably it should be calculated in the caller function. It will be tidier
    if (_renderMode == RenderMode::QUAD) {
        _offsetPosition.x *= _stretchFactor.x;
        _offsetPosition.y *= _stretchFactor.y;
    }

    // rendering using batch node
    if (_renderMode == RenderMode::QUAD_BATCHNODE)
    {
        // update dirty_, don't update recursiveDirty_
        setDirty(true);
    }
    else
    {
        // self rendering

        // Atlas: Vertex
        const float x1 = 0.0f + _offsetPosition.x + rect.origin.x;
        const float y1 = 0.0f + _offsetPosition.y + rect.origin.y;
        const float x2 = x1 + rect.size.width;
        const float y2 = y1 + rect.size.height;

        // Don't update Z.
        outQuad->bl.vertices.set(x1, y1, 0.0f);
        outQuad->br.vertices.set(x2, y1, 0.0f);
        outQuad->tl.vertices.set(x1, y2, 0.0f);
        outQuad->tr.vertices.set(x2, y2, 0.0f);
    }
}

PolygonInfo::setQuad函数如下:

void PolygonInfo::setQuad(V3F_C4B_T2F_Quad *quad)
{
    releaseVertsAndIndices();
    _isVertsOwner = false;
    triangles.indices = quadIndices9;
    triangles.vertCount = 4;
    triangles.indexCount = 6;
    triangles.verts = (V3F_C4B_T2F*)quad;
}

猜你喜欢

转载自blog.csdn.net/weixin_34414196/article/details/87427933