1开始,先创建一个LayerColor

Scene *scene=Scene::create();
director->runWithScene(scene);
//目标
auto layer = LayerColor::create(Color4B(, , , ), , );
//主要的步骤就是设置了node 的 _position
layer->setPosition(,);
scene->addChild(layer);

2 看一下LayerColor的初始化方法

bool LayerColor::initWithColor(const Color4B& color, GLfloat w, GLfloat h)
{
if (Layer::init())
{ // default blend function
//指定混合模式
_blendFunc = BlendFunc::ALPHA_NON_PREMULTIPLIED; /*
realColor和displayedColor 记录元素本身的颜色属性
displayedColor和displayedOpacity方法用于表示和父亲元素叠加过后的最终绘制颜色
sprite用于父亲颜色和自己纹理的混合,LayColor默认一致,不叠加颜色
*/
_displayedColor.r = _realColor.r = color.r;
_displayedColor.g = _realColor.g = color.g;
_displayedColor.b = _realColor.b = color.b;
_displayedOpacity = _realOpacity = color.a; //四个顶点 初始化
for (size_t i = ; i<sizeof(_squareVertices) / sizeof( _squareVertices[]); i++ )
{
_squareVertices[i].x = 0.0f;
_squareVertices[i].y = 0.0f;
}
//四个顶点的颜色归一化,颜色是一样的
updateColor();
//w,h 为 设计分辨率,设置顶点的范围
setContentSize(Size(w, h));
/*
每个node拥有一个GLProgramState实例
查找这种类型的shader GLProgram SHADER_NAME_POSITION_COLOR_NO_MVP
*/
GLProgramState* state=GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_COLOR_NO_MVP); setGLProgramState(state);
return true;
}
return false;
}
/// override contentSize
void LayerColor::setContentSize(const Size & size)
{
//没有赋值的为0,也就是 0(0,0) 1(w,0) 2 (0,h) 3(w,h)
//绘制顺序为012 213
_squareVertices[].x = size.width;
_squareVertices[].y = size.height;
_squareVertices[].x = size.width;
_squareVertices[].y = size.height; Layer::setContentSize(size);
}
void Node::setContentSize(const Size & size)
{
if ( ! size.equals(_contentSize))
{
_contentSize = size;
//得到锚点在本地坐标系下的坐标
_anchorPointInPoints = Vec2(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y );
//告诉该更新了
_transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true;
}
}

3 Director::drawScene方法为正式绘图,如下

void Director::drawScene()
{
//省略部分代码 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //兼容cocos2.0,暂时忽略
pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // draw the scene
if (_runningScene)
{//正式访问
_runningScene->visit(_renderer, Mat4::IDENTITY, false);//第一次的矩阵是单位矩阵 _eventDispatcher->dispatchEvent(_eventAfterVisit);
}
//开始真正的opengl
_renderer->render(); popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _totalFrames++; // swap buffers
if (_openGLView)
{
_openGLView->swapBuffers();//这个之后再看
} if (_displayStats)
{
calculateMPF();//不知道啥意思
}
}

标红不分为开始遍历节点,但不进行opengl绘制,进入代码如下:

void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{
// quick return if not visible. children won't be drawn.
if (!_visible)
{
return;
} uint32_t flags = processParentFlags(parentTransform, parentFlags); // IMPORTANT:
// To ease the migration to v3.0, we still support the Mat4 stack,
// but it is deprecated and your code should not rely on it
/*
为了便于迁移到v3.0,我们仍然支持Mat4堆栈,
      但它已被弃用,您的代码不应该依赖它
*/
Director* director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
//把刚生产的模型视图矩阵加入到顶部的modeview,作为最顶部的最新的modelviewTransform
//有的地方会用到这个,比如RenderTexture,她的孩子用不到,因为直接从_modelViewTransform传就可以了
//
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); int i = ; if(!_children.empty())
{
sortAllChildren();
// draw children zOrder < 0
for( ; i < _children.size(); i++ )
{
auto node = _children.at(i); if ( node && node->_localZOrder < )
node->visit(renderer, _modelViewTransform, flags);
else
break;
}
// self draw
this->draw(renderer, _modelViewTransform, flags); for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, flags);
}
else
{
this->draw(renderer, _modelViewTransform, flags);
} /*
画完了就退出战,是兼容2.0的时候,把最顶部最新计算的modeviewtrnasform退出去
矩阵的转换都在GPU的shader中
*/
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // FIX ME: Why need to set _orderOfArrival to 0??
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
// reset for next frame
// _orderOfArrival = 0;
}

