CustomCommand Tutorial
This example uses CreateColor
as an example to demonstrate how to use CustomCommand
to become familiar with and understand Cocos2d-x V4 API usage.
Create LayerColor
auto layerColor = LayerColor::create(Color4B::RED,
visibleSize.width,
visibleSize.height);
Next, go inside the LayerColor class and see what happens compared to V3.
In V3, the process of creating a shader is as follows:
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_COLOR_NO_MVP));
As with Example 1, during the initialization phase, V4 needs to complete the following steps:
Create backend::ProgramState
auto& pipelineDescriptor = _customCommand.getPipelineDescriptor(); _programState = new (std::nothrow) backend::ProgramState(positionColor_vert, positionColor_frag); pipelineDescriptor.programState = _programState; _mvpMatrixLocation = pipelineDescriptor.programState->getUniformLocation("u_MVPMatrix");
Create backend::VertexLayout
auto& vertexLayout = _customCommand.getPipelineDescriptor().vertexLayout; const auto& attributeInfo = _programState->getProgram()->getActiveAttributes(); auto iter = attributeInfo.find("a_position"); if (iter != attributeInfo.end()) { vertexLayout.setAttribute("a_position", Iter->second.location, Backend::VertexFormat::FLOAT3, 0, False); } iter = attributeInfo.find("a_color"); if (iter != attributeInfo.end()) { vertexLayout.setAttribute("a_color", Iter->second.location, Backend::VertexFormat::FLOAT4, Sizeof(_vertexData[0].vertices), False); } vertexLayout.setLayout(sizeof(_vertexData[0]), backend::VertexStepMode::VERTEX);
Create backend::BlendDescriptor
CustomCommand
has two common initialization methods:CustomCommand::init(float globalZOrder)
andCustomCommand::init(float globalZOrder, const BlendFunc& blendFunc)
. For the first one, you need to manually set the blend state:backend::BlendDescriptor& blendDescriptor = _customCommand.getPipelineDescriptor().blendDescriptor; blendDescriptor.blendEnabled = true; If (_blendFunc == BlendFunc::ALPHA_NON_PREMULTIPLIED) { blendDescriptor.sourceRGBBlendFactor = backend::BlendFactor::SRC_ALPHA; blendDescriptor.destinationRGBBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; blendDescriptor.sourceAlphaBlendFactor = backend::BlendFactor::SRC_ALPHA; blendDescriptor.destinationAlphaBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; } else { blendDescriptor.sourceRGBBlendFactor = backend::BlendFactor::ONE; blendDescriptor.destinationRGBBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; blendDescriptor.sourceAlphaBlendFactor = backend::BlendFactor::ONE; blendDescriptor.destinationAlphaBlendFactor = backend::BlendFactor::ONE_MINUS_SRC_ALPHA; }
For the second initialization method, you need to specify
BlendFunc
, and then theCustomCommand
initialization function will set the corresponding blend state according toBlendFunc
._blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; _customCommand.init(_globalZOrder, _blendFunc);
Create backend::Buffer
_customCommand.createIndexBuffer(CustomCommand::IndexFormat::U_SHORT, //index type format 6, //index count CustomCommand::BufferUsage::STATIC); unsigned short indices[] = {0, 1, 2, 2, 1, 3}; _customCommand.updateIndexBuffer(indices, sizeof(indices)); _customCommand.createVertexBuffer(sizeof(_vertexData[0]), //vertex size 4, //vertex count CustomCommand::BufferUsage::DYNAMIC); _customCommand.setDrawType(CustomCommand::DrawType::ELEMENT); _customCommand.setPrimitiveType(CustomCommand::PrimitiveType::TRIANGLE);
Because the index data does not change during the run, when the index buffer is created, specify bufferUsage as static and update the index buffer during the initialization phase. The vertex buffer data needs to be updated dynamically. Refer to Update Vertex buffer.
Update Unifrom
cocos2d::Mat4 projectionMat = Director::getInstance()->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
auto& pipelineDescriptor = _customCommand.getPipelineDescriptor();
pipelineDescriptor.programState->setUniform(_mvpMatrixLocation,
projectionMat.m,
Sizeof(projectionMat.m));
Update Vertex buffer
CommandBuffer provides the updateVertexBuffer
interface for updating vertex buffer data.
_customCommand.updateVertexBuffer(_vertexData, sizeof(_vertexData));
If you need to update the sub-block of vertex buffer, you can use CustomCommand::updateVertexBuffer(void* data, unsigned int offset, unsigned int length)
to pass in the offset.
addCommand
_customCommand.init(_globalZOrder, _blendFunc);
renderer->addCommand(&_customCommand);