0
votes

How can I draw a shape from an svg file using cocos2d v2.0 and OpenGL ES 2.0?

I have a simple svg file with a shape. If I parse the svg file into sets of points and bezier path handles, is it possible to draw the shape using some OpenGL ES 2.0 calls?

I would like to draw the background of my game level using svg shapes so that the curves continue to look smooth as the player zooms in and out. I've looked at LevelSVG, but I'm looking for a simpler solution that doesn't involve box2d.

Asked another way: In OpenGL ES 2, how do I draw a filled shape from a set of points and bezier curves like the ones in the svg file?

Here is my test svg file generated by GIMP containing a shape.

<svg xmlns="http://www.w3.org/2000/svg"
     width="14.2222in" height="10.6667in"
     viewBox="0 0 1024 768">
  <path id="Unnamed"
        fill="purple" stroke="purple" stroke-width="1"
        d="M 165.00,477.00
           C 165.00,477.00 249.00,348.00 325.50,373.50 
             402.00,399.00 318.00,516.00 447.00,507.00
             576.00,498.00 412.50,327.00 480.00,301.50
             547.50,276.00 639.00,429.00 655.50,510.00
             672.00,591.00 597.00,633.00 454.50,607.50
             312.00,582.00 211.50,589.50 184.50,546.00
             157.50,502.50 165.00,477.00 165.00,477.00 Z
           M 486.00,267.00" />
</svg>

This is my first question on SO after being a long-time lurker. Thanks all!

1

1 Answers

0
votes

For the solution I am proposing, you would need to load your xml file and reformat your data vertices into a GL triangle strip or triangle fan format. I have used that technique to draw smooth curves in many games before, you just need to create a sufficient number of points to make the lines smooth.

This technique could be used to create an effect like the colored curves in the game Tiny Wings. Some of my games that I have used this drawing technique in include Enduro Extreme Trials, SnowXross 2, and several others. To create the curves, I wrote a scripting engine that executes functions that use things like summation of sinusoid functions to create the geometry based on parameters passed in by the level scripts.

If you are not familiar with OpenGL triangle strip drawing, you should look into this because it is a very common way of drawing in OpenGL ES 2.0 (and OpenGL ES 1.1 too).

The glDrawMode is my own custom enum to decide which draw method to use. Triangle strip would probably work best for a bezier.

The dynamicVerts in the code below is a pointer to an C array of 3 float struct, but you could replace it with CGPoint and change the glVertexAttribPointer parameter from 3 to 2 to set it up for two dimensions instead of three. This array defies your geometry that you will dray.

The dynamicVertColors is a pointer to a C array of ccColor4Byte struct. This array aligns to vertices in glVertexAttribPointer to color what is drawn.

Subclass CCNode and add the following draw method to draw in OpenGL 2.0 ES in Cocos2d 2.0.

-(void) draw {

    if (shouldDrawDynicVerts == YES) {

       ccGLUseProgram( shaderProgram->program_ );
        [shaderProgram setUniformForModelViewProjectionMatrix];
        ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position);

        glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, 0, dynamicVerts);    
        glEnableVertexAttribArray(kCCVertexAttribFlag_Position);

        glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, dynamicVertColors);   
        glEnableVertexAttribArray(kCCVertexAttribFlag_Color);



        if (glDrawMode == kDrawTriangleStrip) {
            glDrawArrays(GL_TRIANGLE_STRIP, 0, dynamicVertCount);   

        }else if (glDrawMode == kDrawLines){
            glDrawArrays(GL_LINES, 0, dynamicVertCount);    
            glLineWidth(1);

        }else if (glDrawMode == kDrawPoints){
            glDrawArrays(GL_POINTS, 0, dynamicVertCount);   

        }else if (glDrawMode == kDrawTriangleFan){
            glDrawArrays(GL_TRIANGLE_FAN, 0, dynamicVertCount); 

       }

    }

}

In the init method of the custom node that does the drawing or somewhere else appropriate, assign the GLES shader program to use when drawing. The easiest way to do that is to use one that Coocos2d has built in.

self.shaderProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionColor];

I created a tutorial with sample Xcode project and drawing helper class free at: http://heyalda.com/drawing-with-opengl-es-2-0-in-cocos2d-2-0/