重读cocos2dx引擎

First of All

这个系列是看了版本OpenGL超级宝典之后,重新看cocos2dx渲染部分的笔记。

2016

综述:

/**
 * Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) )
 *
 * Sprite can be created with an image, or with a sub-rectangle of an image.
 *
 * To optimize the Sprite rendering, please follow the following best practices:
 *
 *  - Put all your sprites in the same spritesheet (http://www.codeandweb.com/what-is-a-sprite-sheet)
 *  - Use the same blending function for all your sprites
 *  - ...and the Renderer will automatically "batch" your sprites (will draw all of them in one OpenGL call).
 *
 *  To gain an additional 5% ~ 10% more in the rendering, you can parent your sprites into a `SpriteBatchNode`.
 *  But doing so carries the following limitations:
 *
 *  - The Alias/Antialias property belongs to `SpriteBatchNode`, so you can't individually set the aliased property.
 *  - The Blending function property belongs to `SpriteBatchNode`, so you can't individually set the blending function property.
 *  - `ParallaxNode` is not supported, but can be simulated with a "proxy" sprite.
 *  - Sprites can only have other Sprites (or subclasses of Sprite) as children.
 *
 * The default anchorPoint in Sprite is (0.5, 0.5).
 */  

    /**
     * Creates a sprite with an image filename.
     *
     * After creation, the rect of sprite will be the size of the image,
     * and the offset will be (0,0).
     *
     * @param   filename A path to image file, e.g., "scene1/monster.png"
     * @return  An autoreleased sprite object.
     */
    static Sprite* create(const std::string& filename);

用图片创建的Sprite的尺寸会和图片一样大。

    /**
     * Creates a sprite with an sprite frame.
     *
     * @param   spriteFrame    A sprite frame which involves a texture and a rect
     * @return  An autoreleased sprite object
     */
    static Sprite* createWithSpriteFrame(SpriteFrame *spriteFrame);

说明frame确实拥有一个rect信息。

/**
     * Sets whether the sprite should be flipped horizontally or not.
     *
     * @param flippedX true if the sprite should be flipped horizontally, false otherwise.
     */
    void setFlippedX(bool flippedX);

妈妈再也不用担心我用setScaleX(-1)来写代码啦~~

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;
}

所以可以看到这里关键的一句是Director:getInstance():getTextureCache():addImage(fileName);也就是把文件转成纹理然后缓存。
另外,当载入纹理失败的时候会返回一个透明的Sprite。

bool Sprite::initWithSpriteFrameName(const std::string& spriteFrameName)
{
    CCASSERT(spriteFrameName.size() > 0, "Invalid spriteFrameName");
    SpriteFrame *frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName);
    return initWithSpriteFrame(frame);
}

这里的知识是如何根据Frame的名字拿到Frame,SpriteFrameCache:getInstance():getSpriteFrameByName(frameName);这样子的~

/*
 * This array is the data of a white image with 2 by 2 dimension.
 * It's used for creating a default texture when sprite's texture is set to nullptr.
 * Supposing codes as follows:
 *
 *   auto sp = new (std::nothrow) Sprite();
 *   sp->init();  // Texture was set to nullptr, in order to make opacity and color to work correctly, we need to create a 2x2 white texture.
 *
 * The test is in "TestCpp/SpriteTest/Sprite without texture".
 */
static unsigned char cc_2x2_white_image[] = {
    // RGBA8888
    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF
};
#define CC_2x2_WHITE_IMAGE_KEY  "/cc_2x2_white_image"

这是一个分辨率2x2的白色图片,当载入Texture失败的时候,会把这个当做默认图片传进去。


以上是2016年看的代码。
现在是2018年,现在从渲染的角度去考虑。

2018

cast

首先回顾一下c++的两种转换。

  • static_cast<T>类似于直接加括号强转。
  • dynamic_cast<T>会检查能不能转换,若转换失败就返回一个nullptr。

就性能上来说静态转换少了一步检查,所以会好一些。

Texture2D

概况

其实就是封装了OpenGL的Texture。几个功能:

  • 从内存里面拿到数据(数据来源可能是Image。Image封装着从实际的图片文件变成内存数据的过程),然后在OpenGL那里申请来一个TextureID存起来,然后把数据从client内存推送给OpenGL。
  • 更新数据。使用mapbuffer方法从OpenGL拿到数据的内存,然后更改。
  • 像素类型转换。(所谓像素类型就是RBGA8888,RGB888,RGB565之类的,主要影响一个图对内存的占用大小,当然因为信息量不一样,所以也影响最终texture的图像质量。)

