1 module prova.graphics.sprites.asespritesheet;
2 
3 import prova.graphics,
4        std.json,
5        std.file,
6        std.path;
7 
8 /// Uses sprite sheets generated from Aseprite
9 class AseSpriteSheet : SpriteSheet
10 {
11   private static SpriteSheet[string] sheetCache;
12 
13   /**
14    * JSON file should have the same name and be in the same folder
15    * 
16    * Params:
17    *   path = Path of the image file
18    */
19   this(string path)
20   {
21     SpriteSheet cachedSheet;
22     cachedSheet = path in sheetCache ? sheetCache[path] : cacheFile(path);
23 
24     frames = cachedSheet.frames;
25     animations = cachedSheet.animations;
26     texture = cachedSheet.texture;
27   }
28 
29   ///
30   static SpriteSheet cacheFile(string path)
31   {
32     string jsonPath = stripExtension(path) ~ ".json";
33     string jsonString = readText(jsonPath);
34     JSONValue json = parseJSON(jsonString);
35 
36     JSONValue framesObject = json["frames"];
37     JSONValue metaObject = json["meta"].object;
38     JSONValue frameTagsObject = metaObject["frameTags"];
39 
40     SpriteSheet sheet = new SpriteSheet();
41     sheet.frames = getFrames(framesObject);
42     sheet.animations = getAnimations(frameTagsObject, sheet.frames);
43     sheet.texture = Texture.fetch(path);
44 
45     sheetCache[path] = sheet;
46 
47     return sheet;
48   }
49 
50   private static SpriteFrame[] getFrames(JSONValue framesObject)
51   {
52     SpriteFrame[] frames;
53 
54     if(framesObject.type != JSON_TYPE.ARRAY)
55       throw new Exception("\"frames\" should be an array");
56 
57     foreach(JSONValue frameObject; framesObject.array)
58       frames ~= readFrame(frameObject);
59 
60     return frames;
61   }
62 
63   private static SpriteFrame readFrame(JSONValue frameObject)
64   {
65     SpriteFrame frame;
66 
67     JSONValue clipObject = frameObject["frame"];
68 
69     frame.clip.left = clipObject["x"].integer;
70     frame.clip.top = clipObject["y"].integer;
71     frame.clip.width = clipObject["w"].integer;
72     frame.clip.height = clipObject["h"].integer;
73 
74     frame.duration = frameObject["duration"].integer / 1000f;
75 
76     return frame;
77   }
78 
79   private static SpriteAnimation[string] getAnimations(JSONValue frameTagsObject, SpriteFrame[] frames)
80   {
81     SpriteAnimation[string] animations;
82 
83     foreach(JSONValue value; frameTagsObject.array)
84     {
85       string name = value["name"].str;
86       long start = value["from"].integer;
87       long end = value["to"].integer + 1;
88 
89       animations[name] = new SpriteAnimation(name, frames[start .. end]);
90     }
91 
92     return animations;
93   }
94 }