TextureRegionFactory from JSON file

  ... the case you feel the need for a new feature or want to submit one.

TextureRegionFactory from JSON file

Postby natypc » Thu Jul 21, 2011 8:07 pm

.
NOTE: for the last version click THIS LINK

Hi!

I've finished a class to facilitate the creation of TextureRegions from a PNG/JSON Texture created with the program TexturePacker like:

Syntax: [ Download ] [ Hide ]
  1.     "frames": { 
  2.         "spr1.png": 
  3.         { 
  4.             "frame": {"x":0,"y":0,"w":200,"h":402}, 
  5.             "rotated": false, 
  6.             "trimmed": false, 
  7.             "spriteSourceSize": {"x":0,"y":0,"w":200,"h":402}, 
  8.             "sourceSize": {"w":200,"h":402} 
  9.         }, 
  10.         "spr2.png": 
  11.         { 
  12.             "frame": {"x":201,"y":259,"w":200,"h":36}, 
  13.             "rotated": false, 
  14.             "trimmed": false, 
  15.             "spriteSourceSize": {"x":0,"y":0,"w":200,"h":36}, 
  16.             "sourceSize": {"w":200,"h":36} 
  17.         }, 
  18.     },  
  19.     "meta": { 
  20.         "app": "http://www.texturepacker.com", 
  21.         "version": "1.0", 
  22.         "image": "sprites.png", 
  23.         "format": "RGBA8888", 
  24.         "size": {"w":512,"h":512} 
  25.     } 


The use is very simple:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. TextureRegionFactoryJSON.setPath("gfx/");
  2. TextureRegionFactoryJSON texjson = TextureRegionFactoryJSON.createFromAsset(this, "sprites.json");
  3. Texture mSprTexture = texjson.createTextureFromPNG(TextureOptions.DEFAULT);
  4.  
  5. //spr1
  6. SpriteExtended spr1 = new SpriteExtended(0, 0, texjson.get("spr1.png"));
  7.  
  8. //spr2
  9. TiledTextureRegion mSpr2TextureRegion = texjson.get("spr2.png").createTiledTextureRegion(4, 1);
  10. AnimatedSprite spr2 = new AnimatedSprite(0, 0, mSpr2TextureRegion);
  11.  
Parsed in 0.012 seconds, using GeSHi 1.0.8.4


