1.create
auto sprite = Sprite::create("HelloWorld.png");
Sprite* Sprite::create(const std::string& filename)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->initWithFile(filename))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
Sprite::Sprite(void)
: _batchNode(nullptr)
, _textureAtlas(nullptr)
, _shouldBeHidden(false)
, _texture(nullptr)
, _spriteFrame(nullptr)
, _insideBounds(true)
{
}
2.init
bool Sprite::initWithFile(const std::string& filename)
{
if (filename.empty())
{
CCLOG("Call Sprite::initWithFile with blank resource filename.");
return false;
}
_fileName = filename;
_fileType = 0;
Texture2D *texture = _director->getTextureCache()->addImage(filename);
if (texture)
{
Rect rect = Rect::ZERO;
rect.size = texture->getContentSize();
return initWithTexture(texture, rect);
}
// don't release here.
// when load texture failed, it's better to get a "transparent" sprite then a crashed program
// this->release();
return false;
}
1)_director->getTextureCache()->addImage(filename):TextureCache用于管理texture的加载(另开一个线程)
2)rect.size = texture->getContentSize():用texture content size(像素为单位,window.size也是以像素为单位)作为Sprite的size,如果是一张1024X768的图片,则rect = (0,0,1024,768),这个rect会用来生成Sprite的顶点坐标,比如这个Rect的右上角对应的顶点坐标是(1024 / window.size.w, 768 / window.size.h)
bool Node::init()
{
return true;
}
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(0.5f, 0.5f));
// 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), set program but not set vertex attrib and uniform
setTexture(texture);
// set _quad, _texcoord
setTextureRect(rect, rotated, rect.size);
// by default use "Self Render".
// if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
setBatchNode(nullptr);
result = true;
}
_recursiveDirty = true;
setDirty(true);
return result;
}
0)_quad.bl.colors = Color4B::WHITE:默认4个角的颜色为白色
1)_flippedX = _flippedY = false:不需要flip,因为TexCoords按照未flip生成的(y轴向下,OpenGL坐标系y轴向上)
2)setAnchorPoint(Vec2(0.5f, 0.5f)):除了layer类,其他Node类锚点默认在正中间
3)_offsetPosition.setZero():Node的content size可能和texture size不一样,这样就会产生offset,一般offset都是0。因为使用texture的content size来设置Node的content size的,两者相等,所以没有offset。
4)setTexture(texture):设置texture,获取GLProgramState,加载编译所有的program,如果texture为nullptr,用一张白色的图片作为texture
void Sprite::setTexture(Texture2D *texture)
{
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture));
// If batchnode, then texture id should be the same
CCASSERT(! _batchNode || (texture && texture->getName() == _batchNode->getTexture()->getName()), "CCSprite: Batched sprites should use the same texture as the batchnode");
// accept texture==nil as argument
CCASSERT( !texture || dynamic_cast<Texture2D*>(texture), "setTexture expects a Texture2D. Invalid argument");
if (texture == nullptr)
{
// Gets the texture by key firstly.
texture = _director->getTextureCache()->getTextureForKey(CC_2x2_WHITE_IMAGE_KEY);
// If texture wasn't in cache, create it from RAW data.
if (texture == nullptr)
{
Image* image = new (std::nothrow) Image();
bool isOK = image->initWithRawData(cc_2x2_white_image, sizeof(cc_2x2_white_image), 2, 2, 8);
CC_UNUSED_PARAM(isOK);
CCASSERT(isOK, "The 2x2 empty texture was created unsuccessfully.");
texture = _director->getTextureCache()->addImage(image, CC_2x2_WHITE_IMAGE_KEY);
CC_SAFE_RELEASE(image);
}
}
if (!_batchNode && _texture != texture)
{
CC_SAFE_RETAIN(texture);
CC_SAFE_RELEASE(_texture);
_texture = texture;
updateBlendFunc();
}
}
5)setTextureRect(rect, rotated, rect.size):setTexCoords(左上为(0,0), 左下为(0.1),load image不flip,TexCoords实现flip)和setPosition(position没有变,左下为(0,0))
void Sprite::setTextureRect(const Rect& rect, bool rotated, const Size& untrimmedSize)
{
_rectRotated = rotated;
setContentSize(untrimmedSize);
setVertexRect(rect);
setTextureCoords(rect);
float relativeOffsetX = _unflippedOffsetPositionFromCenter.x;
float relativeOffsetY = _unflippedOffsetPositionFromCenter.y;
// issue #732
if (_flippedX)
{
relativeOffsetX = -relativeOffsetX;
}
if (_flippedY)
{
relativeOffsetY = -relativeOffsetY;
}
_offsetPosition.x = relativeOffsetX + (_contentSize.width - _rect.size.width) / 2;
_offsetPosition.y = relativeOffsetY + (_contentSize.height - _rect.size.height) / 2;
// rendering using batch node
if (_batchNode)
{
// update dirty_, don't update recursiveDirty_
setDirty(true);
}
else
{
// self rendering
// Atlas: Vertex
float x1 = 0.0f + _offsetPosition.x;
float y1 = 0.0f + _offsetPosition.y;
float x2 = x1 + _rect.size.width;
float y2 = y1 + _rect.size.height;
// Don't update Z.
_quad.bl.vertices.set(x1, y1, 0.0f);
_quad.br.vertices.set(x2, y1, 0.0f);
_quad.tl.vertices.set(x1, y2, 0.0f);
_quad.tr.vertices.set(x2, y2, 0.0f);
}
_polyInfo.setQuad(&_quad);
}
void Node::setContentSize(const Size & size)
{
if (! size.equals(_contentSize))
{
_contentSize = size;
_anchorPointInPoints.set(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y);
_transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true;
}
}
void Sprite::setVertexRect(const Rect& rect)
{
_rect = rect;
}
void Sprite::setTextureCoords(const Rect& rectInPoint)
{
Texture2D *tex = _batchNode ? _textureAtlas->getTexture() : _texture;
if (tex == nullptr)
{
return;
}
auto rectInPixels = CC_RECT_POINTS_TO_PIXELS(rectInPoint);
float atlasWidth = (float)tex->getPixelsWide();
float atlasHeight = (float)tex->getPixelsHigh();
float left, right, top, bottom;
if (_rectRotated)
{
#if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
left = (2*rectInPixels.origin.x+1)/(2*atlasWidth);
right = left+(rectInPixels.size.height*2-2)/(2*atlasWidth);
top = (2*rectInPixels.origin.y+