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

下面看下它的初始化函数:
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;
}
网友评论