I hope you'll find it useful :)

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. import java.io.BufferedReader;
  2. import java.io.InputStreamReader;
  3. import java.util.Iterator;
  4.  
  5. import org.anddev.andengine.opengl.texture.ITexture;
  6. import org.anddev.andengine.opengl.texture.Texture;
  7. import org.anddev.andengine.opengl.texture.TextureOptions;
  8. import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
  9. import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas.BitmapTextureFormat;
  10. import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
  11. import org.anddev.andengine.opengl.texture.region.TextureRegion;
  12. import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
  13. import org.json.JSONException;
  14. import org.json.JSONObject;
  15.  
  16. import android.content.Context;
  17.  
  18. /**
  19.  * (c) 2011 Natalia Pujol
  20.  *
  21.  * @author Natalia Pujol
  22.  */
  23. public class TextureRegionFactoryJSON {
  24.  
  25.         // ===========================================================
  26.         // Constants
  27.         // ===========================================================
  28.  
  29.         // ===========================================================
  30.         // Fields
  31.         // ===========================================================
  32.  
  33.         private static String mPath = "";
  34.  
  35.         private Context mContext;
  36.        
  37.         private String mTextureName;
  38.         private Texture mTexture;
  39.         private BitmapTextureFormat mTextureFormat;
  40.         private int mFormat;
  41.        
  42.         private int mWidth;
  43.         private int mHeight;
  44.  
  45.         private final static Object TexturePackerFormats[][] = {
  46.                 { "RGBA8888".hashCode(), BitmapTextureFormat.RGBA_8888 },
  47.                 { "RGBA5551".hashCode(), BitmapTextureFormat.RGBA_8888 },
  48.                 { "RGBA5555".hashCode(), BitmapTextureFormat.RGBA_8888 },
  49.                 { "RGBA4444".hashCode(), BitmapTextureFormat.RGBA_4444 },
  50.                 { "RGB565".hashCode(), BitmapTextureFormat.RGB_565 },
  51.                 { "Alpha".hashCode(), BitmapTextureFormat.A_8 },
  52.         };
  53.        
  54.         private int mNumItems;
  55.         private TextureJSONItem[] mItems;
  56.        
  57.         // ===========================================================
  58.         // Constructors
  59.         // ===========================================================
  60.  
  61.         public TextureRegionFactoryJSON(Context pContext, String pData) {
  62.                 mContext = pContext;
  63.                 JSONObject json = null;
  64.                 try {
  65.                         json = new JSONObject(pData);
  66.                 } catch (JSONException e) {
  67.                         return;
  68.                 }
  69.                 // Meta
  70.                 JSONObject section = json.optJSONObject("meta");
  71.                 mTextureName = section.optString("image");
  72.                 mFormat = section.optString("format").hashCode();
  73.                 mTextureFormat = BitmapTextureFormat.RGBA_8888;
  74.                 for (int i=0; i<TexturePackerFormats.length; i++) {
  75.                         if (mFormat==(Integer)TexturePackerFormats[i][0]) {
  76.                                 mTextureFormat = (BitmapTextureFormat)TexturePackerFormats[i][1];
  77.                                 break;
  78.                         }
  79.                 }
  80.                 section = section.optJSONObject("size");
  81.                 mWidth = section.optInt("w");
  82.                 mHeight = section.optInt("h");
  83.                
  84.                 // Frames (TextureRegions)
  85.                 section = json.optJSONObject("frames");
  86.                 mNumItems = section.length();
  87.                 mItems = new TextureJSONItem[mNumItems];
  88.                 String name;
  89.                 int i = 0;
  90.                 for (Iterator<String> key = section.keys(); key.hasNext(); i++) {
  91.                         name = key.next();
  92.                         mItems[i] = new TextureJSONItem(name, section.optJSONObject(name));
  93.                 }
  94.         }
  95.        
  96.         public static TextureRegionFactoryJSON createFromAsset(Context context, String filename) {
  97.                 String data = "";
  98.                 try {
  99.                         InputStreamReader reader = new InputStreamReader(context.getAssets().open(mPath+filename), "UTF-8");
  100.                         BufferedReader br = new BufferedReader(reader);
  101.                         String line;
  102.                         while ((line = br.readLine())!=null) data += line;
  103.                         br.close();
  104.                         reader.close();
  105.                 } catch (Exception e) {}
  106.                 return new TextureRegionFactoryJSON(context, data);
  107.         }
  108.        
  109.         // ===========================================================
  110.         // Getter & Setter
  111.         // ===========================================================
  112.  
  113.         public Texture getTexture() {
  114.                 return mTexture;
  115.         }
  116.        
  117.         public static void setPath(String path) {
  118.                 mPath = path;
  119.         }
  120.        
  121.         public static String getPath() {
  122.                 return mPath;
  123.         }
  124.        
  125.         public int getWidth() {
  126.                 return mWidth;
  127.         }
  128.        
  129.         public int getHeight() {
  130.                 return mHeight;
  131.         }
  132.        
  133.         public int getNumItems() {
  134.                 return mNumItems;
  135.         }
  136.        
  137.         public TextureJSONItem get(int idx) {
  138.                 return mItems[idx];
  139.         }
  140.        
  141.         public TextureJSONItem get(String name) {
  142.                 int id = name.hashCode();
  143.                 for (int i=0; i<mNumItems; i++) {
  144.                         if (mItems[i].nameid==id) return mItems[i];
  145.                 }
  146.                 return null;
  147.         }
  148.        
  149.         // ===========================================================
  150.         // Methods
  151.         // ===========================================================
  152.  
  153.         public Texture createTextureFromPNG(TextureOptions pTextOpt) {
  154.                 mTexture = new BitmapTextureAtlas(mWidth, mHeight, mTextureFormat, pTextOpt);
  155.                 BitmapTextureAtlasTextureRegionFactory.createFromAsset((BitmapTextureAtlas)mTexture, mContext, mPath+mTextureName, 0, 0);
  156.                 return mTexture;
  157.         }
  158.        
  159.         // ===========================================================
  160.         // Inner and Anonymous Classes
  161.         // ===========================================================
  162.        
  163.         public class TextureJSONItem {
  164.  
  165.                 public int nameid;
  166.                 public boolean rotated;
  167.                 public boolean trimmed;
  168.                 public int pX;
  169.                 public int pY;
  170.                 public int width;
  171.                 public int height;
  172.                 public int offsetX;
  173.                 public int offsetY;
  174.                 public int trimWidth;
  175.                 public int trimHeight;
  176.                
  177.                 public TextureJSONItem(String name, boolean rot, boolean trim, int x, int y, int w, int h) {
  178.                         nameid = name.hashCode();
  179.                         rotated = rot;
  180.                         trimmed = trim;
  181.                         pX = x;
  182.                         pY = y;
  183.                         width = w;
  184.                         height = h;
  185.                 }
  186.  
  187.                 public TextureJSONItem(String name, JSONObject json) {
  188.                         nameid = name.hashCode();
  189.                         rotated = json.optBoolean("rotated");
  190.                         trimmed = json.optBoolean("trimmed");
  191.                         // sourceSize (not-trimmed sprite size)
  192.                         JSONObject item = json.optJSONObject("sourceSize");
  193.                         width = item.optInt("w");
  194.                         height = item.optInt("h");
  195.                         // frame (size/location in texture of real sprite)
  196.                         item = json.optJSONObject("frame");
  197.                         pX = item.optInt("x");
  198.                         pY = item.optInt("y");
  199.                         trimWidth = item.optInt("w");
  200.                         trimHeight = item.optInt("h");
  201.                         // frame (size/location in not-trimmed sprite size)
  202.                         item = json.optJSONObject("spriteSourceSize");
  203.                         offsetX = item.optInt("x");
  204.                         offsetY = item.optInt("y");
  205.                 }
  206.  
  207.                 public TextureRegion createTextureRegion() {
  208.                         return new TextureRegion(mTexture, pX, pY, rotated?trimHeight:trimWidth, rotated?trimWidth:trimHeight);
  209.                 }
  210.  
  211.                 public TextureRegion createTextureRegion(ITexture pTexture) {
  212.                         return new TextureRegion(pTexture, pX, pY, rotated?trimHeight:trimWidth, rotated?trimWidth:trimHeight);
  213.                 }
  214.  
  215.                 public TiledTextureRegion createTiledTextureRegion(int pTileColums, int pTileRows) {
  216.                         return new TiledTextureRegion(mTexture, pX, pY, trimWidth, trimHeight, pTileColums, pTileRows);
  217.                 }
  218.  
  219.                 public TiledTextureRegion createTiledTextureRegion(ITexture pTexture, int pTileColums, int pTileRows) {
  220.                         return new TiledTextureRegion(pTexture, pX, pY, trimWidth, trimHeight, pTileColums, pTileRows);
  221.                 }
  222.                
  223.         }
  224.        
  225. }
  226.  
