0

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!

Alex B
  • 35
  • 1
  • 6

1 Answers1

0

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/

Jim Range
  • 523
  • 2
  • 9
  • Thanks Jim, this will help me a lot. The only trouble is that as a user zooms-in I would need to recalculate the points on the curve, or else have a boat-load of points to make the curve smooth. Does OpenGL only render triangles? – Alex B Aug 04 '12 at 11:47
  • I have only used the different triangle and line geometry in iOS. Mostly triangle strip. In Open GLES 1.1 I have created games that have 50,000 points that define the triangle strip along with four 1024x1024 sprite sheets and Chipmunk physics doing 10 update loops per frame update and I can still get 60FPS on 3GS and newer devices. But I also was using Frame Buffer Objects to leverage the GPU for efficiency to draw the geometry. I know how to do that in gles 1.1 but have yet to take the time to figure it out in 2.0. – Jim Range Aug 04 '12 at 21:17
  • Regarding smoothness, create enough points for the closest zoomed in camera setting and you should be fine. Should likely also look into winding direction and how to draw multiple separate objects with a single triangle mesh. Also might want to experiment with the kmMat4PerspectiveProjection function in the CCDirectorIOS that sets up the default 3D projection Cocos2d uses. The min and max zoom values of are set at 0.1f, zeye*2. These can be changed to enable greater zoom ranges i.e. 0.1 and 5000 for the min and max zoom. – Jim Range Aug 04 '12 at 21:33
  • @JimRange know this is an old post, and this may be considered a bump... however as you obviously have experience with creating games using this technique I wondered if you could help me with this problem I'm having: http://stackoverflow.com/questions/13915531/repeating-opengl-es-texture-bound-to-hills-in-cocos2d-2-0 Don't worry if you don't have the time :) but would be nice to get some decent advice! – simonthumper Dec 22 '12 at 16:36