Yeah for per quad data you’ll want to use attributes to support batching.
If you can pack your data into 3 floats (pos), 4 floats (color), and 2 floats (texcoord) by, for example, using the alpha channel as an argument into a shader function that outputs the correct frame size based on the alpha value then you’re good to go with just Sprite and modifying its 3 attributes correctly.
I’m not sure how easily you can modify or subclass Sprite to do what you want without writing some custom render code since TriangleCommand defaults to V3F_C4B_T2F for its vertex buffer attributes. It probably would be easiest to write a simple Sprite subclass (e.g. BlurSprite) along with a simple TriangleCommand subclass (e.g. BlurTriangleCommand) and then modify the struct Triangles appropriately for your additional attributes and any supporting code.
We do something similar with our custom tile map so that we pass in a normal (a_normal) and 2nd texture coord (a_texCoord1) for lighting, fog of war, and a couple tile-based effects (as opposed to screen position). However, we based it off FastTMXTileLayer class and thus we’re batching all quads internally into a single render command. This is another avenue you could take, custom batch all your sprites together as a single draw command. Then you can also provide uniforms to the entire batch as well.
Here’s our vertex buffer code for that
struct ST_V3F_C4B_T2Fx3_N3F
{
cocos2d::Vec3 vertices; // 12 bytes (pos)
cocos2d::Color4B colors; // 4 bytes (color + opacity)
cocos2d::Tex2F texCoord0 // 8 bytes (uv s.frame coord)
cocos2d::Tex2F texCoord1; // 8 bytes (tile coord)
cocos2d::Tex2F texCoord2; // 8 bytes (extra remove if not need)
cocos2d::Vec3 normals; // 12 bytes (normal, could pack smaller)
};
struct ST_V3F_C4B_T2Fx3_N3F_Quad
{
ST_V3F_C4B_T2Fx3_N3F tl;
ST_V3F_C4B_T2Fx3_N3F bl;
ST_V3F_C4B_T2Fx3_N3F tr;
ST_V3F_C4B_T2Fx3_N3F br;
};
// in ::updateTotalQuads()
quad.bl.texCoord1 = Tex2F(u, v); // tile coordinate
quad.bl.normals.x = //default tile normal map
// in ::updateVertexBuffer()
_vData = VertexData::create();
_vertexBuffer = VertexBuffer::create(sizeof(ST_V3F_C4B_T2Fx3_N3F), (int)_totalQuads.size() * 4);
_vData->setStream(_vertexBuffer, VertexStreamAttribute(0, GLProgram::VERTEX_ATTRIB_POSITION, GL_FLOAT, 3));
_vData->setStream(_vertexBuffer, VertexStreamAttribute(offsetof(ST_V3F_C4B_T2Fx3_N3F, colors), GLProgram::VERTEX_ATTRIB_COLOR, GL_UNSIGNED_BYTE, 4, true));
_vData->setStream(_vertexBuffer, VertexStreamAttribute(offsetof(ST_V3F_C4B_T2Fx3_N3F, texCoord0), GLProgram::VERTEX_ATTRIB_TEX_COORD, GL_FLOAT, 2));
_vData->setStream(_vertexBuffer, VertexStreamAttribute(offsetof(ST_V3F_C4B_T2Fx3_N3F, texCoord1), GLProgram::VERTEX_ATTRIB_TEX_COORD1, GL_FLOAT, 2));
_vData->setStream(_vertexBuffer, VertexStreamAttribute(offsetof(ST_V3F_C4B_T2Fx3_N3F, normals), GLProgram::VERTEX_ATTRIB_NORMAL, GL_FLOAT, 3));
// shader
attribute vec2 a_texCoord1;
attribute vec3 a_normal;
For implementing your own drawing for You can take a look at the Mesh class to see how it handles usage of adding in the normal attribute.
Hopefully I’ve given enough info and ideas that you can figure out how to move forward.
Others can feel free to give different or better advice.