Make Texture unpacker with cocos2d-x

Source: Internet
Author: User

Make Texture unpacker with cocos2d-x
Make Texture unpacker with cocos2d-x

That is, unpacker.
Many texture maps can be found in most game packages. They are basically made using texture packer and contain plist files and png images.
If there are few small pictures, you can find the name in plist. If there are hundreds of small pictures, it will be crazy. So today I used the cocos2d-x engine to make a large texture diagram into a small graph tool.

1. parse the plist File

The SpriteFrameCache class implements the logic of parsing plist textures in the cocos2d-x engine. After SpriteFrameCache parses plistMap ::_spriteFrames Store these small images. Since the thumbnail is on this page, can we save it to a file ~

The SpriteFrameCache class does not provide an interface for obtaining _ spriteFrames. Let's change the SpriteFrameCache class and provide an interface for obtaining this member:

const Map
  
   & SpriteFrameCache::getSpriteframes(){    return _spriteFrames;}
  
2. generate an image

SpriteFrame is obtained from SpriteFrameCache, and SpriteFrame cannot be saved directly. Therefore, we need to render it to a texture and save it.

1) render SpriteFrame into a texture

Since the rendering method in cocos3.x has been. the method in Version x is different (use the rendering command instead of 2. directly rendering in Version x), so pay attention to the following when generating the texture:

Sprite* pSp = Sprite::createWithSpriteFrame(pSpriteFrame /*one sprite frame*/);RenderTexture* texture = RenderTexture::create(pSp->getContentSize().width, pSp->getContentSize().height);texture->setName(m_savePath + tempBuf);texture->begin();pSp->setPosition(pSp->getContentSize()/2); //--- be carefulpSp->visit();texture->end();

The above Code only adds the command to render the texture. When the texture is actually rendered in the next frame, add a schedule and save the texture as an image in the next frame.

2) save as image
Image * image = texture-> newImage (true); // A textureif (image) {image-> saveToFile ("filename.png", false) rendered by frame );} CC_SAFE_DELETE (image );

In fact, the RenderTexture class provides the saveToFile interface. Why didn't it be called directly? This interface saves the image to the doc directory. I want to save it to another disk on win32.

3. Remove invalid Images

After adding an encryption operation when creating a texture Gallery, many invalid images will be parsed in the plist file (for example, the width and height are only 1 pixel, multiple identical images). Obviously, there are only 10 valid images and dozens of images after resolution.

1) Remove frames with only one pixel in width and height

Configuration in plist:


  
   1002_effup/0000
  
      
   
    frame
       
   
    {{440,56},{1,1}}
       
   
    offset
       
   
    {-479.5,319.5}
       
   
    rotated
       
       
    
     sourceColorRect
        
    
     {{0,0},{1,1}}
        
    
     sourceSize
        
    
     {960,640}
    
   
  
  
   1002_effup/0001
  
      
   
    frame
       
   
    {{440,56},{1,1}}
       
   
    offset
       
   
    {-479.5,319.5}
       
   
    rotated
       
       
    
     sourceColorRect
        
    
     {{0,0},{1,1}}
        
    
     sourceSize
        
    
     {960,640}
    
   
  

The width and height of these two frames are 1 pixel, Which is useless for parsing, so we need to remove them.

2) Remove duplicate Images

Configuration in plist:


  
   1002_effup/0010
  
      
   
    frame
       
   
    {{440,56},{102,88}}
       
   
    offset
       
   
    {5,7}
       
   
    rotated
       
       
    
     sourceColorRect
        
    
     {{363,355},{212,50}}
        
    
     sourceSize
        
    
     {960,640}
    
   
  
  
   1002_effup/0093
  
      
   
    frame
       
   
    {{440,56},{102,88}}
       
   
    offset
       
   
    {5,7}
       
   
    rotated
       
       
    
     sourceColorRect
        
    
     {{363,355},{212,50}}
        
    
     sourceSize
        
    
     {960,640}
    
   
  

As shown above, except for the frame name, all other fields are the same. Save one image.

So how to implement it?
Since the names are different and the others are the same, we will use other data to generate a key. Every time a frame is saved, we will cache its key. Later, we will find that the same key is discarded directly.

Map
  
   
FramesMap = SpriteFrameCache: getInstance ()-> getSpriteframes (); for (Map
   
    
: Const_iterator itor = framesMap. begin (); itor! = FramesMap. end (); ++ itor) {SpriteFrame * frame = itor-> second; GLuint textName = frame-> getTexture ()-> getName (); const Rect & rect = frame-> getRectInPixels (); bool isRotate = frame-> isRotated (); const Vec2 & offset = frame-> getOffsetInPixels (); const Size & origSize = frame-> getOriginalSizeInPixels (); // Remove invalid images that are too small (after encryption? Plist will generate many invalid images) // # define INVALID_IMAGE_WIDTH 2 if (rect. size. width <= INVALID_IMAGE_WIDTH & rect. size. height <= INVALID_IMAGE_HEIGHT) {continue;} // key --- Remove duplicate images (after encryption? Plist will have many repeated images) sprintf (fileKeyBuf, "% d _ %. 1f %. 1f %. 1f %. 1f _ % s _ %. 1f %. 1f _ %. 1f %. 1f ", textName, rect. origin. x, rect. origin. y, rect. size. width, rect. size. height, isRotate? "1": "0", offset. x, offset. y, origSize. width, origSize. height); if (m_textureList.find (fileKeyBuf )! = M_textureList.end () {continue;} Sprite * pSp = Sprite: createWithSpriteFrame (itor-> second); RenderTexture * texture = RenderTexture: create (pSp-> getContentSize (). width, pSp-> getContentSize (). height); texture-> setName (itor-> first + ". png "); texture-> begin (); pSp-> setPosition (pSp-> getContentSize ()/2); // --- be careful pSp-> visit (); texture-> end (); m_textureList.insert (fileKeyBuf, texture); ++ m_iFramesCount ;}
   
  
4. Rename in order

After the third step (deleting invalid or redundant images) is completed, each frame is not consecutive.

For example, after frame0001.pngis passed, frame0008.png

When we save the image, we need to rename each frame, use m_iFramesCount to record the number of frames currently, and then name them accordingly.
Note that
for (Map ::const_iterator itor = framesMap.begin(); itor != framesMap.end(); ++itor)
Sort the framesMap before traversing.

5. Description

This function has been encapsulated as a class and put it on github. you can clone it by yourself.
Https://github.com/SongCF/TextureUnpacker
Usage:

PlistTool *tool = new PlistTool();std::vector
  
    vec;vec.push_back("Enemy.plist");vec.push_back("1001_effup.plist");tool->addUnpackList(vec);tool->startUnpack([](){    MessageBox("unpack finished", "info");});
  

In this way, two folders are generated in the current directory to store the small images that are extracted from the two plist packages.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.