Using multiple CGLayer objects to draw a flag

Example: Using Multiple CGLayer objects to Draw a Flag

This section shows how to use two CGLayer objects to draw the flag shown in Figure 12-5 onscreen. First you’ll see how to reduce the flag to simple drawing primitives, then you’ll look at the code needed to accomplish the drawing.

Figure 12-5   The result of using layers to draw the United States flag

From the perspective of drawing it onscreen, the flag has three parts:

  • A pattern of red and white stripes. You can reduce the pattern to a single red stripe because, for onscreen drawing, you can assume a white background. You create a single red rectangle, then repeatedly draw the rectangle at various offsets to create the seven red stripes necessary for the U.S. flag. A CGLayer is ideal for repeated drawing. You draw the red rectangle to a CGLayer, then draw the CGLayer onscreen seven times.

  • A blue rectangle. You need the blue rectangle once, so using a CGLayer is of no benefit. When it comes time to draw the blue rectangle, draw it directly onscreen.

  • A pattern of 50 white stars. Like the red stripe, a CGLayer is ideal for drawing the stars. You create a path that outlines a star shape, and then fill the path with white. Draw one star to a CGLayer, then draw the layer 50 times, adjusting the offset each time to get the appropriate spacing.

The code in “Code that uses layers to draw a flag” produces the output shown in Figure 12-5 . A detailed explanation for each numbered line of code appears following the listing. The listing is rather long, so you might want to print the explanation so that you can read it as you look at the code. The myDrawFlag routine is called from within a Cocoa or Carbon application. The application passes a window graphics context and a rectangle that specifies the size of the view associated with the window graphics context.

Note:  Before you call this or any routine that uses CGLayer objects, you must check to make sure that the system is running Mac OS X v10.4 or later and has a graphics card that supports using CGLayer objects.

Listing 12-1   Code that uses layers to draw a flag

void myDrawFlag (CGContextRef context, CGRect* contextRect)
{
    int          i, j,
                 num_six_star_rows = 5,
                 num_five_star_rows = 4;
    float        start_x = 5.0,// 1
                 start_y = 108.0,// 2
                 red_stripe_spacing = 34.0,// 3
                 h_spacing = 26.0,// 4
                 v_spacing = 22.0;// 5
    CGContextRef myLayerContext1,
                 myLayerContext2;
    CGLayerRef   stripeLayer,
                 starLayer;
    CGRect       myBoundingBox,// 6
                 stripeRect,
                 starField;
 // ***** Setting up the primitives *****
    const CGPoint myStarPoints[] = {{ 5, 5},   {10, 15},// 7
                                    {10, 15},  {15, 5},
                                    {15, 5},   {2.5, 11},
                                    {2.5, 11}, {16.5, 11},
                                    {16.5, 11},{5, 5}};
 
    stripeRect  = CGRectMake (0, 0, 400, 17); // stripe// 8
    starField  =  CGRectMake (0, 102, 160, 119); // star field// 9
 
    myBoundingBox = CGRectMake (0, 0, contextRect->size.width, // 10
                                      contextRect->size.height);
 
     // ***** Creating layers and drawing to them *****
    stripeLayer = CGLayerCreateWithContext (context, // 11
                            stripeRect.size, NULL);
    myLayerContext1 = CGLayerGetContext (stripeLayer);// 12
 
    CGContextSetRGBFillColor (myLayerContext1, 1, 0 , 0, 1);// 13
    CGContextFillRect (myLayerContext1, stripeRect);// 14
 
    starLayer = CGLayerCreateWithContext (context,
                            starField.size, NULL);// 15
    myLayerContext2 = CGLayerGetContext (starLayer);// 16
    CGContextSetRGBFillColor (myLayerContext2, 1.0, 1.0, 1.0, 1);// 17
    CGContextAddLines (myLayerContext2, myStarPoints, 10);// 18
    CGContextFillPath (myLayerContext2);    // 19
 
     // ***** Drawing to the window graphics context *****
    CGContextSaveGState(context);    // 20
    for (i=0; i< 7;  i++)   // 21
    {
        CGContextDrawLayerAtPoint (context, CGPointZero, stripeLayer);// 22
        CGContextTranslateCTM (context, 0.0, red_stripe_spacing);// 23
    }
    CGContextRestoreGState(context);// 24
 
    CGContextSetRGBFillColor (context, 0, 0, 0.329, 1.0);// 25
    CGContextFillRect (context, starField);// 26
 
    CGContextSaveGState (context);              // 27
    CGContextTranslateCTM (context, start_x, start_y);      // 28
    for (j=0; j< num_six_star_rows;  j++)   // 29
    {
        for (i=0; i< 6;  i++)
        {
            CGContextDrawLayerAtPoint (context,CGPointZero,
                                            starLayer);// 30
            CGContextTranslateCTM (context, h_spacing, 0);// 31
        }
        CGContextTranslateCTM (context, (-i*h_spacing), v_spacing); // 32
    }
    CGContextRestoreGState(context);
 
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, start_x + h_spacing/2, // 33
                                 start_y + v_spacing/2);
    for (j=0; j< num_five_star_rows;  j++)  // 34
    {
        for (i=0; i< 5;  i++)
        {
        CGContextDrawLayerAtPoint (context, CGPointZero,
                            starLayer);// 35
            CGContextTranslateCTM (context, h_spacing, 0);// 36
        }
        CGContextTranslateCTM (context, (-i*h_spacing), v_spacing);
    }
    CGContextRestoreGState(context);
 
    CGLayerRelease(stripeLayer);// 37
    CGLayerRelease(starLayer);        // 38
}

