Cocos2D-X source code analysis from cocos2D-X learning OpenGL (2) ---- QUAD_COMMAND, cocos2dopengl
Personal Original, welcome to reprint, reprint please indicate the original address http://blog.csdn.net/bill_man
The previous article introduced the basic rendering structure of the cocos2d-x, this article along with the previous rendering structure introduction rendering command QUAD_COMMAND command part, through this part of the function, learning opengl processing image rendering method, first, we will introduce the basic concepts VAO and VBO involved in this section.
VAO and VBO:
Vertex Array Object (VAO) is an Object that contains one or more Vertex Buffer objects (VBO). It generally stores all information about a rendered Object. VertexBuffer Object VBO is a high-speed memory buffer in your graphics card memory, used to store all vertex information.
These concepts seem obscure. In short, we usually need to store the information of all vertices in an array to draw some images, but some points are often used repeatedly, in this way, the storage space of a vertex information will be reused, which will first lead to a waste of storage controls, and second, if we want to modify the information of this vertex, it needs to be changed multiple times. Therefore, we use the index method to describe the image. In this way, we can use an array to store vertex information, and an array to store vertex indexes. In this way, all vertices are different, in addition, the vertex information is stored in the memory of the video card, which reduces the time for the cpu to transmit data to the gpu and improves the rendering efficiency of the program. This is VBO. In OpenGL3.0, even more advanced VAO occurs, the VBO gets the drawing state by drawing the context. The VAO can have multiple VBO, which records all the drawing States, and its code is simpler and more efficient, in the drawing of the cocos2d-x, we will determine whether the bottom layer supports VAO. If VAO is supported, VAO is preferred. The differences between the two can be seen from the initialization:
Void Renderer: setupBuffer () {if (Configuration: getInstance ()-> supportsShareableVAO () {// initialize VBO and VAO setupVBOAndVAO ();} else {// VAO is not supported. Only VBO setupVBO () ;}} void Renderer: setupVBOAndVAO () {// a vao glGenVertexArrays (1, & _ quadVAO ); // bindVAO (_ quadVAO); // create two VBO glGenBuffers (2, & _ buffersVBO [0]); // vertex Buffer glBindBuffer (GL_ARRAY_BUFFER, _ buffersVBO [0]); glBufferData (GL_ARRAY_BUFFER, sizeof (_ quads [0]) * VBO_SIZE, _ quads, GL_DYNAMIC_DRAW); // The difference between VAO and VBO, VAO put the code in Initialization. No matter how many times it is drawn, as long as it is not changed, this code will only be called once, while in VBO, the code of this function is called every time it is drawn, which saves efficiency. // The position is glablevertexattribarray (GLProgram: VERTEX_ATTRIB_POSITION); glVertexAttribPointer (GLProgram: VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof (dimensions), (GLvoid *) offsetof (dimensions, vertices); // color: glablevertexattribarray (GLProgram: VERTEX_ATTRIB_COLOR); Scheme (GLProgram: VERTEX_ATTRIB_COLOR, 4, dimensions, GL_TRUE, sizeof (dimensions), (GLvoid *) offsetof (V3F_C4B_T2F, colors); // glablevertexattribarray (GLProgram: dimensions); glVertexAttribPointer (GLProgram :: latency, 2, GL_FLOAT, GL_FALSE, sizeof (V3F_C4B_T2F), (GLvoid *) offsetof (latency, texCoords); // index Buffer glBindBuffer (latency, _ buffersVBO [1]); glBufferData (bytes, sizeof (_ indices [0]) * VBO_SIZE * 6, _ indices, GL_STATIC_DRAW); // cancel vao gl: bindVAO (0); glBindBuffer (bytes, 0); glBindBuffer (GL_ARRAY_BUFFER, 0); CHECK_GL_ERROR_DEBUG ();} void Renderer: setupVBO () {// create two VBO glGenBuffers (2, & _ buffersVBO [0]); // call the function to bind buffer mapBuffers ();} void Renderer: mapBuffers () {// GL_ARRAY_BUFFER indicates vertex data // GL_ELEMENT_ARRAY_BUFFER indicates index data // avoid changing the buffer element GL: bindVAO (0); // bind id vertex data glBindBuffer (GL_ARRAY_BUFFER, _ buffersVBO [0]); // specify the glBufferData (GL_ARRAY_BUFFER, sizeof (_ quads [0]) * VBO_SIZE, _ quads, GL_DYNAMIC_DRAW) in the memory area for the id change ); glBindBuffer (GL_ARRAY_BUFFER, 0); // The second VBO index data glBindBuffer (bytes, _ buffersVBO [1]); glBufferData (bytes, sizeof (_ indices [0]) * VBO_SIZE * 6, _ indices, GL_STATIC_DRAW); glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); CHECK_GL_ERROR_DEBUG ();}
Two key functions to be introduced
GlBindBuffer: it binds a buffer object, indicating which buffer object will be affected by future operations. If an application has multiple buffer objects, you need to call the glBindBuffer () function multiple times: Initialize the buffer object and its data at one time. You can select a buffer object for rendering for future calls, either update the data of the buffer object.
When the second input parameter uses a non-zero unsigned integer for the first time, a new buffer object is created. When the second parameter is previously used, the buffer object becomes an active buffer object; if the second parameter value is 0, the buffer object is stopped.
GlBufferData: reserved space for storing data. It allocates a certain size (second parameter) of openGL server memory for storing vertex data or indexes. Data associated with the bound object will be cleared.
GlBufferData Parameters
Parameter 1: Target GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER
Parameter 2, memory capacity
Parameter 3 is used to initialize a buffer object. It can be a pointer or empty.
Parameter 4: how to read and write data, you can select the following types
GL_DYNAMIC_DRAW
GL_STATIC_DRAW
GL_STREAM_DRAW: The data is specified only once. It can be used only a few times as the source data of the function specified for drawing and image. The data in the buffer object often needs to be updated, however, this data is used less often in plotting or other operations.
From the initialization code, why is VAO complicated? Because he just put some things that need to be done during the painting into the initialization function in advance, let's take a look at the painting process.
// Does the current openGL support VAO if (Configuration: getInstance ()-> supportsShareableVAO () {// bind the vertex array glBindBuffer (GL_ARRAY_BUFFER, _ buffersVBO [0]); // request a space from the buffer and specify the data transmission mode glBufferData (GL_ARRAY_BUFFER, sizeof (_ quads [0]) * (_ numQuads), nullptr, GL_DYNAMIC_DRAW ); // provide an update void * buf = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY) for the buffer object containing the entire data set; memcpy (buf, _ quads, sizeof (_ quads [0]) * (_ numQuads); // The buffer object is updated to glUnmapBuffe. R (GL_ARRAY_BUFFER); // to disable a buffer object, you can use 0 as the identifier of the buffer object to call the glBindBuffer () function. This switches OpenGL to the default mode that does not use buffer objects. GlBindBuffer (GL_ARRAY_BUFFER, 0); // Bind vao gl: bindVAO (_ quadVAO);} else {# define kQuadSize sizeof (_ quads [0]. bl) glBindBuffer (GL_ARRAY_BUFFER, _ buffersVBO [0]); glBufferData (GL_ARRAY_BUFFER, sizeof (_ quads [0]) * _ numQuads, _ quads, GL_DYNAMIC_DRAW ); // activate the attribute GL: enableVertexAttribs (GL: vertex) of vertex color texture coordinates; // vertex glVertexAttribPointer (GLProgram: VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid *) offsetof (dimensions, vertices); // glVertexAttribPointer (GLProgram: VERTEX_ATTRIB_COLOR, 4, Hangzhou, GL_TRUE, kQuadSize, (GLvoid *) offsetof (dimensions, colors); // texture coordinate glVertexAttribPointer (GLProgram: limit, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid *) offsetof (limit, texCoords); glBindBuffer (limit, _ buffersVBO [1]);}
We can see that the functions with these settings are placed in the plotting function. Although they seem to be the same, the plotting function is called more frequently, therefore, putting these functions into the initialization function can greatly improve the program efficiency.
Here we will introduce two functions of VAO:
The glMapBuffer function returns a pointer pointing to the data storage of the currently bound buffer object associated with the first parameter. The first parameter is the same as the first parameter of glBufferData. The second parameter is one of GL_READ_ONLY, GL_WRITE_ONLY, or GL_READ_WRITE, which indicates operations on data.
GlUnmapBuffer indicates that the update to the currently bound buffer object has been completed and the buffer can be released.
Finally, you need to call the element function to draw the information.
glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) );
It draws Based on the index (Note: vertex data and indexes use different buffers respectively)
It should be noted that glDeleteBuffers should be called in the Renderer destructor to release its resources, and its identification can be used by other buffer objects.
In the previous article, the QUAD_COMMAND (called quadrilateral drawing) command in several rendering commands calls drawBatchedQuads to call the drawing function. The command for processing this logic is as follows:
If (commandType = RenderCommand: Type: QUAD_COMMAND) {auto cmd = static_cast <QuadCommand *> (command); CCASSERT (nullptr! = Cmd, "Illegal command for RenderCommand Taged as QUAD_COMMAND"); // If the Quad data volume exceeds the VBO size, call the plot, draw All cached commands if (_ numQuads + cmd-> getQuadCount ()> VBO_SIZE) {CCASSERT (cmd-> getQuadCount ()> = 0 & cmd-> getQuadCount () <VBO_SIZE, "VBO is not big enough for quad data, please break the quad data down or use customized render command"); drawBatchedQuads ();} // cache commands, do not call plotting _ batchedQuadCommands. push_back (cmd); memcpy (_ quads + _ numQuads, cmd-> getQuads (), sizeof (V3F_C4B_T2F_Quad) * cmd-> getQuadCount ()); // convert to the world coordinates convertToWorldCoordinates (_ quads + _ numQuads, cmd-> getQuadCount (), cmd-> getModelView ()); // record the number of quadrilateral _ numQuads + = cmd-> getQuadCount ();}
Void Renderer: flush () {// draw drawBatchedQuads (); // clear _ lastMaterialID = 0 ;}
This processing is mainly to save the command to _ batchedQuadCommands. If the Quad data volume exceeds the VBO size, call the rendering function to draw all the cached commands.
If the size of the VBO is not exceeded, the drawBatchedQuads plotting function is called when flush is called.
In case of any errors, please note
Next section describes graphic rendering and batch processing.
Functions of OpenGL ES and cocos2d-x on android Development
Opengl is relatively basic and cocos2d is professional, but its functions are not comprehensive. There is no need to learn games, and many android things need to be learned.
We hope to learn more about the underlying Game Development Technology (OpenGL), preferably the cocos2d x engine.
High quality cocos2d x tutorials on the market is not much, you can search mcco network, there are Yang rich cross-platform game development courses, is to talk about cocos2d-x. Hope to adopt