self->draw为绘制自己,但不是真的绘制,而是让自己关联一个绘制命令Command,LayerColor的draw方法重写如下:

//transform为本地坐标转世界坐标的矩阵
void LayerColor::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
_customCommand.init(_globalZOrder);
//回调函数
_customCommand.func = CC_CALLBACK_0(LayerColor::onDraw, this, transform, flags);
//把绘制命令的东西放到renderer里面
renderer->addCommand(&_customCommand); for(int i = ; i < ; ++i)
{
Vec4 pos;
//四个顶点的设计分辨率坐标
pos.x = _squareVertices[i].x; pos.y = _squareVertices[i].y; pos.z = _positionZ;
pos.w = ;//齐次坐标
//得出来的pos就是世界坐标下的pos了
_modelViewTransform.transformVector(&pos);
//pos.w 世界坐标的w始终为1
//这个世界坐标会在shader内乘以相机矩阵和裁剪矩阵,得出最后的视口需要的坐标
_noMVPVertices[i] = Vec3(pos.x,pos.y,pos.z)/pos.w;
}
}

代码把需要绘制的信息加入到了customCommand里面。

4 _renderer->render(); 负责执行command内的opengl绘制命令,代码如下:

void Renderer::render()
{ //Process render commands
//1. Sort render commands based on ID
//renderGroups包括若干rederqueue,默认使用第一个,
//renderquque包括若干个rendercommand
for (auto &renderqueue : _renderGroups)
{
renderqueue.sort();
} visitRenderQueue(_renderGroups[]); flush(); clean(); }
void Renderer::visitRenderQueue(const RenderQueue& queue)
{
ssize_t size = queue.size(); for (ssize_t index = ; index < size; ++index)
{
auto command = queue[index];
auto commandType = command->getType(); if(RenderCommand::Type::CUSTOM_COMMAND == commandType)//比如 LayerColor
{
flush();
auto cmd = static_cast<CustomCommand*>(command);
cmd->execute();//会调用LayerColor::onDraw,直接开始绘图
} }
}

5 cmd->execute会调用customCommand的回调函数,在LayerColor中为onDraw,代码如下:

//通过自定义方法进行回调 transform为 本地坐标转世界坐标的旋转矩阵
void LayerColor::onDraw(const Mat4& transform, uint32_t flags)
{
getGLProgram()->use();//layercolor 的tansform为相机矩阵*裁剪矩阵
getGLProgram()->setUniformsForBuiltins(transform);//设置顶点着色器中全局变量的值,如MVP矩阵
//启用 顶点坐标和颜色
GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR );
//
// Attributes
//
#ifdef EMSCRIPTEN
setGLBufferData(_noMVPVertices, * sizeof(Vec3), );
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, , GL_FLOAT, GL_FALSE, , ); setGLBufferData(_squareColors, * sizeof(Color4F), );
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, , GL_FLOAT, GL_FALSE, , );
#else //找到顶点的索引 _noMVPVertices为世界坐标中的四个顶点的值,存在了cpu中,没有存到显存
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, , GL_FLOAT, GL_FALSE, , _noMVPVertices); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, , GL_FLOAT, GL_FALSE, , _squareColors);
#endif // EMSCRIPTEN //混合,源和目标 颜色的混合
GL::blendFunc( _blendFunc.src, _blendFunc.dst ); //画这四个点
glDrawArrays(GL_TRIANGLE_STRIP, , ); //这是记录图元和顶点吗
// CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4);
auto __renderer__ = Director::getInstance()->getRenderer();
__renderer__->addDrawnBatches();
__renderer__->addDrawnVertices(); }

