17.5 Painting a Layer


17.5 Painting a Layer

A scene layer can now manage the scene objects attached to it. In addition, it will need to draw the scene objects as its draw method is called. It does this by cycling through all its attached objects and determining whether each one is visible. If so, the object can be drawn; otherwise it can be omitted. When called to draw an object, the scene layer must ensure the contents of the sprite is drawn onto the layer's surface. In the previous section we demonstrated how to draw a surface or sprite to the display. The next section examines how a surface or sprite can be drawn to another surface.

17.5.1 Painting to a Surface

In ClanLib, every sprite or surface object has a draw method and its purpose is to draw images to the display. In addition to this, however, surfaces and sprites can be drawn onto other surfaces and sprites, much like copy and paste works between images in a photo program. Given two surfaces X and Y, X can be copied and pasted onto Y at a specific (x, y) location on Y. It follows then that upon X being pasted onto Y, the image data from X that was pasted will not be visible on screen until surface Y is subsequently drawn.

To draw a surface or sprite onto another surface or sprite, a CL_Canvas object first needs to be created. A canvas represents a drawing surface, or the actual rectangle of pixels that a surface is composed of. Furthermore, the canvas needs to be associated with the destination surface or sprite, or the actual canvas that will receive the copied pixels. Then, any surface or sprite may be drawn, and the draw method accepts as an optional parameter a provided canvas to draw upon. Consider the following code:

      CL_Surface surface_X("1.png");      CL_Surface surface_Y("2.png");      CL_Canvas canvas;      canvas.select_surface(surface_X);      surface_Y.draw(5, 5, canvas.get_gc());      canvas.sync_surface(); 

17.5.2 CL_SceneLayer-Painting

The actual draw function of the scene layer uses many of the methods discussed in the previous sections. To draw all scene objects, the layer must loop through all scene objects and draw each visible object. The full code of this function can be seen below.

      //void composite(CL_Rect *Rect)      //Renders all sprites onto the layer surface      //Called each draw      void CL_SceneLayer::composite(CL_Rect *Rect)      {      m_Canvas->get_gc()->clear(CL_Color(0, 0, 0, 0));      //Cycle through all objects to draw      for(unsigned int i = 0; i < m_Objects.size(); i++)      {         CL_SceneObject *Object = m_Objects[i];         if(Object->getVisible()) //If object visible         {         //Test for cull         CL_Rect LayerRect(0, 0, get_width(), get_height());         //Relative layer dimensions         CL_Rect CL_SpriteRect((int) Object->getX(), (int) Object->getY(),         (int) (Object->getX() + Object->get_width()),         (int) (Object->getY() + Object->get_height()));            if(CL_SpriteRect.is_overlapped(LayerRect)) //If sprite inside layer            {               //Draw object               Object->draw(Rect->left + Object->getX(),                       Rect->top + Object->getY(),                       m_Canvas->get_gc());            }         }      }         m_Canvas->sync_surface();      } 

Note 

Notice how the relative x and y coordinates of the scene object are added onto the existing left and top coordinates of the rectangle, in accordance with absolute and relative positioning. This was discussed earlier in this chapter.

17.5.3 CL_SceneManager-Structure

As mentioned in previous sections, it is the role of the scene manager to coordinate all of the events in a scene. A scene manager should maintain a collection of layers, and it will naturally do this using the same std::vector method as employed by layers to maintain a collection of scene objects. This class will have a createLayer method and an addLayer method to create and add a new layer, as shown below. As the scene manager is drawn it will cycle through its list of layers, draw each visible one, and those layers in turn will cycle through their list of objects and draw them to the surface.

      CL_SceneLayer* CL_SceneManager::createLayer(float Width, float height,                     CL_PixelFormat Format, float Pitch, std::string Name)      {         CL_PixelBuffer Buffer((int) Width, (int) height, (int) Pitch, Format,                               NULL);         CL_SceneLayer *Layer = new CL_SceneLayer(Buffer, Name);         return Layer;      }      void addLayer(CL_SceneLayer* Layer) {m_Layers.push_back(Layer);} 

In addition to the issues of drawing, as addressed, a scene manager also needs to load its data from and save its data to XML files.

17.5.4 CL_SceneManager-XML