Parsed in 0.023 seconds, using GeSHi 1.0.8.4


...and the SpriteExtended class to support Sprites created from trimmed/rotated TextureRegions.
I'm sure this class can be really improved... yours improvements are welcomed:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. import org.anddev.andengine.entity.primitive.Rectangle;
  2. import org.anddev.andengine.entity.shape.IShape;
  3. import org.anddev.andengine.entity.sprite.Sprite;
  4. import org.anddev.andengine.opengl.texture.ITexture;
  5. import org.anddev.andengine.opengl.texture.region.TextureRegion;
  6. import org.natygames.utils.TextureRegionFactoryJSON.TextureJSONItem;
  7.  
  8. /**
  9.  * (c) 2011 Natalia Pujol
  10.  *
  11.  * @author Natalia Pujol
  12.  */
  13. public class SpriteExtended extends Rectangle {
  14.        
  15.         // ===========================================================
  16.         // Fields
  17.         // ===========================================================
  18.        
  19.         protected boolean regionRotated;
  20.         protected int regionOffsetX;
  21.         protected int regionOffsetY;
  22.         protected int regionWidth;
  23.         protected int regionHeight;
  24.  
  25.         protected float factorX;
  26.         protected float factorY;
  27.        
  28.         protected Sprite mSpr;
  29.        
  30.         // ===========================================================
  31.         // Constructors
  32.         // ===========================================================
  33.        
  34.         public SpriteExtended(float pX, float pY, TextureJSONItem json) {
  35.                 this(pX, pY, json.width, json.height, json.offsetX, json.offsetY, json.trimWidth, json.trimHeight, json.rotated, json.createTextureRegion());
  36.         }
  37.        
  38.         public SpriteExtended(float pX, float pY, TextureJSONItem json, ITexture pTexture) {
  39.                 this(pX, pY, json.width, json.height, json.offsetX, json.offsetY, json.trimWidth, json.trimHeight, json.rotated, json.createTextureRegion(pTexture));
  40.         }
  41.        
  42.         public SpriteExtended(float pX, float pY, float sprWidth, float sprHeight, int regionOffsetX, int regionOffsetY, int regionWidth, int regionHeight, boolean regionRotated, TextureRegion pTexReg) {
  43.                 super(pX, pY, sprWidth, sprHeight);
  44.                 super.setColor(0, 0, 0, 0);
  45.                 this.regionRotated = regionRotated;
  46.                 this.regionOffsetX = regionOffsetX;
  47.                 this.regionOffsetY = regionOffsetY;
  48.                 this.regionWidth = regionWidth;
  49.                 this.regionHeight = regionHeight;
  50.                 factorX = factorY = 1f;
  51.                 if (regionRotated) {
  52.                         mSpr = new Sprite(regionOffsetX, regionOffsetY, regionHeight, regionWidth, pTexReg);
  53.                         mSpr.setRotationCenter(regionHeight*0.5f, regionHeight*0.5f);
  54.                         mSpr.setRotation(-90f);
  55.                 } else {
  56.                         mSpr = new Sprite(regionOffsetX, regionOffsetY, regionWidth, regionHeight, pTexReg);
  57.                 }
  58.                 attachChild(mSpr);
  59.         }
  60.        
  61.         // ===========================================================
  62.         // Getter & Setter
  63.         // ===========================================================
  64.  
  65.         //
  66.         // from BaseSprite
  67.         //
  68.        
  69.         @Override
  70.     public boolean collidesWith(final IShape pOtherShape) {
  71.                 return mSpr.collidesWith(pOtherShape);
  72.         }
  73.        
  74.         public TextureRegion getTextureRegion() {
  75.                 return mSpr.getTextureRegion();
  76.         }
  77.        
  78.         public void setFlippedHorizontal(boolean pFlippedHorizontal) {
  79.                 if (regionRotated) {
  80.                         mSpr.setFlippedVertical(pFlippedHorizontal);
  81.                 } else {
  82.                         mSpr.setFlippedHorizontal(pFlippedHorizontal);
  83.                 }
  84.                 if (pFlippedHorizontal) {
  85.                         mSpr.setPosition((mBaseWidth-regionOffsetX-regionWidth)*factorX, regionOffsetY*factorY);
  86.                 } else {
  87.                         mSpr.setPosition(regionOffsetX*factorX, regionOffsetY*factorY);
  88.                 }
  89.         }
  90.  
  91.         public void setFlippedVertical(boolean pFlippedVertical) {
  92.                 if (regionRotated) {
  93.                         mSpr.setFlippedHorizontal(pFlippedVertical);
  94.                 } else {
  95.                         mSpr.setFlippedVertical(pFlippedVertical);
  96.                 }
  97.                 if (pFlippedVertical) {
  98.                         mSpr.setPosition(regionOffsetX*factorX, (mBaseHeight-regionOffsetY-regionHeight)*factorY);
  99.                 } else {
  100.                         mSpr.setPosition(regionOffsetX*factorX, regionOffsetY*factorY);
  101.                 }
  102.         }
  103.  
  104.         //
  105.         // from RectangularShape
  106.         //
  107.        
  108.         @Override
  109.         public void setBaseSize() {
  110.                 super.setBaseSize();
  111.                 factorX = factorY = 1f;
  112.                 setWidth(mBaseWidth);
  113.                 setHeight(mBaseHeight);
  114.         }
  115.  
  116.         @Override
  117.         public void setAlpha(float pAlpha) {
  118.                 mSpr.setAlpha(pAlpha);
  119.         }
  120.  
  121.         @Override
  122.         public void setColor(float pRed, float pGreen, float pBlue) {
  123.                 mSpr.setColor(pRed, pGreen, pBlue);
  124.         }
  125.  
  126.         @Override
  127.         public void setColor(float pRed, float pGreen, float pBlue, float pAlpha) {
  128.                 mSpr.setColor(pRed, pGreen, pBlue, pAlpha);
  129.         }
  130.  
  131.         @Override
  132.         protected void onUpdateVertexBuffer() {
  133.         }
  134. }
  135.  
