一、纹理缓存(TextureCache)
纹理缓存是将纹理缓存起来方便之后的绘制工作。每一个缓存的图像的大小,颜色和区域范围都是可以被修改的。这些信息都是存储在内存中的,不用在每一次绘制的时候都发送给GPU。
首先,我们创建一个精灵
Sprite* Sprite::create(const std::string& filename)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->initWithFile(filename))
{
sprite->autorelease();
sprite->setName(filename.c_str());
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
然后,继续深入,initWithFile
的方法
bool Sprite::initWithFile(const std::string& filename)
{
CCASSERT(filename.size()>0, "Invalid filename for sprite");
Texture2D *texture = Director::getInstance()->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;
}
最后在TextureCache 的 addImage方法里,我们会先去集合里查找是否之前加载过,如果没有找到,那么我们就会新生成一张纹理,并且添加到集合里。
二、精灵帧缓存(CCSpriteFrameCache)
CCSpriteFrameCache单例是所有精灵帧的缓存。使用spritesheet和与之相关的xml文件,我们可以加载很多的精灵帧到缓存中,那么之后我们就可以从这个缓存中创建精灵对象了。
三、创建内存查看器
在TextureCache中有个getCachedTextureInfo的方法
这个方法可以输出每一张纹理所占用的内存,但是log日志输出查看的话,难免不够直观,查看起来不太方便,所以这里我就想到把所有的这些纹理封装到一个Node里,然后显示在屏幕上。
Node* TextureCache::getCachedTextureNode() const
{
std::string buffer;
char buftmp[4096];
unsigned int count = 0;
unsigned int totalBytes = 0;
// wade
Node* node = Node::create();
int _height = 0;
for( auto it = _textures.begin(); it != _textures.end(); ++it ) {
memset(buftmp,0,sizeof(buftmp));
Texture2D* tex = it->second;
Sprite* _sprite = Sprite::createWithTexture(tex);
if (_sprite) {
_sprite->setAnchorPoint(Point(0,1));
_sprite->setPositionY(-_height);
node->addChild(_sprite);
_height = _height+_sprite->getContentSize().height;
}
unsigned int bpp = tex->getBitsPerPixelForFormat();
// Each texture takes up width * height * bytesPerPixel bytes.
auto bytes = tex->getPixelsWide() * tex->getPixelsHigh() * bpp / 8;
totalBytes += bytes;
count++;
snprintf(buftmp,sizeof(buftmp)-1,"\"%s\" rc=%lu id=%lu %lu x %lu @ %ld bpp => %lu KB\n",
it->first.c_str(),
(long)tex->getReferenceCount(),
(long)tex->getName(),
(long)tex->getPixelsWide(),
(long)tex->getPixelsHigh(),
(long)bpp,
(long)bytes / 1024);
buffer += buftmp;
}
snprintf(buftmp, sizeof(buftmp)-1, "TextureCache dumpDebugInfo: %ld textures, for %lu KB (%.2f MB)\n", (long)count, (long)totalBytes / 1024, totalBytes / (1024.0f*1024.0f));
buffer += buftmp;
return node;
}
接下来就是JS的工作了,至于怎么导出C++接口到JS中,这里就不作介绍了,在JS中我们创建了一个叫MemoryLayer
的类,专门用来负责显示缓存。
var MemoryLayer = cc.LayerColor.extend({
node:null,
startPosition:null,
distance:0,
ctor:function(){
this._super(cc.color(0,0,0,200));
this.initTouchEvent();
this.initView();
},
initView:function(){
var _info = cc.TextureCache.getInstance().getCachedTextureInfo()
cc.log("wade MemoryLayer info:"+_info)
node = cc.TextureCache.getInstance().getCachedTextureNode();
node.setPositionY(cc.winSize.height);
node.setScale(0.5);
this.addChild(node);
var closeBtn = new ccui.Button("res/Default/Button_Normal.png");
this.addChild(closeBtn);
var size = cc.director.getWinSize();
closeBtn.setPosition(cc.p(size.width-100,size.height-100));
closeBtn.addTouchEventListener(this.closeBtnListener,this);
cc.log(" MemoryLayer initView success");
},
closeBtnListener:function(_sender,_type){
switch(_type){
case ccui.Widget.TOUCH_ENDED:
this.removeFromParent();
break;
}
},
initTouchEvent : function(){
//对layer添加触摸事件;
var listener = cc.EventListener.create({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches:true,
onTouchBegan:this.onTouchBegan.bind(this),
onTouchMoved:this.onTouchMoved.bind(this),
onTouchEnded:this.onTouchEnded.bind(this)
});
cc.eventManager.addListener(listener,this);
},
onTouchBegan : function(touch,event){
startPosition = touch.getLocation().y;
return true;
},
onTouchMoved : function(touch,event){
var curPosition = touch.getLocation().y;
var dis = (curPosition - startPosition);
startPosition = curPosition;
this.distance = this.distance + dis;
if(this.distance<0){
this.distance = 0;
return;
}
node.setPositionY(node.getPositionY()+dis);
},
onTouchEnded : function(touch,event){
return true;
},
})
最后以一张效果图作为本期节目的结束: