OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
LLRAW.cs
Go to the documentation of this file.
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 OpenSim.Framework;
31 using OpenSim.Region.Framework.Interfaces;
32 using OpenSim.Region.Framework.Scenes;
33 
34 namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
35 {
36  public class LLRAW : ITerrainLoader
37  {
38  public struct HeightmapLookupValue : IComparable<HeightmapLookupValue>
39  {
40  public ushort Index;
41  public float Value;
42 
43  public HeightmapLookupValue(ushort index, float value)
44  {
45  Index = index;
46  Value = value;
47  }
48 
50  {
51  return Value.CompareTo(val.Value);
52  }
53  }
54 
56  HeightmapLookupValue[] LookupHeightTable;
57 
58  public LLRAW()
59  {
60  }
61 
62  private void BuildLookupHeightTable()
63  {
64  LookupHeightTable = new HeightmapLookupValue[256 * 256];
65 
66  for (int i = 0; i < 256; i++)
67  {
68  for (int j = 0; j < 256; j++)
69  {
70  LookupHeightTable[i + (j * 256)] = new HeightmapLookupValue((ushort)(i + (j * 256)), (float)((double)i * ((double)j / 128.0d)));
71  }
72  }
73  Array.Sort<HeightmapLookupValue>(LookupHeightTable);
74  }
75 
76  #region ITerrainLoader Members
77 
78  public ITerrainChannel LoadFile(string filename)
79  {
80  FileInfo file = new FileInfo(filename);
81 
82  ITerrainChannel channel;
83 
84  using (FileStream s = file.Open(FileMode.Open, FileAccess.Read))
85  channel = LoadStream(s);
86 
87  return channel;
88  }
89 
90  public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight)
91  {
92  TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight);
93 
94  FileInfo file = new FileInfo(filename);
95 
96  using (FileStream s = file.Open(FileMode.Open, FileAccess.Read))
97  using (BinaryReader bs = new BinaryReader(s))
98  {
99  int currFileYOffset = fileHeight - 1;
100 
101  // if our region isn't on the first Y section of the areas to be landscaped, then
102  // advance to our section of the file
103  while (currFileYOffset > offsetY)
104  {
105  // read a whole strip of regions
106  int heightsToRead = sectionHeight * (fileWidth * sectionWidth);
107  bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels
108  currFileYOffset--;
109  }
110 
111  // got to the Y start offset within the file of our region
112  // so read the file bits associated with our region
113  int y;
114 
115  // for each Y within our Y offset
116  for (y = sectionHeight - 1; y >= 0; y--)
117  {
118  int currFileXOffset = 0;
119 
120  // if our region isn't the first X section of the areas to be landscaped, then
121  // advance the stream to the X start pos of our section in the file
122  // i.e. eat X upto where we start
123  while (currFileXOffset < offsetX)
124  {
125  bs.ReadBytes(sectionWidth * 13);
126  currFileXOffset++;
127  }
128 
129  // got to our X offset, so write our regions X line
130  int x;
131  for (x = 0; x < sectionWidth; x++)
132  {
133  // Read a strip and continue
134  retval[x, y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
135  bs.ReadBytes(11);
136  }
137  // record that we wrote it
138  currFileXOffset++;
139 
140  // if our region isn't the last X section of the areas to be landscaped, then
141  // advance the stream to the end of this Y column
142  while (currFileXOffset < fileWidth)
143  {
144  // eat the next regions x line
145  bs.ReadBytes(sectionWidth * 13); //The 13 channels again
146  currFileXOffset++;
147  }
148  }
149  }
150 
151  return retval;
152  }
153 
154  public ITerrainChannel LoadStream(Stream s)
155  {
156  // The raw format doesn't contain any dimension information.
157  // Guess the square dimensions by using the length of the raw file.
158  double dimension = Math.Sqrt((double)(s.Length / 13));
159  // Regions are always multiples of 256.
160  int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize);
161  if (trimmedDimension < Constants.RegionSize)
162  trimmedDimension = (int)Constants.RegionSize;
163 
164  TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension);
165 
166  using (BinaryReader bs = new BinaryReader(s))
167  {
168  int y;
169  for (y = 0; y < retval.Height; y++)
170  {
171  int x;
172  for (x = 0; x < retval.Width; x++)
173  {
174  retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
175  bs.ReadBytes(11); // Advance the stream to next bytes.
176  }
177  }
178  }
179 
180  return retval;
181  }
182 
183  public void SaveFile(string filename, ITerrainChannel map)
184  {
185  FileInfo file = new FileInfo(filename);
186 
187  using (FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write))
188  SaveStream(s, map);
189  }
190 
191  public void SaveStream(Stream s, ITerrainChannel map)
192  {
193  if (LookupHeightTable == null)
194  BuildLookupHeightTable();
195 
196  using (BinaryWriter binStream = new BinaryWriter(s))
197  {
198  // Output the calculated raw
199  for (int y = 0; y < map.Height; y++)
200  {
201  for (int x = 0; x < map.Width; x++)
202  {
203  double t = map[x, (map.Height - 1) - y];
204  //if height is less than 0, set it to 0 as
205  //can't save -ve values in a LLRAW file
206  if (t < 0d)
207  {
208  t = 0d;
209  }
210 
211  int index = 0;
212 
213  // The lookup table is pre-sorted, so we either find an exact match or
214  // the next closest (smaller) match with a binary search
215  index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, (float)t));
216  if (index < 0)
217  index = ~index - 1;
218 
219  index = LookupHeightTable[index].Index;
220 
221  byte red = (byte) (index & 0xFF);
222  byte green = (byte) ((index >> 8) & 0xFF);
223  const byte blue = 20;
224  const byte alpha1 = 0;
225  const byte alpha2 = 0;
226  const byte alpha3 = 0;
227  const byte alpha4 = 0;
228  const byte alpha5 = 255;
229  const byte alpha6 = 255;
230  const byte alpha7 = 255;
231  const byte alpha8 = 255;
232  byte alpha9 = red;
233  byte alpha10 = green;
234 
235  binStream.Write(red);
236  binStream.Write(green);
237  binStream.Write(blue);
238  binStream.Write(alpha1);
239  binStream.Write(alpha2);
240  binStream.Write(alpha3);
241  binStream.Write(alpha4);
242  binStream.Write(alpha5);
243  binStream.Write(alpha6);
244  binStream.Write(alpha7);
245  binStream.Write(alpha8);
246  binStream.Write(alpha9);
247  binStream.Write(alpha10);
248  }
249  }
250  }
251  LookupHeightTable = null;
252  }
253 
254  public string FileExtension
255  {
256  get { return ".raw"; }
257  }
258 
259  public virtual void SaveFile(ITerrainChannel m_channel, string filename,
260  int offsetX, int offsetY,
261  int fileWidth, int fileHeight,
262  int regionSizeX, int regionSizeY)
263  {
264  throw new System.Exception("Not Implemented");
265  }
266 
267  #endregion
268 
269  public override string ToString()
270  {
271  return "LL/SL RAW";
272  }
273 
274  //Returns true if this extension is supported for terrain save-tile
275  public bool SupportsTileSave()
276  {
277  return false;
278  }
279  }
280 }
virtual void SaveFile(ITerrainChannel m_channel, string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int regionSizeX, int regionSizeY)
Save a number of map tiles to a single big image file.
Definition: LLRAW.cs:259
ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight)
Definition: LLRAW.cs:90
void SaveStream(Stream s, ITerrainChannel map)
Definition: LLRAW.cs:191
ITerrainChannel LoadFile(string filename)
Definition: LLRAW.cs:78
void SaveFile(string filename, ITerrainChannel map)
Definition: LLRAW.cs:183
A new version of the old Channel class, simplified