Parsed in 0.017 seconds, using GeSHi 1.0.8.4
Last edited by natypc on Tue Aug 09, 2011 2:25 pm, edited 7 times in total.
natypc
 
Posts: 18
Joined: Thu Jul 21, 2011 2:04 am

Re: TextureRegionFactory from JSON file

Postby drjava72 » Fri Jul 22, 2011 1:52 pm

very nice. Should a included in andEngine. I think it should be posted under Tutorial section with subject [Tutorial} create TextureRegionFactory from JSON file
Best Regards,
drJava72
drjava72
 
Posts: 287
Joined: Fri Apr 29, 2011 8:03 am

Re: TextureRegionFactory from JSON file

Postby natypc » Thu Jul 28, 2011 8:29 am

I'm extending the class to support "rotated" and "trimmed" and allow read Sprites rotated and/or trimmed in the texture to avoid transparent regions and improve texture size.

Is done, but the only way I found to do this is creating a transparent Rectangle with the original Sprite size and attach them the trimmed/rotated Sprite with a OffsetX,Y and the rotation if exists.

It works and look nice! but... there is any more optimized way to do this using any other AndEngine class instead Rectangle like sprite wrapper?
natypc
 
Posts: 18
Joined: Thu Jul 21, 2011 2:04 am

Re: TextureRegionFactory from JSON file