LayerColor绘制过程比较简单,没有纹理设置,只有顶点和颜色,通过glDrawArrays绘制完成

												

cocos源码分析--LayerColor的绘制过程的更多相关文章

  1. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  2. Spring源码分析之`BeanFactoryPostProcessor`调用过程

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 本文内容: AbstractApplicationContext#refresh前部分的一点小内容 ...

  3. Spring Ioc源码分析系列--Bean实例化过程(一)

    Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...

  4. Spring Ioc源码分析系列--Bean实例化过程(二)

    Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...

  5. MyBatis 源码分析 - SQL 的执行过程

    * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...

  6. 【Netty源码分析】发送数据过程

    前面两篇博客[Netty源码分析]Netty服务端bind端口过程和[Netty源码分析]客户端connect服务端过程中我们分别介绍了服务端绑定端口和客户端连接到服务端的过程,接下来我们分析一下数据 ...

  7. 【Canal源码分析】parser工作过程

    本文主要分析的部分是instance启动时,parser的一个启动和工作过程.主要关注的是AbstractEventParser的start()方法中的parseThread. 一.序列图 二.源码分 ...

  8. tomcat8 源码分析 | 组件及启动过程

    tomcat 8 源码分析 ,本文主要讲解tomcat拥有哪些组件,容器,又是如何启动的 推荐访问我的个人网站,排版更好看呦: https://chenmingyu.top/tomcat-source ...

  9. Spark 源码分析 -- task实际执行过程

    Spark源码分析 – SparkContext 中的例子, 只分析到sc.runJob 那么最终是怎么执行的? 通过DAGScheduler切分成Stage, 封装成taskset, 提交给Task ...

随机推荐

  1. MCU ADC 进入 PD 模式后出现错误的值?

    MCU ADC 进入 PD 模式后出现错误的值? 在调试一款 MCU,最开始问题是无法读到 ADC 的值,应该是读到的值是异常高. 怀疑问题 可能是主频太低,为了降低功耗,这个 MCU 主频被我降了很 ...

  2. Webpack4 的 Tree Shaking:babel-loader设置modules: false,还是设置"sideEffects": false,待确定

    Webpack4 的 Tree Shaking:babel-loader设置modules: false,还是设置"sideEffects": false,待确定 babel-lo ...

  3. TypeScript 之 书写.d.ts文件

    https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/Writing%20Definition%20Files.html ...

  4. NET设计模式 第二部分 创建型模式(4):工厂方法模式(Factory Method)

    工厂方法模式(Factory Method) ——.NET设计模式系列之五 Terrylee,2004年1月2日 概述 在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实 ...

  5. mysql 删除数据库中所有的表中的数据,只删database下面所有的表。

    select concat('drop table ',table_name,';') from TABLES where table_schema='数据库名称'; select concat('t ...

  6. piwik高负载加速之切换session存储位置

    默认情况下,piwik的session是存储于根目录下面的tmp/sessions/路径下面的.而官方文档里面说,如果由于本地硬盘的原因,这种设置可能会导致系统被变慢,这在高负载系统应用中可能是不可以 ...

  7. 阅读OReilly.Web.Scraping.with.Python.2015.6笔记---Crawl

    阅读OReilly.Web.Scraping.with.Python.2015.6笔记---Crawl 1.函数调用它自身,这样就形成了一个循环,一环套一环: from urllib.request ...

  8. 单进程与 多进程关系及区别(多进程系统linux)

    单进程编程:顺序执行 数据同步 复杂度低 用途单一 多进程编程:同时执行 数据异步 复杂度高 用途广泛 1. 多进程的优势在于任务的独立性,比如某个任务单独作为一个进程的话,崩溃只影响自己的服务,其他 ...

  9. 代码编辑器之sublime text插件

    sublimetext 学习资源:http://www.jianshu.com/p/d1b9a64e2e37 Sublime SFTP CTags – 让Sublime Text支持CTags. Si ...

  10. tomcat源码 Container

    1.Container的有四个子容器,分别是Engine,Host,Context,Wrapper,如下: 1.Engine:整个Catalina servlet引擎,标准实现为StandardEng ...