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