Here’s what the code does:

  1. Declares a variable for the horizontal location of the first star.

  2. Declares a variable for the vertical location of the first star.

  3. Declares a variable for the spacing between the red stripes on the flag.

  4. Declares a variable for the horizontal spacing between the stars on the flag.

  5. Declares a variable for the vertical spacing between the stars on the flag.

  6. Declares rectangles that specify where to draw the flag to (bounding box), the stripe layer, and the star field.

  7. Declares an array of points that specify the lines that trace out one star.

  8. Creates a rectangle that is the shape of a single stripe.

  9. Creates a rectangle that is the shape of the star field.

  10. Creates a bounding box that is the same size as the window graphics context passed to the myDrawFlag routine.

  11. Creates a layer that is initialized with the window graphics context passed to the myDrawFlag routine.

  12. Gets the graphics context associated with that layer. You’ll use this layer for the stripe drawing.

  13. Sets the fill color to opaque red for the graphics context associated with the stripe layer.

  14. Fills a rectangle that represents one red stripe.

  15. Creates another layer that is initialized with the window graphics context passed to the myDrawFlag routine.

  16. Gets the graphics context associated with that layer. You’ll use this layer for the star drawing.

  17. Sets the fill color to opaque white for the graphics context associated with the star layer.

  18. Adds the 10 lines defined by the myStarPoints array to the context associated with the star layer.

  19. Fills the path, which consists of the 10 lines you just added.

  20. Saves the graphics state of the windows graphics context. You need to do this, because you’ll draw the same stripe repeatedly, but in different locations.

  21. Sets up a loop that iterates 7 times, once for each red stripe on the flag.

  22. Draws the stripe layer (which consists of a single red stripe).

  23. Translates the current transformation matrix so that the origin is positioned at the location where the next red stripe must be drawn.

  24. Restores the graphics state to what is was prior to drawing the stripes.

  25. Sets the fill color to the appropriate shade of blue for the star field. Note that this color has an opacity of 1.0. Although all the colors in this example are opaque, they don’t need to be. You can create nice effects with layered drawing by using partially transparent colors. Recall that an alpha value of 0.0 specifies a transparent color.

  26. Fills the star field rectangle with blue. You draw this rectangle directly to the window graphics context. Don’t use layers if you are drawing something only once.

  27. Saves the graphics state for the window graphics context because you’ll be transforming the CTM to position the stars properly.

  28. Translates the CTM so that the origin lies in the star field, positioned for the first star (left side) in the first (bottom) row.

  29. This and the next for loop sets up the code to repeatedly draw the star layer so the five odd rows on the flag each contain six stars.

  30. Draws the star layer to the window graphics context. Recall that the star layer contains one white star.

  31. Positions the CTM so that the origin is moved to the right in preparation for drawing the next star.

  32. Positions the CTM so that the origin is moved upward in preparation for drawing the next row of stars.

  33. Translates the CTM so that the origin lies in the star field, positioned for the first star (left side) in the second row from the bottom. Note that the even rows are offset with respect to the odd rows.

  34. This and the next for loop sets up the code to repeatedly draw the star layer so the four even rows on the flag each contain five stars.

  35. Draws the star layer to the window graphics context.

  36. Positions the CTM so that the origin is moved to the right in preparation for drawing the next star.

  37. Releases the stripe layer.

  38. Releases the star layer.

1. Define the XML schema: Before recording the location information of multiple objects in a game through serialized XML files, it is necessary to define the XML schema. The schema should define the structure of the XML file, including the tags, attributes, and data types. 2. Serialize the objects: In order to record the location information of multiple objects in a game, the objects must be serialized. Serialization is the process of converting an object into a stream of bytes that can be written to a file. In C#, the serialization process can be achieved using the XMLSerializer class. 3. Create an XML file: After serializing the objects, an XML file must be created to store the location information. The XML file can be created using the XMLTextWriter class. This class allows you to write XML data to a file or stream. 4. Write the serialized objects to the XML file: Once the XML file has been created, the serialized objects can be written to the file. This can be done using the WriteStartElement and WriteEndElement methods of the XMLTextWriter class. These methods allow you to write the start and end tags of the XML data. 5. Save the XML file: After writing the serialized objects to the XML file, the file must be saved. This can be done using the Close method of the XMLTextWriter class. This method closes the file and saves any changes that have been made. 6. Read the XML file: To retrieve the location information of the objects, the XML file must be read. This can be done using the XMLReader class. This class allows you to read the XML data from the file and convert it back into objects. 7. Deserialize the objects: Once the XML data has been read, the objects can be deserialized. Deserialization is the process of converting the XML data back into objects. In C#, the deserialization process can be achieved using the XMLSerializer class. 8. Use the location information: After deserializing the objects, the location information can be used in the game. The location information can be used to position the objects in the game world, or to perform other actions based on their location.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值