Added constants for tile_width and tile_height.
[supertux.git] / tools / tilemanager / TileSet.cs
1 using System;
2 using System.IO;
3 using System.Collections;
4 using System.Collections.Generic;
5 using Lisp;
6
7 public class TileGroup {
8     public string Name;
9     public ArrayList Tiles = new ArrayList();
10
11     public void Write(LispWriter writer) {
12         writer.StartList("tilegroup");
13
14         writer.Write("name", Name);
15         writer.Write("tiles", Tiles);
16
17         writer.EndList("tilegroup");
18     }
19
20     public void Parse(Lisp.Parser parser) {
21         int d = parser.Depth;
22         while(parser.Parse() && parser.Depth >= d) {
23             if(parser.Depth == d+1) {
24                 if(parser.Type != Parser.LispType.SYMBOL)
25                     throw new Exception("expected SYMBOL at supertux-tiles level, but got \"" + parser.StringValue + "\"");
26                 string symbol = parser.SymbolValue;
27                 parser.Parse();
28                 switch(symbol) {
29                     case "name":
30                         Name = parser.StringValue;
31                         break;
32                     case "tiles":
33                         do {
34                           Tiles.Add(parser.IntegerValue);
35                         } while(parser.Parse()
36                                 && parser.Type == Parser.LispType.INTEGER);
37                         break;
38                     default:
39                         Console.WriteLine("Unknown section " + symbol);
40                         break;
41                 }
42             }
43         }
44     }
45 }
46
47 public class TileSet {
48     public const int TILE_WIDTH = 32;
49     public const int TILE_HEIGHT = 32;
50
51     private bool tooNew = false;
52
53     /// <summary>Whether version of tileset file is too new</summary>
54     public bool TooNew {
55         get {
56                 return tooNew;
57         }
58     }
59
60     public ArrayList Tiles = new ArrayList();
61     public ArrayList TileGroups = new ArrayList();
62
63     public void Write(string filename) {
64         FileStream fs = new FileStream(filename, FileMode.Create);
65
66         TextWriter tw = new StreamWriter(fs);
67         LispWriter writer = new LispWriter(tw);
68
69         writer.WriteComment("Generated by tiler");
70         writer.StartList("supertux-tiles");
71         foreach(TileGroup tilegroup in TileGroups) {
72             tilegroup.Write(writer);
73         }
74         foreach(Tile tile in Tiles) {
75             if(tile == null)
76                 continue;
77             if(tile.ID >= 0)
78                 tile.Write(writer);
79         }
80         writer.EndList("supertux-tiles");
81         tw.Close();
82         fs.Close();
83     }
84
85     public void Parse(string filename) {
86         FileStream fs = new FileStream(filename, FileMode.Open);
87         StreamReader stream = new StreamReader(fs);
88
89         Lisp.Parser parser = new Lisp.Parser(stream);
90         parser.Parse();
91         if(parser.Type != Parser.LispType.START_LIST)
92             throw new Exception("Expected START_LIST");
93         parser.Parse();
94         if(parser.Type != Parser.LispType.SYMBOL)
95             throw new Exception("Expected symbol");
96         if(parser.SymbolValue != "supertux-tiles")
97             throw new Exception("not a supertux tile files but " +
98                     parser.SymbolValue);
99         ParseTiles(parser);
100
101         stream.Close();
102         fs.Close();
103     }
104
105     public void ParseTiles(Lisp.Parser parser) {
106         tooNew = false;
107         int d = parser.Depth;
108         while(parser.Parse() && parser.Depth >= d) {
109             if(parser.Depth == d && parser.Type != Parser.LispType.START_LIST) {
110                 Console.WriteLine("non-cons type in list...");
111                 continue;
112             }
113
114             if(parser.Depth == d+1) {
115                 if(parser.Type != Parser.LispType.SYMBOL) {
116                     throw new Exception("Expected symbol in list element");
117                 }
118                 switch(parser.SymbolValue) {
119                     case "properties":
120                         SkipList(parser);
121                         break;
122                     case "tilegroup":
123                         TileGroup tilegroup = new TileGroup();
124                         tilegroup.Parse(parser);
125                         TileGroups.Add(tilegroup);
126                         break;
127                     case "tile":
128                         Tile tile = new Tile();
129                         tile.Parse(parser);
130
131                         while(tile.ID >= Tiles.Count)
132                             Tiles.Add(null);
133                         Tiles[tile.ID] = tile;
134                         break;
135                     case "tiles":
136                         ParseMoreTiles(parser);
137                         tooNew = true;
138                         Console.WriteLine(
139                                 "Warning: new syntax of \"More tiles in one image\" file isn't currently supported");
140                         Console.WriteLine(
141                                 "And this means: YOU WON'T BE ABLE TO SAVE YOUR CHANGES !!!");
142                         break;
143                    default:
144                         throw new Exception("Unexpected listentry: " +
145                                 parser.SymbolValue);
146                 }
147             }
148         }
149     }
150
151         public void ParseMoreTiles(Lisp.Parser parser)
152         {
153                 int blockWidth = 0;
154                 int blockHeight = 0;
155                 List<int> ids = new List<int>();
156                 List<int> attributes = new List<int>();
157                 List<int> datas = new List<int>();
158                 List<string> imageNames = new List<string>();
159                 float animFps = 0;
160
161                 int d = parser.Depth;
162                 while(parser.Parse() && parser.Depth >= d) {
163                         if(parser.Depth == d+1) {
164                                 if(parser.Type != Parser.LispType.SYMBOL)
165                                         throw new Exception("expected SYMBOL at supertux-tiles---tiles level, but got \"" + parser.StringValue + "\"");
166                                 string symbol = parser.SymbolValue;
167                                 parser.Parse();
168                                 switch(symbol) {
169                                         case "width":
170                                                 blockWidth = parser.IntegerValue;
171                                                 break;
172                                         case "height":
173                                                 blockHeight = parser.IntegerValue;
174                                                 break;
175                                         case "ids":
176                                                 Parser.ParseIntList(parser, ids);
177                                                 break;
178                                         case "attributes":
179                                                 Parser.ParseIntList(parser, attributes);
180                                                 break;
181                                         case "datas":
182                                                 Parser.ParseIntList(parser, datas);
183                                                 break;
184                                         case "anim-fps":
185                                                 animFps = parser.FloatValue;
186                                                 break;
187                                         case "image":
188                                                 int subDepth = parser.Depth;
189                                                 while(parser.Depth >= subDepth) {
190                                                         imageNames.Add(parser.StringValue);
191                                                         parser.Parse();
192                                                 }
193                                                 break;
194                                         default:
195                                                 Console.WriteLine("Unknown tiles element " + symbol);
196                                                 break;
197                                 }
198                         }
199                 }
200                 if(ids.Count != blockWidth * blockHeight)
201                         throw new ApplicationException("Must have width*height ids in tiles block, but found " + ids.Count.ToString());
202                 if((attributes.Count != blockWidth * blockHeight) && attributes.Count > 0)      //missing atributes == all-are-0-attributes
203                         throw new ApplicationException("Must have width*height attributes in tiles block");
204                 if((datas.Count != blockWidth * blockHeight) && datas.Count > 0)        //missing DATAs == all-are-0-DATAs
205                         throw new ApplicationException("Must have width*height DATAs in tiles block");
206
207                 int id = 0;
208                 for(int y = 0; y < blockHeight; ++y) {
209                         for(int x = 0; x < blockWidth; ++x) {
210                                 if (ids[id] != 0) {
211                                         Tile tile = new Tile();
212
213                                         tile.Images = new ArrayList();
214                                         foreach (string str in imageNames)
215                                         {
216                                                 ImageRegion region = new ImageRegion();
217                                                 region.ImageFile = str;
218                                                 region.Region.X = x * TILE_WIDTH;
219                                                 region.Region.Y = y * TILE_HEIGHT;
220                                                 region.Region.Width = TILE_WIDTH;
221                                                 region.Region.Height = TILE_HEIGHT;
222                                                 tile.Images.Add(region);
223                                         }
224                                         tile.ID = ids[id];
225                                         tile.Attributes = (attributes.Count > 0)?attributes[id]:0;      //missing atributes == all-are-0-attributes
226                                         tile.Data = (datas.Count > 0)?datas[id]:0;      //missing DATAs == all-are-0-DATAs
227                                         tile.AnimFps = animFps;
228
229                                         while(Tiles.Count <= tile.ID)
230                                                 Tiles.Add(null);
231
232                                         Tiles[tile.ID] = tile;
233                                 }
234
235                                 id++;
236                         }
237                 }
238         }
239
240         private void SkipList(Lisp.Parser parser)
241         {
242                 int d = parser.Depth;
243                 while(parser.Parse() && parser.Depth >= d)
244                         ;
245         }
246 }