1、cocos主线程以及Auto-batching
AppDelegate app;//封装用于智能分化,完成初始化,载入资源、构造场景、生成精灵
Application::getInstance()->run();//启动主线程
director->mainLoop();//分为场景渲染,和清理缓存池
glview->pollEvents();
drawScene:
1)优先处理输入事件(空实现,留接口)
2)默认定时器(负优先级,0,正优先级)。自定义计时器
3)visit主渲染树(autobatcch)是使用group
4)visit通知窗口
5)渲染,切换缓存区
visit:中序遍历二叉树,添加RenderCommand。
遍历结束后执行Render():
排序RenderCommand为三组:负、0、正;
RenderCommand中为QUAD_COMMAND的将会进行autoBatch处理:
_batchedQuadCommands缓存池不断添加单个QuadCommand,
当前的绘制命令绘制quad单元数加上现存的绘制单元数超过缓存池容量,则执行现存的绘制操作,并清理缓存池,之后添加命令至缓冲池中。
其余绘制类型如custom、batchNode则是直接执行,不执行autoBatch。
而GroupCommand类型是又是一组绘制队列,将递归地执行上诉过程。
1、shader绘制灰度纹理
在helloworld中增加变量:
cocos2d::CustomCommand m_customCommand;
void onDraw(const cocos2d::Mat4 &transform, uint32_t flags);
cocos2d::Sprite* m_pSprite;
cocos2d::V3F_C4B_T2F_Quad m_sQuad;
//cpp中代码
#include "HelloWorldScene.h"
USING_NS_CC;
static Texture2D * texture2d;
//--------------------------------------------------------
static const GLchar* s_szColorSpriteVSH =
" \n\
attribute vec4 a_position; \n\
attribute vec2 a_texCoord; \n\
attribute vec4 a_color; \n\
\n\
#ifdef GL_ES \n\
varying lowp vec4 v_fragmentColor; \n\
varying mediump vec2 v_texCoord; \n\
#else \n\
varying vec4 v_fragmentColor; \n\
varying vec2 v_texCoord; \n\
#endif \n\
\n\
void main() \n\
{ \n\
gl_Position = CC_MVPMatrix * a_position; \n\
v_fragmentColor = a_color; \n\
v_texCoord = a_texCoord; \n\
}";
//--------------------------------------------------------
static const GLchar* s_szColorSpriteFSH =
" \n\
#ifdef GL_ES \n\
precision mediump float; \n\
#endif \n\
\n\
uniform sampler2D u_texture; \n\
varying vec2 v_texCoord; \n\
varying vec4 v_fragmentColor; \n\
\n\
void main(void) \n\
{ \n\
// vec3( 0.299, 0.587, 0.114 ) 是RGB转YUV的参数值,生成灰色图
\n\
float MixColor = dot(texture2D(u_texture, v_texCoord).rgb, vec3(0.299, 0.587, 0.114)); \n\
// 使用灰色图进行颜色混合 \n\
vec4 blendColor = vec4( 1.0, 1.0, 1.0, 1.0 ); // 调整这个值以修改最终混合色值 \n\
gl_FragColor = vec4(MixColor * blendColor.r, MixColor * blendColor.g, MixColor * blendColor.b, blendColor.a); \n\
}";
Scene* HelloWorld::createScene()
{
// ‘scene‘ is an autorelease object
auto scene = Scene::create();
// ‘layer‘ is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
texture2d = TextureCache::sharedTextureCache()->addImage("HelloWorld.png");
texture2d->getGLProgram()->initWithVertexShaderByteArray( s_szColorSpriteVSH, s_szColorSpriteFSH );
texture2d->getGLProgram()->link();
CHECK_GL_ERROR_DEBUG();
texture2d->getGLProgram()->updateUniforms();
CHECK_GL_ERROR_DEBUG();
return true;
}
void HelloWorld::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
m_customCommand.init(_globalZOrder);
m_customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this, transform, flags);
renderer->addCommand(&m_customCommand);
}
void HelloWorld::onDraw(const Mat4 &transform, uint32_t flags)
{
//ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst );
static GLfloat vertext[] = {
0.0f,0.0f,0.0f,
480.0f,0.0f,0.0f,
0.0f,320.0f,0.0f,
480.0f,320.0f,0.0f
};
//但是纹理的读取也是逆时针,只是EG是用三角形作为基础图形去绘制其他图形,方向先绘制下三角,再绘制上三角!!!之前这里搞错了。希望大家别被我误导了
static GLfloat coord[] = {
0.0f,1.0f,
1.0f,1.0f,
0.0f,0.0f,
1.0f,0.0f
};
static GLfloat colors[] = {
1.0f,1.0f,1.0f,1.0f,
1.0f,1.0f,1.0f,1.0f,
1.0f,1.0f,1.0f,1.0f,
1.0f,1.0f,1.0f,1.0f,
};
//初始化纹理,即将纹理映射至openGL ES的世界坐标系中
coord[2] = coord[6] = texture2d->getMaxS();
coord[1] = coord[3] = texture2d->getMaxT();
//开启着色器,坐标、颜色、纹理
GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
//设置着色器
texture2d->getGLProgram()->use();
//设置统一属性,即M模型、V视图、P投影,完成从Opengl的世界坐标到屏幕坐标的映射
texture2d->getGLProgram()->setUniformsForBuiltins();
//绑定纹理,texture2d->getName() 纹理在内存或显存中存储的下标(应该是下标,我没看纹理加载,还不了解GPU和CPU的通信)
glBindTexture(GL_TEXTURE_2D,texture2d->getName());
//设置顶点,每个顶点向量维数为3,数据类型为GL_FLOAT,不归一化(真实物理坐标不能归一化),两个个顶点间的偏移量为0,
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, 0, vertext);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, 0, coord);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR,4,GL_FLOAT,GL_FALSE,0,colors);
//绘图,从下标0开始,有4个顶点
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
}
2、cocos2d-x中,添加C++和luaScript的桥接函数,比如:
int lua_cocos2dx_3d_Skeleton3D_getBoneByName(lua_State* tolua_S)
{
int argc = 0;
cocos2d::Skeleton3D* cobj = nullptr;
bool ok = true;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG >= 1
if (!tolua_isusertype(tolua_S,1,"cc.Skeleton3D",0,&tolua_err)) goto tolua_lerror;
#endif
cobj = (cocos2d::Skeleton3D*)tolua_tousertype(tolua_S,1,0);
#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid ‘cobj‘ in function ‘lua_cocos2dx_3d_Skeleton3D_getBoneByName‘", nullptr);
return 0;
}
#endif
argc = lua_gettop(tolua_S)-1;
if (argc == 1)
{
std::string arg0;
ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.Skeleton3D:getBoneByName");
if(!ok)
{
tolua_error(tolua_S,"invalid arguments in function ‘lua_cocos2dx_3d_Skeleton3D_getBoneByName‘", nullptr);
return 0;
}
cocos2d::Bone3D* ret = cobj->getBoneByName(arg0);
object_to_luaval<cocos2d::Bone3D>(tolua_S, "cc.Bone3D",(cocos2d::Bone3D*)ret);
return 1;
}
luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "cc.Skeleton3D:getBoneByName",argc, 1);
return 0;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function ‘lua_cocos2dx_3d_Skeleton3D_getBoneByName‘.",&tolua_err);
#endif
return 0;
}
3、面试遗留:
1)lua的table本身是由两块内存组成,一块是连续的array,另外一块则是hashTable实现的。因为没看过源码不确认数组这块的存储,就没有提及
2)lua的调用栈从1到N为栈增加,即从栈底向栈顶进发。-1为栈顶,-N为栈底。具体的内存结构还没看
3)QuickSort和HeapSort的确切代码,主要在于QuickSort的非递归实现。
4)认真考究cocos2d的主线线程流程,有利于以后做架构优化
4、lua脚本调用C++,则是先压函数地址为0下标位;C++、lua入栈从左参数开始入栈。C++若调用lua的函数则需要使用lua_call;Lua只能调用使用特定格式的函数:
定义一个C/C++函数:
代码:typedef int (*lua_CFunction) (lua_State *L); //要求参数和返回值必须和这个一直,即可以赋值函数指针给lua_CFunction的都可以被调用
函数必须以Lua解释器作为参数,并且返回值为int类型。既然Lua解释器作为函数的参数,那么实际上函数可以从栈中取得任意多个参数。下面我 们将看到,返回的整数值代表入栈的值的数目。如果有一个C/C++函数,你想在Lua中调用他,很容易封装一下就可以满足上述要求。
5、上面一条成为C++粘合层,cocos2d-lua的分支就是增加了粘合层来建立lua虚拟机和C++库的连接,同时删减没必要了模块。这个粘合层在设计模式中叫做代理,早前云风曾经提到是否使用类似的设计,如果真要提供库,必须减少粘合层的厚度才能保证健壮性
lua这边的库也要实现Lua的粘合层,才能使得脚本开发时使用的是和C++类似的API。
cocos的粘合层需要重新编写一边,这也是为什么自定义库需要使用luabinding等工具方便。而维护引擎必须也要熟悉cocos接口设计思想,如第3条,都会根据参数个数去实现粘合调用的是哪个接口,quick引擎组要做的事情大部分是这个吧。
6、以前实现的QuicklySort:在github上面有Cpp文件夹中有
void swap(int *x,int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int participation(int a[],int l,int r)
{
int p = a[l];
int i = l;
int j = r+1;
while(i<j)
{
do{
i++;
}while(a[i]<=p);
do{
j--;
}while (a[j]>p);
swap(&a[i],&a[j]);
}
swap(&a[i],&a[j]);
swap(&a[l],&a[j]);
return j;
}
void QuicklySort(int a[],int l,int r)
{
int s = 0;
if(l<r)
{
s = participation(a,l,r);
QuicklySort(a,l,s-1);
QuicklySort(a,s+1,r);
}
}
7、
1、先记录几篇博客,供以后查看:
http://cn.cocos2d-x.org/tutorial/show?id=1474
http://blog.csdn.net/ym012/article/details/7209637
http://www.cnblogs.com/sifenkesi/p/3876745.html
http://my.oschina.net/xlplbo/blog/314956
http://blog.csdn.net/dongdongdongjl/article/details/8629704
2、本人的环境文档:链接:http://pan.baidu.com/s/1o6FROMY 密码:o7vt
直接使用源码配置。luac.c和lua.c相关说明参照:
http://blog.csdn.net/dongdongdongjl/article/details/8629704