opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.IO;
30 using System.Text;
31 using OpenSim.Region.Framework.Interfaces;
32 using OpenSim.Region.Framework.Scenes;
33 using OpenSim.Framework;
34  
35 namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
36 {
37 /// <summary>
38 /// Terragen File Format Loader
39 /// Built from specification at
40 /// http://www.planetside.co.uk/terragen/dev/tgterrain.html
41 /// </summary>
42 internal class Terragen : ITerrainLoader
43 {
44 #region ITerrainLoader Members
45  
46 public ITerrainChannel LoadFile(string filename)
47 {
48 FileInfo file = new FileInfo(filename);
49 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
50 ITerrainChannel retval = LoadStream(s);
51  
52 s.Close();
53  
54 return retval;
55 }
56  
57 public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight)
58 {
59 TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight);
60  
61 FileInfo file = new FileInfo(filename);
62 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
63 BinaryReader bs = new BinaryReader(s);
64  
65 bool eof = false;
66  
67 int fileXPoints = 0;
68 // int fileYPoints = 0;
69  
70 // Terragen file
71 while (eof == false)
72 {
73 string tmp = Encoding.ASCII.GetString(bs.ReadBytes(4));
74 switch (tmp)
75 {
76 case "SIZE":
77 fileXPoints = bs.ReadInt16() + 1;
78 // fileYPoints = fileXPoints;
79 bs.ReadInt16();
80 break;
81 case "XPTS":
82 fileXPoints = bs.ReadInt16();
83 bs.ReadInt16();
84 break;
85 case "YPTS":
86 // fileYPoints = bs.ReadInt16();
87 bs.ReadInt16();
88 bs.ReadInt16();
89 break;
90 case "ALTW":
91 eof = true;
92 Int16 heightScale = bs.ReadInt16();
93 Int16 baseHeight = bs.ReadInt16();
94  
95 int currFileYOffset = 0;
96  
97 // if our region isn't on the first X section of the areas to be landscaped, then
98 // advance to our section of the file
99 while (currFileYOffset < offsetY)
100 {
101 // read a whole strip of regions
102 int heightsToRead = sectionHeight * fileXPoints;
103 bs.ReadBytes(heightsToRead * 2); // because the shorts are 2 bytes in the file
104 currFileYOffset++;
105 }
106  
107 for (int y = 0; y < sectionHeight; y++)
108 {
109 int currFileXOffset = 0;
110  
111 // if our region isn't the first X section of the areas to be landscaped, then
112 // advance the stream to the X start pos of our section in the file
113 // i.e. eat X upto where we start
114 while (currFileXOffset < offsetX)
115 {
116 bs.ReadBytes(sectionWidth * 2); // 2 bytes = short
117 currFileXOffset++;
118 }
119  
120 // got to our X offset, so write our regions X line
121 for (int x = 0; x < sectionWidth; x++)
122 {
123 // Read a strip and continue
124 retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0;
125 }
126 // record that we wrote it
127 currFileXOffset++;
128  
129 // if our region isn't the last X section of the areas to be landscaped, then
130 // advance the stream to the end of this Y column
131 while (currFileXOffset < fileWidth)
132 {
133 // eat the next regions x line
134 bs.ReadBytes(sectionWidth * 2); // 2 bytes = short
135 currFileXOffset++;
136 }
137 //eat the last additional point
138 bs.ReadInt16();
139 }
140  
141  
142 break;
143 default:
144 bs.ReadInt32();
145 break;
146 }
147 }
148  
149 bs.Close();
150 s.Close();
151  
152 return retval;
153 }
154  
155 public ITerrainChannel LoadStream(Stream s)
156 {
157  
158 int w = (int)Constants.RegionSize;
159 int h = (int)Constants.RegionSize;
160  
161 TerrainChannel retval = new TerrainChannel(w, h);
162  
163 BinaryReader bs = new BinaryReader(s);
164  
165 bool eof = false;
166 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ")
167 {
168 // int fileWidth = w;
169 // int fileHeight = h;
170  
171 // Terragen file
172 while (eof == false)
173 {
174 string tmp = Encoding.ASCII.GetString(bs.ReadBytes(4));
175 switch (tmp)
176 {
177 case "SIZE":
178 // int sztmp = bs.ReadInt16() + 1;
179 // fileWidth = sztmp;
180 // fileHeight = sztmp;
181 bs.ReadInt16();
182 bs.ReadInt16();
183 break;
184 case "XPTS":
185 // fileWidth = bs.ReadInt16();
186 bs.ReadInt16();
187 bs.ReadInt16();
188 break;
189 case "YPTS":
190 // fileHeight = bs.ReadInt16();
191 bs.ReadInt16();
192 bs.ReadInt16();
193 break;
194 case "ALTW":
195 eof = true;
196 Int16 heightScale = bs.ReadInt16();
197 Int16 baseHeight = bs.ReadInt16();
198 for (int y = 0; y < h; y++)
199 {
200 for (int x = 0; x < w; x++)
201 {
202 retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0;
203 }
204 }
205 break;
206 default:
207 bs.ReadInt32();
208 break;
209 }
210 }
211 }
212  
213 bs.Close();
214  
215 return retval;
216 }
217  
218 public void SaveFile(string filename, ITerrainChannel map)
219 {
220 FileInfo file = new FileInfo(filename);
221 FileStream s = file.Open(FileMode.Create, FileAccess.Write);
222 SaveStream(s, map);
223  
224 s.Close();
225 }
226  
227 public void SaveStream(Stream stream, ITerrainChannel map)
228 {
229 BinaryWriter bs = new BinaryWriter(stream);
230  
231 //find the max and min heights on the map
232 double heightMax = map[0,0];
233 double heightMin = map[0,0];
234  
235 for (int y = 0; y < map.Height; y++)
236 {
237 for (int x = 0; x < map.Width; x++)
238 {
239 double current = map[x,y];
240 if (heightMax < current)
241 heightMax = current;
242 if (heightMin > current)
243 heightMin = current;
244 }
245 }
246  
247 double baseHeight = Math.Floor( (heightMax + heightMin) / 2d );
248  
249 double horizontalScale = Math.Ceiling((heightMax - heightMin));
250  
251 // if we are completely flat add 1cm range to avoid NaN divisions
252 if (horizontalScale < 0.01d)
253 horizontalScale = 0.01d;
254  
255 Encoding enc = Encoding.ASCII;
256  
257 bs.Write(enc.GetBytes("TERRAGENTERRAIN "));
258  
259 bs.Write(enc.GetBytes("SIZE"));
260 bs.Write(Convert.ToInt16(Constants.RegionSize));
261 bs.Write(Convert.ToInt16(0)); // necessary padding
262  
263 //The XPTS and YPTS chunks are not needed for square regions
264 //but L3DT won't load the terrain file properly without them.
265 bs.Write(enc.GetBytes("XPTS"));
266 bs.Write(Convert.ToInt16(Constants.RegionSize));
267 bs.Write(Convert.ToInt16(0)); // necessary padding
268  
269 bs.Write(enc.GetBytes("YPTS"));
270 bs.Write(Convert.ToInt16(Constants.RegionSize));
271 bs.Write(Convert.ToInt16(0)); // necessary padding
272  
273 bs.Write(enc.GetBytes("SCAL"));
274 bs.Write(ToLittleEndian(1f)); //we're going to say that 1 terrain unit is 1 metre
275 bs.Write(ToLittleEndian(1f));
276 bs.Write(ToLittleEndian(1f));
277  
278 // as we are square and not projected on a sphere then the other
279 // header blocks are not required
280  
281 // now write the elevation data
282 bs.Write(enc.GetBytes("ALTW"));
283 bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min
284 bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point
285  
286 for (int y = 0; y < map.Height; y++)
287 {
288 for (int x = 0; x < map.Width; x++)
289 {
290 float elevation = (float)((map[x,y] - baseHeight) * 65536 ) / (float)horizontalScale; // see LoadStream for inverse
291  
292 // clamp rounding issues
293 if (elevation > Int16.MaxValue)
294 elevation = Int16.MaxValue;
295 else if (elevation < Int16.MinValue)
296 elevation = Int16.MinValue;
297  
298 bs.Write(Convert.ToInt16(elevation));
299 }
300 }
301  
302 //This is only necessary for older versions of Terragen.
303 bs.Write(enc.GetBytes("EOF "));
304  
305 bs.Close();
306 }
307  
308 public string FileExtension
309 {
310 get { return ".ter"; }
311 }
312  
313 public virtual void SaveFile(ITerrainChannel m_channel, string filename,
314 int offsetX, int offsetY,
315 int fileWidth, int fileHeight,
316 int regionSizeX, int regionSizeY)
317 {
318 throw new System.Exception("Not Implemented");
319 }
320  
321 #endregion
322  
323 public override string ToString()
324 {
325 return "Terragen";
326 }
327  
328 //Returns true if this extension is supported for terrain save-tile
329 public bool SupportsTileSave()
330 {
331 return false;
332 }
333  
334 /// <summary>
335 /// terragen SCAL floats need to be written intel ordered regardless of
336 /// big or little endian system
337 /// </summary>
338 /// <param name="number"></param>
339 /// <returns></returns>
340 private byte[] ToLittleEndian( float number)
341 {
342 byte[] retVal = BitConverter.GetBytes(number);
343 if (BitConverter.IsLittleEndian == false)
344 {
345 byte[] tmp = new byte[4];
346 for (int i = 0; i < 4; i++)
347 {
348 tmp[i] = retVal[3 - i];
349 }
350 retVal = tmp;
351  
352 }
353 return retVal ;
354 }
355  
356 }
357 }