Using brl.json to parse Texture Packer json files

Monkey Forums/Monkey Programming/Using brl.json to parse Texture Packer json files

therevills(Posted 2013) [#1]
Texture Packer outputs the following json:
{"frames": {
    
"frame-abc.png":
{
	"frame": {"x":41,"y":2,"w":256,"h":256},
	"rotated": false,
	"trimmed": false,
	"spriteSourceSize": {"x":0,"y":0,"w":256,"h":256},
	"sourceSize": {"w":256,"h":256}
},
"someframe":
{
	"frame": {"x":2,"y":2,"w":37,"h":382},
	"rotated": false,
	"trimmed": false,
	"spriteSourceSize": {"x":0,"y":0,"w":37,"h":382},
	"sourceSize": {"w":37,"h":382}
}
}
}


Yet I am having a hard time parsing it using brl.json... in fact I don't know where to start!! :(

This is what I've got so far and its not much:
		Local str:String = LoadString("sprites.json")
		Local jso:JsonObject = New JsonObject(str)
		Local sprites:JsonValue = jso.Get("frames")
		Print sprites.ToJson()


This outputs all the frames to the console, but how do I parse those objects to create "sprites"?


therevills(Posted 2013) [#2]
Must have been tired last night:



Still not happy about changing the "objects" to json all the time... and its fugly... but it works...


marksibly(Posted 2013) [#3]
You could use GetData() to retrieve the underlying StringMap<JsonValue>, then iterate through the map, eg:

Local str:=LoadString("sprites.json")
Local jso:=New JsonObject(str)
Local sprs:=JsonObject( jso.Get("frames") )
For Local it:=EachIn sprs.GetData()
   Local key:=it.Key                 'eg: frame-abc.png
   Local spr:=JsonObject( it.Value )
   Local frame:=JsonObject( spr.Get( "frame" ) )
   Print "x,y,w,h="+frame.GetInt( "x" )...etc...
Next


(IMO, frames should really be an array...)

There's an issue if the order of the frames is important, in which case brl.json would need to be modified, eg: a GetOrderedKeys:String[]() method could be added to JsonObject...


therevills(Posted 2013) [#4]
Ah thats a lot nicer! Thanks Mark! And I do agree that Frames should be an array, but its not my format ;)



Oh, just found out the TexturePacker can output two types of JSON, one in Hash format (above) and Array based (below):
{"frames": [

{
	"filename": "axe.png",
	"frame": {"x":2,"y":364,"w":128,"h":126},
	"rotated": true,
	"trimmed": true,
	"spriteSourceSize": {"x":0,"y":1,"w":128,"h":126},
	"sourceSize": {"w":128,"h":128}
},
{
	"filename": "sword.png",
	"frame": {"x":117,"y":199,"w":126,"h":126},
	"rotated": false,
	"trimmed": true,
	"spriteSourceSize": {"x":1,"y":0,"w":126,"h":126},
	"sourceSize": {"w":128,"h":128}
}],
"meta": {
	"app": "http://www.codeandweb.com/texturepacker ",
	"version": "1.0",
	"image": "array.png",
	"format": "RGBA8888",
	"size": {"w":256,"h":542},
	"scale": "1",
	"smartupdate": "$TexturePacker:SmartUpdate:<SNIP>"
}
}



Erik(Posted 2013) [#5]
You don't have to use JSON as an exporter from texturepacker, I prefer simple textfiles.

Put the following in a textfile and save under TexturePacker\bin\exporters\[yourname] to get a simple one line per image file.

{% for sprite in allSprites %}{{sprite.trimmedName}} {{sprite.frameRect.x}} {{sprite.frameRect.y}} {{sprite.frameRect.width}} {{sprite.frameRect.height}} {{sprite.cornerOffset.x}} {{sprite.cornerOffset.y}} {{sprite.untrimmedSize.width}} {{sprite.untrimmedSize.height}} {% if sprite.rotated %}1{% else %}0{% endif %}{% if not forloop.last %}
{% endif %}{% endfor %}


Then copy exporter.xml from another exporter in \exporters\ to your dir and change the name etc in the xml file.
It should have the following values:
<fileExtension>txt</fileExtension>
<supportsTrimming>yes</supportsTrimming>
<supportsRotation>yes</supportsRotation>
<rotationDirection>cw</rotationDirection>
<supportsNPOT>no</supportsNPOT>
<supportsTrimSpriteNames>yes</supportsTrimSpriteNames>
<supportsTextureSubPath>yes</supportsTextureSubPath>

Here's an image class that can load from the above exporter:

Class bbImage

  Field Name:String
  Field Width
  Field Height
  Field OffX
  Field OffY
  Field Rotated? 'If rotated in textureatlas to save space

  Field Img:Image

  Method Draw(atx#,aty#)
    If Rotated Then
      DrawImage(Img, atx+OffX, aty + OffY + Width, 90,1,1)
    Else
      DrawImage(Img, atx+OffX, aty+OffY)
    End
  End

  Function LoadFromTexturePacker:bbImage[](filename:String)
    Local Atlas := LoadImage(filename+".png")

    If Atlas = Null Then
      Error "Can't find ~q"+filename+"~q"
      Return
    End

    Local lines := app.LoadString(filename+".txt").Split("~n")[1..]
    Local result := New List<bbImage>()

    For Local i := Eachin lines
       Local c := i.Split(" ")

       Local bb := New bbImage()
       bb.Name = c[0]
       Local x := Int(c[1])
       Local y := Int(c[2])
       Local w := Int(c[3])
       Local h := Int(c[4])

       bb.Img = Atlas.GrabImage(x,y,w,h)

       bb.OffX   = Int(c[5])
       bb.OffY   = Int(c[6])
       bb.Width = Int(c[7])
       bb.Height = Int(c[8])
       bb.Rotated = Int(c[9]) = 1

       result.AddLast(bb)
    End

    Return result.ToArray()
  End

End



therevills(Posted 2013) [#6]
Thanks Erik, I was also using it to learn how to use the brl.json module :)

One thing with the JSON output from TexturePacker is that it doesn't tell you what rotation to do if the image has been rotated, which is weird...