Postby natypc » Fri Jul 29, 2011 11:31 pm

Note: I've improved TextureRegionFactoryJSON and added a SpriteExtended class to easily create Sprites from trimmed/rotated TextureRegions. The code are at first message in this post.
The dimensions of these Sprites are the original image dimensions before trim, but with less texture memory requirements due to transparent pixels trimming.

Image
natypc
 
Posts: 18
Joined: Thu Jul 21, 2011 2:04 am

Re: TextureRegionFactory from JSON file

Postby borrrden » Mon Aug 01, 2011 12:07 pm

Seriously well done man! Lack of this feature was one of the few things keeping me from going forward with AndEngine instead of LibGDX. Thanks a million.
borrrden
 
Posts: 8
Joined: Mon Aug 01, 2011 12:06 pm

Re: TextureRegionFactory from JSON file

Postby natypc » Mon Aug 01, 2011 12:34 pm

I'm glad you have found this useful... Thanks :)
natypc
 
Posts: 18
Joined: Thu Jul 21, 2011 2:04 am

Re: TextureRegionFactory from JSON file

Postby Nicolas Gramlich » Tue Aug 02, 2011 2:54 am

Hi,

I've been in contact with the developer of the TexturePacker tool and we'll get a format (beta already there internally) that will perfectly fit our spoiled Android needs (compile-time safety of accessing the textureregion). See: updates/andenginetexturepackerextension-t4334.html

I have an idea to implement rotation completely transparently (subclassing generated TextureRegions), but trimming will be harder to implement transparently and there might be no way around subclassing Sprite, like you did =/

Best Regards,
Nicolas
Nicolas Gramlich
Site Admin
 
Posts: 1734
Joined: Mon Jun 07, 2010 6:20 pm
Location: Schriesheim, Germany

Re: TextureRegionFactory from JSON file

Postby borrrden » Fri Aug 05, 2011 11:12 am

I have been trying for hours but I can't get it to stop crashing....null pointer exceptions everywhere :( I really hope this new TexturePacker format comes soon with trimming.

EDIT: Oops I didnt realize how important that createTextureFromPng line was. It crashed because I left it out....but the SpriteExtended are not working as I expected. They are just showing white squares for everything :(. Any ideas ?
borrrden
 
Posts: 8
Joined: Mon Aug 01, 2011 12:06 pm

Re: TextureRegionFactory from JSON file

Postby natypc » Fri Aug 05, 2011 11:41 am

Hi borrrden

Be sure you copied the line:
super.setColor(0, 0, 0, 0);
in the SpriteExtended constructor. This prevents shows the superclass white square.

Anyway, could you write the code where you create the SpriteExtended?

PS: be careful, SpriteExtended is not production code, but a concept proposal.
natypc
 
Posts: 18
Joined: Thu Jul 21, 2011 2:04 am

Re: TextureRegionFactory from JSON file

Postby borrrden » Sat Aug 06, 2011 6:47 am

I think it comes from my inexperience with andengine. I never actually loaded the texture.....I didn't know that you had to explicitly do that. I'm getting my bearings bit by bit, but I can't wait for the TexturePacker format. I've been spoiled by Sparrow (iOS) and its perfect integration with TexturePacker. Once that is done I'll surely be able to push out the port to Android.
borrrden
 
Posts: 8
Joined: Mon Aug 01, 2011 12:06 pm

Next

Return to Features

Who is online

Users browsing this forum: No registered users and 3 guests