A scene consists of layers, objects, and their relationships. Objects are children of layers, and layers are children of the scene, and all of these exist in the same coordinate space. This is the structure of the scene, and it is possible to define and express this structure in XML. The scene manager can load and configure a scene according to this XML file. This idea opens up some interesting possibilities such as level designers, where people can create and define a level and then save this information to XML where it can be loaded by the scene manager in the game. Before examining how this file is to be loaded and processed, it is first necessary to see the structure of the XML scene file, how it is written, and the kinds of elements it contains. Consider the following simple file:

      <scene>      <layers>      <layer name="layer0" visible="true" posx="500" posy="900" width="512"             height="512">      <sprite name="Game/Sprite01" posx="0" posy="0" visible="true" />      <sprite name="Game/Sprite02" posx="100" posy="50" visible="true" />      </layer>      <layer name="layer1" visible="true" posx="500" posy="900" width="512"             height="512">      <sprite name="Game/Sprite03" posx="0" posy="100" visible="true" />      </layer>      </layers>      </scene> 

Following are descriptions of the various scene elements.

  • <scene>-This is the root tag; the ultimate parent. Every other element of the scene will be a child of this node. It does not contain any other properties.

  • <layers>-This tag marks the beginning of a layer list. All the child nodes of this element will be layers.

  • <layer>-Defines a single scene layer. This tag has several attributes that correspond to properties of a layer: name, visible, posx, posy, width, and height.

  • <sprite>-Each layer may contain many sprite children. Each child is a sprite of the containing layer. Each sprite may have several attributes: name (corresponds to the sprite name in the resource XML files), posx, posy, and visible.

17.5.5 CL_SceneManager-Load from XML

The XML scene file can define a list of layers, properties for each layer, and each of the scene objects a layer may contain. Each scene object has a reference to a sprite in a resource file that defines the standard properties for sprites, as discussed in the previous chapter. The scene manager can now be given a method to load data from an XML file with a specified file name. First, all layers must be enumerated and a scene layer created for each layer element in XML, and consequently, for each scene object found in the XML file, a scene object must be created in the game and added to the appropriate layer. The following function does this, and is likely to be the longest C++ function demonstrated in this book.

      //void loadFromXMLFile(std::string FileName)      //Loads the scene from an XML file      //Requires a valid m_ResourceManager if sprites are to be loaded      void CL_SceneManager::loadFromXMLFile(std::string FileName)      {      CL_DomDocument document;      document.load(new CL_InputSource_File(FileName), true, true);      CL_DomElement element = document.get_document_element(); //Get Root Element      m_SceneName = element.get_attribute("name", "");      CL_DomNodeList LayerRootList = element.get_elements_by_tag_name("layers");         if(LayerRootList.get_length() > 0)         {             CL_DomNode LayerRootNode = LayerRootList.item(0);             CL_DomNodeList LayerList = LayerRootNode.to_element().get_elements_                                        by_tag_name("layer");             if(LayerList.get_length() > 0) //if there is one layer or more             {                for(int i=0; i < LayerList.get_length(); i++)             {                CL_DomElement LayerElement = LayerList.item(i).to_element();                std::string Name = LayerElement.get_attribute("name", "");                float PosX, PosY, Width, Height;                bool LayerVisible = true;                if(LayerElement.get_attribute("visible", "true") != "true")                   LayerVisible = false;                PosX = CL_String::to_float(LayerElement.get_attribute("posx",                                           "0"));                PosY = CL_String::to_float(LayerElement.get_attribute("posy",                                           "0"));                Width = CL_String::to_float(LayerElement.get_attribute("width",                                            "0"));                Height = CL_String::to_float(LayerElement.get_attribute("height",                                             "0"));                CL_SceneLayer *Layer = createLayer(Width, Height,                                       CL_PixelFormat::rgba8888, Width*4, Name);                if(m_ResourceManager) //If resource manager is valid to load                                      //layer sprites                {                   CL_DomNodeList ObjectList = LayerElement.get_elements_by_tag_                                               name("sprite"); //Get Sprite List                   if(ObjectList.get_length() > 0)                   {                      for(int j=0; j < ObjectList.get_length(); j++)                      {                          CL_DomElement ObjectElement = ObjectList.item(j).to_                                                        element();                           std::string SpriteName = ObjectElement.get_                                                    attribute("name", "");                           float ObjectPosX, ObjectPosY;                           bool ObjectVisible = true;                           if(ObjectElement.get_attribute("visible", "true")                                                          != "true")                              ObjectVisible = false;                           ObjectPosX = CL_String::to_float(ObjectElement.get_                                                  attribute("posx", "0"));                           ObjectPosY = CL_String::to_float(ObjectElement.get_                                                  attribute("posy", "0"));                           CL_SceneObject* Object = createSceneObject(SpriteName,                                                    m_ResourceManager,                                            ObjectPosX, ObjectPosY, ObjectVisible);                           Layer->attachObject(Object);                      }                   }                }                addLayer(Layer);              }           }         }      } 




Introduction to Game Programming with C++
Introduction to Game Programming with C++ (Wordware Game Developers Library)
ISBN: 1598220322
EAN: 2147483647
Year: 2007
Pages: 225
Authors: Alan Thorn

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net