初始化

构造方法啥事儿没做,初始化就一个initWithData,会转换数据然后调到initWithMipMap

Sprite

从这个头文件的include就让人浮想联翩。

// ...
#include "2d/CCNode.h"
#include "2d/CCDrawNode.h"
#include "base/CCProtocols.h"
#include "renderer/CCTextureAtlas.h"
#include "renderer/CCTrianglesCommand.h"
#include "renderer/CCCustomCommand.h"
#include "2d/CCAutoPolygon.h"
  • DrawNode作用
  • Protocal主要是一些图像接口,设置颜色啊,设置透明度啊啥的
  • 合图
  • 三角形命令
  • 自定义命令,作用多种多样,可以自己把callback塞进去。之前看见的作用是拿来操作OpenGL状态机,开启关闭stencil或者depth测试啥的。
  • 多边形??

接下来看头文件里面的概况解说。

概况

Sprite可以用一个Image,或者一个Image的一部分来创建。
渲染优化方法:

  • 使用一个图集的图片
  • 使用一样的混合函数

为了把性能再提高个5%~10%,可以考虑使用SpriteBatchNode,但是有诸如以下的限制:

  • 抗锯齿属性会被SpriteBatchNode控制住,无法对每个子控件做单独设置
  • 混合函数同上
  • 不能使用ParallaxNode(啥玩意儿??)
  • 所有的子节点都应该是Sprite,不应该存在别的类型的子节点

Sprite是多继承,Node自然必不可少,还继承了TextureProtocol,就提供了一个texture的set\get接口。
创建方法多种多样:

  • 默认创建
  • 根据图片路径创建(可以猜到会先生成texture了)
  • 根据多边形来创建
  • 根据纹理创建
  • 根据精灵帧创建

    精灵帧是啥

其他的方法:

  • updateTransform 就modelViewTransform嘛,旋转缩放啥的
  • getBatchNode 就是拿到SpriteBatchNode,没啥,还有一个set的
  • 对精灵帧的设置和取出
  • dirty位的取出和设置
  • 拿到合图里面的索引
  • 翻转
    和setScaleX(-1)的不同是setScale会把整个逻辑都真的反转,包括锚点啥的。而setFilppedX只是反转了texture。可以看一下怎么翻转的texture。

    翻转纹理
    用contentWidth减去三角形顶点的x坐标,得到它新的x坐标,就是翻转。coord就不用变了。

  • 设置blendFunc
  • 拿到描述

其他的都是从node继承而来的,待会儿要看看draw方法。

受保护的方法:

  • setTextureCoords(Rect rect) 这就很有意思了,应该可以根据这个来改变效果

持有的域(只列举感兴趣的):

  • TrianglesCommand _trianglesCommand
  • DrawNode _debugDrawNode
    debug用的,应该会画出边界

方法详解

initWithTexture

有多种重写。最简单的是接收一个纹理,然后读出它的size作为大小矩阵。

  • 设置blendFunc为ALPHA_PREMULTIPIED。
  • 清空**_quad**。其中quad的类型为
    struct CC_DLL V3F_C4B_T2F_Quad
    {
    	/// top left
    	V3F_C4B_T2F    tl;
    	/// bottom left
    	V3F_C4B_T2F    bl;
    	/// top right
    	V3F_C4B_T2F    tr;
    	/// bottom right
    	V3F_C4B_T2F    br;
    };
    
    也就是vector3, color4b, coord2f,分别代表矩形的四个角。
    把四个角的颜色都设置成白色
  • 设置默认shader:GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP
  • 设置纹理和纹理矩阵
    调用到了setTexture()
    • 如果使用了batchNode,那么会判断传进来的纹理是否和上一个batchNode的纹理相同,否则异常。
    • 使用dynamic_cast判断纹理类型是否合法,否则异常。
    • 如果传进来的纹理就是空纹理,那么在纹理缓存里面找到名字为CC_2x2_WHITE_IMAGE_KEY的白色方块作为纹理(加入不存在就创建一个,白色方块很暴力,数据直接是定义一个2x2的数组在代码里)
    • retain一下新纹理表示持有,释放旧有纹理
    • 持有新纹理
  • 设置dirty
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值