摘要: 此文對cocos2d-x引擎中最具代表性,最能體現框架結構的幾個類做了簡單的介紹, 包括Director,Application, Renderer, EventDispatcher, Scheduler. 對於這些類, 也只對關系主要流程的方法做了介紹, 略過了容錯代碼和其它細節. 主要目的是讓大家快速的對cocos2d-x引擎有一個全面籠統的認識, 也方便快速定位問題.
- 博客: http://www.cnblogs.com/jhzhu
- 郵箱: jhzhuustc@gmail.com
- 作者: 知明所以
- 時間: 2014-07-21
GLView
cocos2d-x對openGL的封裝. 不同平台下, openGL有一些差別.
openGL
一段簡單的例子
以下內容引用自Introduction to OpenGL. 需要更具體的介紹也可參考這個鏈接.
#include <whateverYouNeed.h> main() { InitializeAWindowPlease(); glClearColor (0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); glBegin(GL_POLYGON); glVertex3f (0.25, 0.25, 0.0); glVertex3f (0.75, 0.25, 0.0); glVertex3f (0.75, 0.75, 0.0); glVertex3f (0.25, 0.75, 0.0); glEnd(); glFlush(); UpdateTheWindowAndCheckForEvents(); }
OpenGL Command Syntax
- OpenGL commands use the prefix
gland initial capital letters for each word making up the command name - some seemingly extraneous letters appended to some command names (for example, the
3finglColor3f()andglVertex3f())
OpenGL as a State Machine
OpenGL is a state machine. You put it into various states (or modes) that then remain in effect until you change them.
Application
主要方法:
virtual const char * getCurrentLanguage(); virtual Platform getTargetPlatform(); virtual void setAnimationInterval(double interval); int run();//啟動主循環
run()函數
int Application::run() { ... while(!glview->windowShouldClose()) { QueryPerformanceCounter(&nNow); if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart) { nLast.QuadPart = nNow.QuadPart; director->mainLoop(); //Director進行這一幀的渲染 glview->pollEvents(); // This function processes only those events that have already been received and then returns immediately. } else { Sleep(0); } } ... return true; }
Director
主要函數預覽
//openGL Matrix Operate void pushMatrix(MATRIX_STACK_TYPE type); void popMatrix(MATRIX_STACK_TYPE type); void loadIdentityMatrix(MATRIX_STACK_TYPE type); void loadMatrix(MATRIX_STACK_TYPE type, const Mat4& mat); void multiplyMatrix(MATRIX_STACK_TYPE type, const Mat4& mat); Mat4 getMatrix(MATRIX_STACK_TYPE type); void resetMatrixStack(); //View Data inline double getAnimationInterval(); inline bool isDisplayStats(); inline GLView* getOpenGLView(); inline Projection getProjection(); Size getVisibleSize() const; Vec2 getVisibleOrigin() const; Vec2 convertToGL(const Vec2& point); Vec2 convertToUI(const Vec2& point); float getZEye() const; // Scene 場景管理 inline Scene* getRunningScene(); void runWithScene(Scene *scene); void pushScene(Scene *scene); // 控制繪制的暫停和恢復 void end(); void pause(); void resume(); //繪制圖形(界面展示最重要的函數) void drawScene(); //Getter and Setter Scheduler* getScheduler() const { return _scheduler; } void setScheduler(Scheduler* scheduler); ActionManager* getActionManager() const { return _actionManager; } void setActionManager(ActionManager* actionManager); EventDispatcher* getEventDispatcher() const { return _eventDispatcher; } void setEventDispatcher(EventDispatcher* dispatcher); Renderer* getRenderer() const { return _renderer; }
drawScene(): 主要繪制函數
// Draw the Scene void Director::drawScene() { ... if (! _paused) { _scheduler->update(_deltaTime); //Scheduler 定時器 更新 _eventDispatcher->dispatchEvent(_eventAfterUpdate); //Dispatcher 拋發事件. } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glClear if (_nextScene) //取得下一個將要顯示的Scene. { setNextScene(); } pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); //將上一次繪制的Context放到堆棧 // draw the scene if (_runningScene) { _runningScene->visit(_renderer, Mat4::IDENTITY, false); _eventDispatcher->dispatchEvent(_eventAfterVisit); } _renderer->render(); //渲染 _eventDispatcher->dispatchEvent(_eventAfterDraw); popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); //返回到上一次繪制時的狀態. // swap buffers if (_openGLView) { _openGLView->swapBuffers(); //把上面渲染的結果顯示到屏幕 } ... }
Node::visit() 函數
預覽
Node::visit() 的主要功能就是
- 調用所有孩子的
visit函數 - 調用
self->draw()函數
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 Director* director = Director::getInstance(); director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); int i = 0; if(!_children.empty()) { sortAllChildren(); // draw children zOrder < 0 for( ; i < _children.size(); i++ ) { auto node = _children.at(i); if ( node && node->_localZOrder < 0 ) 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); } director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); }
Node::draw()
因為Node是所有可顯示對象的父類, 沒有任何顯示內容, 所以draw函數為空.
這里我們以Sprite::draw函數為例簡單介紹下draw的作用.
void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) { // Don't do calculate the culling if the transform was not updated _insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; if(_insideBounds) { _quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform); renderer->addCommand(&_quadCommand); } }
我們看到, Sprite::draw函數主要實現了[添加一個QuadCommand到Render中去]的功能.
再看看Label的繪制函數.
Label::draw
void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) { // Don't do calculate the culling if the transform was not updated _insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; if(_insideBounds) { _customCommand.init(_globalZOrder); _customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, flags); renderer->addCommand(&_customCommand); } }
其實, 跟Sprite::draw也差不多. 關鍵在於這個RenderCommand怎么構造和執行的.
Renderer 渲染器
主要函數預覽
void initGLView(); /** Adds a `RenderComamnd` into the renderer */ void addCommand(RenderCommand* command); /** Adds a `RenderComamnd` into the renderer specifying a particular render queue ID */ void addCommand(RenderCommand* command, int renderQueue); /** Pushes a group into the render queue */ void pushGroup(int renderQueueID); /** Pops a group from the render queue */ void popGroup(); /** Creates a render queue and returns its Id */ int createRenderQueue(); /** Renders into the GLView all the queued `RenderCommand` objects */ void render();
可見它主要由兩個功能:
- 對
ReanderCommand進行排序和分類管理 - 進行渲染:
render()
渲染函數Renderer::render()
void Renderer::render() { ... if (_glViewAssigned) { ... //排列渲染隊列 for (auto &renderqueue : _renderGroups) { renderqueue.sort(); } //進行渲染 visitRenderQueue(_renderGroups[0]); ... } ... }
Renderer::visitRenderQueue
按照順序執行所有的 RenderCommand
void Renderer::visitRenderQueue(const RenderQueue& queue) { ssize_t size = queue.size(); for (ssize_t index = 0; index < size; ++index) { auto command = queue[index]; auto commandType = command->getType(); if(RenderCommand::Type::QUAD_COMMAND == commandType) { auto cmd = static_cast<QuadCommand*>(command); //Batch quads if(_numQuads + cmd->getQuadCount() > VBO_SIZE) { drawBatchedQuads(); } _batchedQuadCommands.push_back(cmd); memcpy(_quads + _numQuads, cmd->getQuads(), sizeof(V3F_C4B_T2F_Quad) * cmd->getQuadCount()); convertToWorldCoordinates(_quads + _numQuads, cmd->getQuadCount(), cmd->getModelView()); _numQuads += cmd->getQuadCount(); } else if(RenderCommand::Type::GROUP_COMMAND == commandType) { flush(); int renderQueueID = ((GroupCommand*) command)->getRenderQueueID(); visitRenderQueue(_renderGroups[renderQueueID]); } else if(RenderCommand::Type::CUSTOM_COMMAND == commandType) { ... } ... } }
openGL VAO, VBO 介紹.
GLSL渲染語言入門與VBO、VAO使用:繪制一個三角形
OpenGL 4.0 VAO VBO 理解
Schelduler介紹
Schelduler是cocos2d-x中實現延遲調用,定時調用時最重要的功能. 類似於其他語言中的Timer
他最核心的函數就是:
void schedule(const ccSchedulerFunc& callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const std::string& key);
用來啟動一個定時操作: 在延遲delay時間后, 每隔repeat時間, 調用一次callback. target用來標記這個操作屬於誰, 方便管理, 比如在析構的時候調用void unschedule(void *target)即可移除當前對象的所有定時操作.
Schelduler的其它大部分方法, 要么是它的衍生, 為了減少調用參數; 要么是對定時操作的控制, 比如暫停, 恢復, 移除等. 如果只對想對框架的各個模塊有大概的了解, 可以不做深入.
EventDispatcher
(后續添加)
Written with StackEdit.
