//TrackService _TrackService; //RouteTrack _RouteTrack; internal Route(SimisProvider simisProvider, string routePath, FileFinder files, SimisFile trackFile) { SimisProvider = simisProvider; RoutePath = routePath; Files = files; TrackFile = trackFile; }
static void RunDump(IEnumerable <string> files, bool verbose) { SimisProvider provider; try { provider = new SimisProvider(Path.GetDirectoryName(Application.ExecutablePath) + @"\Resources"); } catch (FileException ex) { Console.WriteLine(ex.ToString()); return; } foreach (var inputFile in files) { try { var parsedFile = new SimisFile(inputFile, provider.GetForPath(inputFile)); Console.WriteLine(inputFile); if (parsedFile.Tree != null) { PrintSimisTree(0, parsedFile.Tree); } else if (parsedFile.Ace != null) { PrintSimisAce(parsedFile.Ace); } } catch (Exception ex) { if (verbose) { Console.WriteLine("Read: " + ex + "\n"); } } } }
public TrackService(FileFinder files, SimisProvider simisProvider) { Files = files; SimisProvider = simisProvider; TrackShapes = new Dictionary <uint, TrackShape>(); TrackShapesByFileName = new Dictionary <string, TrackShape>(); TrackSections = new Dictionary <uint, TrackSection>(); TSection = new SimisFile(Files[@"Global\tsection.dat"], SimisProvider); foreach (var section in TSection.Tree["TrackSections"].Where(n => n.Type == "TrackSection")) { if (section.Contains("SectionSize")) { var sectionSize = section["SectionSize"]; if (section.Contains("SectionCurve")) { var sectionCurve = section["SectionCurve"]; var ts = new TrackSection(section[0].ToValue <uint>(), sectionSize[0].ToValue <float>(), sectionSize[1].ToValue <float>(), true, sectionCurve[0].ToValue <float>(), sectionCurve[1].ToValue <float>()); TrackSections.Add(ts.Id, ts); } else { var ts = new TrackSection(section[0].ToValue <uint>(), sectionSize[0].ToValue <float>(), sectionSize[1].ToValue <float>()); TrackSections.Add(ts.Id, ts); } } } foreach (var shape in TSection.Tree["TrackShapes"].Where(n => n.Type == "TrackShape")) { var tpaths = new List <TrackPath>(); foreach (var path in shape.Where(n => n.Type == "SectionIdx")) { var count = path[0].ToValue <uint>(); var tsections = new List <TrackSection>(); for (var i = 0; i < count; i++) { tsections.Add(TrackSections[path[5 + i].ToValue <uint>()]); } tpaths.Add(new TrackPath(path[1].ToValue <float>(), path[2].ToValue <float>(), path[3].ToValue <float>(), path[4].ToValue <float>(), tsections)); } var ts = new TrackShape(shape[0].ToValue <uint>(), shape["FileName"][0].ToValue <string>().ToLowerInvariant(), shape.Contains("ClearanceDist") ? shape["ClearanceDist"][0].ToValue <float>() : 0, shape.Contains("TunnelShape"), shape.Contains("RoadShape"), tpaths, shape.Contains("MainRoute") ? (int)shape["MainRoute"][0].ToValue <uint>() : -1); TrackShapes.Add(ts.Id, ts); if (TrackShapesByFileName.ContainsKey(ts.FileName)) { TrackShapesByFileName[ts.FileName] = ts; } else { TrackShapesByFileName.Add(ts.FileName, ts); } } }
public RouteTrack(string fileName, FileFinder files, SimisProvider simisProvider) { FileName = fileName; Files = files; SimisProvider = simisProvider; TrackNodes = new Dictionary <uint, RouteTrackNode>(); TrackVectors = new Dictionary <uint, RouteTrackVectors>(); TrackDB = new UndoRedoSimisFile(Files[FileName + ".tdb"], SimisProvider); TrackDB.Read(); foreach (var node in TrackDB.Tree["TrackDB"]["TrackNodes"].Where(n => n.Type == "TrackNode")) { if (node.Contains("TrJunctionNode") || node.Contains("TrEndNode")) { var uid = node["UiD"]; var tileX = uid[4].ToValue <int>(); var tileZ = uid[5].ToValue <uint>(); var x = uid[6].ToValue <float>(); var y = uid[7].ToValue <float>(); var z = uid[8].ToValue <float>(); var rtNode = new RouteTrackNode(node[0].ToValue <uint>(), tileX, tileZ, x, y, z); TrackNodes.Add(rtNode.Id, rtNode); } else if (node.Contains("TrVectorNode")) { var sections = node["TrVectorNode"]["TrVectorSections"]; var sectionCount = sections[0].ToValue <uint>(); var vectors = new List <RouteTrackVector>(); for (var i = 0; i < sectionCount; i++) { var tileX = sections[i * 16 + 9].ToValue <int>(); var tileZ = sections[i * 16 + 10].ToValue <uint>(); var x = sections[i * 16 + 11].ToValue <float>(); var y = sections[i * 16 + 12].ToValue <float>(); var z = sections[i * 16 + 13].ToValue <float>(); vectors.Add(new RouteTrackVector(tileX, tileZ, x, y, z)); } if (node["TrPins"].Count != 4) { throw new InvalidDataException("Track DB node does not have exactly 2 pins."); } var rtVectors = new RouteTrackVectors(node[0].ToValue <uint>(), vectors, node["TrPins"][2][0].ToValue <uint>(), node["TrPins"][3][0].ToValue <uint>()); TrackVectors.Add(rtVectors.Id, rtVectors); } else { throw new InvalidDataException("Track DB contains track node with no obvious type."); } } }
void LoadObjects() { string worldFile = String.Format(@"{0}\World\w{1,6:+000000;-000000}{2,6:+000000;-000000}.w", Route.RoutePath, TileCoordinate.TileX, TileCoordinate.TileZ); if (File.Exists(worldFile)) { var world = new SimisFile(worldFile, SimisProvider.GetForPath(worldFile)); foreach (var worldItem in world.Tree["Tr_Worldfile"]) { if (!worldItem.Contains("Position")) { continue; } var position = worldItem["Position"]; var qdirection = worldItem.Contains("QDirection") ? worldItem["QDirection"] : null; TileObject tileObject = new TileLabeledObject(position[0].ToValue <float>(), position[1].ToValue <float>(), position[2].ToValue <float>(), worldItem.Type); switch (worldItem.Type) { case "TrackObj": if (qdirection != null) { tileObject = new TileTrackShape(position[0].ToValue <float>(), position[1].ToValue <float>(), position[2].ToValue <float>(), qdirection[0].ToValue <float>(), qdirection[1].ToValue <float>(), qdirection[2].ToValue <float>(), qdirection[3].ToValue <float>(), worldItem["SectionIdx"][0].ToValue <uint>()); } break; case "Platform": var platformData = worldItem["PlatformData"]; tileObject = new TilePlatform(position[0].ToValue <float>(), position[1].ToValue <float>(), position[2].ToValue <float>(), platformData[0].ToValue <uint>().ToString()); break; case "Siding": var sidingData = worldItem["SidingData"]; tileObject = new TileSiding(position[0].ToValue <float>(), position[1].ToValue <float>(), position[2].ToValue <float>(), sidingData[0].ToValue <uint>().ToString()); break; case "Signal": tileObject = new TileSignal(position[0].ToValue <float>(), position[1].ToValue <float>(), position[2].ToValue <float>(), qdirection[0].ToValue <float>(), qdirection[1].ToValue <float>(), qdirection[2].ToValue <float>(), qdirection[3].ToValue <float>()); break; case "milepost": break; case "fuel": break; } Objects.Add(tileObject); } } }
//Image _terrainImage; //List<TileTrackSection> _trackSections; //List<TileTrackNode> _trackNodes; //List<TilePlatform> _platforms; //List<TileSiding> _sidings; //List<TileSignal> _signals; //List<TileMarker> _markers; //if (terrainToolStripMenuItem.Checked) layers.Add(TileLayer.Terrain); //if (roadsToolStripMenuItem.Checked) layers.Add(TileLayer.Roads); //if (trackToolStripMenuItem.Checked) layers.Add(TileLayer.Track); //// ----------------------------------------------------------------- //if (platformsToolStripMenuItem.Checked) layers.Add(TileLayer.Platforms); //if (platformNamesToolStripMenuItem.Checked) layers.Add(TileLayer.PlatformNames); //if (sidingsToolStripMenuItem.Checked) layers.Add(TileLayer.Sidings); //if (sidingNamesToolStripMenuItem.Checked) layers.Add(TileLayer.SidingNames); //if (signalsToolStripMenuItem.Checked) layers.Add(TileLayer.Signals); //if (milepostsToolStripMenuItem.Checked) layers.Add(TileLayer.Mileposts); //if (fuelPointsToolStripMenuItem.Checked) layers.Add(TileLayer.FuelPoints); //// ----------------------------------------------------------------- //if (markersToolStripMenuItem.Checked) layers.Add(TileLayer.Markers); //public Route Route { get { return _route; } set { _route = value; } } //public SimisProvider SimisProvider { get { return _simisProvider; } } //public string TileName { get { return _tileName; } } //public TileCoordinate TileCoordinate { get { return _tileCoordinate; } } public Tile(string tileName, Route route, SimisProvider simisProvider) { TileName = tileName; Route = route; SimisProvider = simisProvider; TileCoordinate = Coordinates.ConvertToTile(tileName); Terrain = new double[256, 256]; Objects = new List <TileObject>(); LoadTerrain(); LoadObjects(); // _trackSections = new List<TileTrackSection>(); // _trackNodes = new List<TileTrackNode>(); // _platforms = new List<TilePlatform>(); // _sidings = new List<TileSiding>(); // _signals = new List<TileSignal>(); // _markers = new List<TileMarker>(); }
public Route(string trackFile, SimisProvider simisProvider) { RoutePath = Path.GetDirectoryName(trackFile); SimisProvider = simisProvider; // We can find things relative to the following: // +-<msts> <-- here // +-Global <-- here // +-Routes // +-<route> <-- here // +-Global <-- here* // * Allowed for route-specific global files; this is a feature for Open Rails Train Simulator (ORTS). // Paths used to access files will usually contain 1 directory above, e.g. "activities\foo.act", to avoid // unexpected and undesired collisions between files in <msts>, <msts>\Global and <msts>\Routes\<route>. var mstsPath = Path.GetDirectoryName(Path.GetDirectoryName(RoutePath)); Files = new FileFinder(new string[] { RoutePath, Path.Combine(RoutePath, "Global"), mstsPath, Path.Combine(mstsPath, "Global") }); TrackFile = new SimisFile(trackFile, SimisProvider.GetForPath(trackFile)); }
static void ShowFormats() { SimisProvider provider; try { provider = new SimisProvider(Path.GetDirectoryName(Application.ExecutablePath) + @"\Resources"); } catch (FileException ex) { Console.WriteLine(ex.ToString()); return; } var outFormat = "{0,-40:S} {1,-15:S} {2,-15:S}"; Console.WriteLine(String.Format(CultureInfo.CurrentCulture, outFormat, "Format Name", "File Type", "Internal Type")); Console.WriteLine(String.Empty.PadLeft(40 + 2 + 15 + 2 + 15 + 2, '=')); foreach (var format in provider.Formats) { Console.WriteLine(String.Format(CultureInfo.CurrentCulture, outFormat, format.Name, format.Extension, format.Format)); } }
void LoadTerrain() { string tileElevationFile = String.Format(@"{0}\Tiles\{1}_y.raw", Route.RoutePath, TileName); string tileFile = String.Format(@"{0}\Tiles\{1}.t", Route.RoutePath, TileName); var terrainWidth = 256u; var terrainHeight = 256u; var terrainFloor = 0d; var terrainScale = 1d; var tile = new SimisFile(tileFile, SimisProvider.GetForPath(tileFile)); var terrainSamples = tile.Tree["terrain"]["terrain_samples"]; terrainWidth = terrainHeight = terrainSamples["terrain_nsamples"][0].ToValue <uint>(); Debug.Assert(terrainWidth == 256); Debug.Assert(terrainHeight == 256); if (terrainSamples.Contains("terrain_sample_rotation")) { Debug.Assert(terrainSamples["terrain_sample_rotation"][0].ToValue <float>() == 0); } terrainFloor = terrainSamples["terrain_sample_floor"][0].ToValue <float>(); terrainScale = terrainSamples["terrain_sample_scale"][0].ToValue <float>(); var terrain_sample_size = terrainSamples["terrain_sample_size"][0].ToValue <float>(); Debug.Assert(terrain_sample_size == 8 || terrain_sample_size == 16 || terrain_sample_size == 32); using (var streamElevation = new FileStream(tileElevationFile, FileMode.Open, FileAccess.Read)) { var readerElevation = new BinaryReader(streamElevation); for (var z = 0; z < terrainHeight; z++) { for (var x = 0; x < terrainWidth; x++) { Terrain[x, z] = terrainFloor + (double)readerElevation.ReadUInt16() * terrainScale; } } } }
static void RunTest(IEnumerable <string> files, bool verbose, int threading) { SimisProvider provider; try { provider = new SimisProvider(Path.GetDirectoryName(Application.ExecutablePath) + @"\Resources"); } catch (FileException ex) { Console.WriteLine(ex.ToString()); return; } var totalCount = new TestFormatCount(); var supportedCount = new TestFormatCount(); var formatCounts = new Dictionary <string, TestFormatCount>(); var timeStart = DateTime.Now; Func <SimisJinxFormat, TestFormatCount> GetFormatFor = (simisFormat) => { var formatName = simisFormat.Name; if (!formatCounts.ContainsKey(formatName)) { formatCounts[formatName] = new TestFormatCount() { FormatName = formatName, SortKey = formatName }; } return(formatCounts[formatName]); }; Func <string, ProcessFileResults> ProcessFile = (file) => { if (verbose && (threading > 1)) { lock (formatCounts) { Console.WriteLine(String.Format("[Thread {0}] {1}", Thread.CurrentThread.ManagedThreadId, file)); } } var result = new ProcessFileResults(); var formatCount = new TestFormatCount(); var fileProvider = provider.GetForPath(file); SimisFile newFile = null; Stream readStream = new UnclosableStream(new BufferedInMemoryStream(File.OpenRead(file))); Stream saveStream = new UnclosableStream(new MemoryStream()); { result.Total = true; try { using (var reader = SimisReader.FromStream(readStream, fileProvider)) { var readerJinx = reader as SimisJinxReader; var readerAce = reader as SimisAceReader; if (readerJinx != null) { readerJinx.ReadToken(); if (readerJinx.JinxStreamFormat == null) { return(result); } result.JinxStreamFormat = readerJinx.JinxStreamFormat; } else if (readerAce != null) { if (fileProvider.Formats.FirstOrDefault() == null) { return(result); } result.JinxStreamFormat = fileProvider.Formats.First(); } else { return(result); } } } catch (ReaderException) { return(result); } readStream.Position = 0; } // First, read the file in. try { try { newFile = new SimisFile(readStream, fileProvider); } catch (Exception e) { throw new FileException(file, e); } result.ReadSuccess = true; } catch (FileException ex) { if (verbose) { lock (formatCounts) { Console.WriteLine("Read: " + ex + "\n"); } } return(result); } // Second, write the file out into memory. try { try { newFile.Write(saveStream); } catch (Exception e) { throw new FileException(file, e); } // WriteSuccess is delayed until after the comparison. We won't claim write support without comparison support. } catch (FileException ex) { if (verbose) { lock (formatCounts) { Console.WriteLine("Write: " + ex + "\n"); } } return(result); } // Third, verify that the output is the same as the input. readStream.Seek(0, SeekOrigin.Begin); saveStream.Seek(0, SeekOrigin.Begin); var readReader = new BinaryReader(new SimisTestableStream(readStream), newFile.StreamIsBinary ? ByteEncoding.Encoding : Encoding.Unicode); var saveReader = new BinaryReader(new SimisTestableStream(saveStream), newFile.StreamIsBinary ? ByteEncoding.Encoding : Encoding.Unicode); var isDXTACE = (result.JinxStreamFormat.Extension == "ace") && ((newFile.Ace.Format & 0x10) != 0); var readChars = readReader.ReadChars((int)readReader.BaseStream.Length); var saveChars = saveReader.ReadChars((int)saveReader.BaseStream.Length); var charBytes = newFile.StreamIsBinary ? 1 : 2; var charMin = Math.Min(readChars.Length, saveChars.Length); for (var i = 0; i < charMin; i++) { if (isDXTACE && (i > 168)) { break; } if (readChars[i] != saveChars[i]) { readReader.BaseStream.Position = charBytes * (i + 1); saveReader.BaseStream.Position = charBytes * (i + 1); var readEx = new ReaderException(readReader, newFile.StreamIsBinary, charBytes, ""); var saveEx = new ReaderException(saveReader, newFile.StreamIsBinary, charBytes, ""); if (verbose) { lock (formatCounts) { Console.WriteLine("Compare: " + String.Format(CultureInfo.CurrentCulture, "{0}\n\nFile character {1:N0} does not match: {2:X4} vs {3:X4}.\n\n{4}{5}\n", file, charBytes * i, readChars[i], saveChars[i], readEx.ToString(), saveEx.ToString())); } } return(result); } } if ((result.JinxStreamFormat.Extension == "ace") && ((newFile.Ace.Format & 0x10) != 0)) { // DXT images are a massive pain because it is a lossy compression. saveStream.Seek(0, SeekOrigin.Begin); var saveOutput = new SimisFile(saveStream, fileProvider); Debug.Assert(saveOutput.Ace != null); Debug.Assert(saveOutput.Ace.Format == newFile.Ace.Format); try { if (newFile.Ace.Width != saveOutput.Ace.Width) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE width expected {0}; got {1}.", newFile.Ace.Width, saveOutput.Ace.Width)); } if (newFile.Ace.Height != saveOutput.Ace.Height) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE height expected {0}; got {1}.", newFile.Ace.Height, saveOutput.Ace.Height)); } if (newFile.Ace.Unknown7 != saveOutput.Ace.Unknown7) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE unknown7 expected {0}; got {1}.", newFile.Ace.Unknown7, saveOutput.Ace.Unknown7)); } if (newFile.Ace.Creator != saveOutput.Ace.Creator) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE creator expected {0}; got {1}.", newFile.Ace.Creator, saveOutput.Ace.Creator)); } var newFileChannels = String.Join(",", newFile.Ace.Channel.Select(c => c.Type.ToString() + ":" + c.Size).ToArray()); var saveFileChannels = String.Join(",", saveOutput.Ace.Channel.Select(c => c.Type.ToString() + ":" + c.Size).ToArray()); if (newFileChannels != saveFileChannels) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE channels expected {0}; got {1}.", newFileChannels, saveFileChannels)); } if (newFile.Ace.Image.Count != saveOutput.Ace.Image.Count) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE image count expected {0}; got {1}.", newFile.Ace.Image.Count, saveOutput.Ace.Image.Count)); } var errors = new List <double>(); for (var i = 0; i < newFile.Ace.Image.Count; i++) { if (newFile.Ace.Image[i].Width != saveOutput.Ace.Image[i].Width) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE image {2} width expected {0}; got {1}.", newFile.Ace.Image[i].Width, saveOutput.Ace.Image[i].Width, i)); } if (newFile.Ace.Image[i].Height != saveOutput.Ace.Image[i].Height) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "ACE image {2} height expected {0}; got {1}.", newFile.Ace.Image[i].Height, saveOutput.Ace.Image[i].Height, i)); } errors.Add(ImageComparison.GetRootMeanSquareError(newFile.Ace.Image[i].ImageColor, saveOutput.Ace.Image[i].ImageColor, newFile.Ace.Width, newFile.Ace.Height)); errors.Add(ImageComparison.GetRootMeanSquareError(newFile.Ace.Image[i].ImageMask, saveOutput.Ace.Image[i].ImageMask, newFile.Ace.Width, newFile.Ace.Height)); } // Any error over 10.0 is considered a fail. var maxError = 10.0; if (errors.Max() > maxError) { throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "Image RMS (root mean square) errors are too high; highest: {2,5:F1} > {0,5:F1}; all: {1}.", maxError, String.Join(", ", errors.Select(e => e.ToString("F1").PadLeft(5)).ToArray()), errors.Max())); } } catch (InvalidDataException ex) { if (verbose) { lock (formatCounts) { Console.WriteLine("Compare: " + String.Format(CultureInfo.CurrentCulture, "{0}\n\n{1}\n", file, ex.Message)); } } return(result); } } else { if (readChars.Length != saveChars.Length) { readReader.BaseStream.Position = charBytes * charMin; saveReader.BaseStream.Position = charBytes * charMin; var readEx = new ReaderException(readReader, newFile.StreamIsBinary, 0, ""); var saveEx = new ReaderException(saveReader, newFile.StreamIsBinary, 0, ""); if (verbose) { lock (formatCounts) { Console.WriteLine("Compare: " + String.Format(CultureInfo.CurrentCulture, "{0}\n\nFile and stream length do not match: {1:N0} vs {2:N0}.\n\n{3}{4}\n", file, readReader.BaseStream.Length, saveReader.BaseStream.Length, readEx.ToString(), saveEx.ToString())); } } return(result); } } // It all worked! result.WriteSuccess = true; return(result); }; if (threading > 1) { var filesEnumerator = files.GetEnumerator(); var filesFinished = false; var threads = new List <Thread>(threading); for (var i = 0; i < threading; i++) { threads.Add(new Thread(() => { var file = ""; var results = new List <ProcessFileResults>(); while (true) { lock (filesEnumerator) { if (filesFinished || !filesEnumerator.MoveNext()) { filesFinished = true; break; } file = filesEnumerator.Current; } results.Add(ProcessFile(file)); } lock (totalCount) { foreach (var result in results) { if (result.Total) { totalCount.Total++; } if (result.ReadSuccess) { totalCount.ReadSuccess++; } if (result.WriteSuccess) { totalCount.WriteSuccess++; } if (result.JinxStreamFormat != null) { var formatCount = GetFormatFor(result.JinxStreamFormat); if (result.Total) { supportedCount.Total++; } if (result.ReadSuccess) { supportedCount.ReadSuccess++; } if (result.WriteSuccess) { supportedCount.WriteSuccess++; } if (result.Total) { formatCount.Total++; } if (result.ReadSuccess) { formatCount.ReadSuccess++; } if (result.WriteSuccess) { formatCount.WriteSuccess++; } } } } })); } foreach (var thread in threads) { thread.Start(); } foreach (var thread in threads) { thread.Join(); } } else { foreach (var file in files) { var result = ProcessFile(file); if (result.Total) { totalCount.Total++; } if (result.ReadSuccess) { totalCount.ReadSuccess++; } if (result.WriteSuccess) { totalCount.WriteSuccess++; } if (result.JinxStreamFormat != null) { var formatCount = GetFormatFor(result.JinxStreamFormat); if (result.Total) { supportedCount.Total++; } if (result.ReadSuccess) { supportedCount.ReadSuccess++; } if (result.WriteSuccess) { supportedCount.WriteSuccess++; } if (result.Total) { formatCount.Total++; } if (result.ReadSuccess) { formatCount.ReadSuccess++; } if (result.WriteSuccess) { formatCount.WriteSuccess++; } } } } supportedCount.FormatName = "(Total supported files of " + totalCount.Total + ")"; supportedCount.SortKey = "ZZZ"; formatCounts[""] = supportedCount; var outFormat = "{0,-40:S} {1,1:S}{2,-7:D} {3,1:S}{4,-7:D} {5,1:S}{6,-7:D}"; Console.WriteLine(String.Format(CultureInfo.CurrentCulture, outFormat, "Format Name", "", "Total", "", "Read", "", "Write")); Console.WriteLine(String.Empty.PadLeft(69, '=')); foreach (var formatCount in formatCounts.OrderBy(kvp => kvp.Value.SortKey).Select(kvp => kvp.Value)) { Console.WriteLine(String.Format(CultureInfo.CurrentCulture, outFormat, formatCount.FormatName, "", formatCount.Total, formatCount.Total == formatCount.ReadSuccess ? "*" : "", formatCount.ReadSuccess, formatCount.Total == formatCount.WriteSuccess ? "*" : formatCount.ReadSuccess == formatCount.WriteSuccess ? "+" : "", formatCount.WriteSuccess)); } }
public RouteMarkers(Route route, SimisProvider simisProvider) { Route = route; SimisProvider = simisProvider; Markers = LoadMarkers(); }
public RouteService(string basePath, SimisProvider simisProvider) { BasePath = basePath; SimisProvider = simisProvider; }
static void DoConversion(IEnumerable <ConversionFile> files, bool verbose, int threading, bool convertRoundtrip, bool convertTexture, bool convertDXT1, bool convertZLIB) { if (!files.Any()) { throw new OperationCanceledException("Must specify files for conversion."); } SimisProvider provider; try { provider = new SimisProvider(Path.GetDirectoryName(Application.ExecutablePath) + @"\Resources"); } catch (FileException ex) { Console.WriteLine(ex.ToString()); return; } Action <ConversionFile> ConvertFile = (file) => { if (verbose) { lock (files) { if (threading > 1) { Console.WriteLine("[Thread {0}] {1} -> {2}", Thread.CurrentThread.ManagedThreadId, file.Input, file.Output); } else { Console.WriteLine("{0} -> {1}", file.Input, file.Output); } } } try { var inputExt = Path.GetExtension(file.Input).ToUpperInvariant(); var outputExt = Path.GetExtension(file.Output).ToUpperInvariant(); if ((inputExt == ".ACE") && (outputExt == ".ACE")) { // ACE -> ACE var inputAce = new SimisFile(file.Input, provider); var outputAce = new SimisFile(file.Output, true, convertZLIB, inputAce.Ace); outputAce.Write(); } else if (inputExt == ".ACE") { // ACE -> *** var inputAce = new SimisFile(file.Input, provider); var width = convertRoundtrip ? inputAce.Ace.Image.Max(i => i.Width) : inputAce.Ace.Image[0].Width; var height = convertRoundtrip ? inputAce.Ace.Image.Sum(i => i.Height) : inputAce.Ace.Image[0].Height; var outputImage = new Bitmap(width * (convertRoundtrip ? 2 : 1), height, PixelFormat.Format32bppArgb); using (var g = Graphics.FromImage(outputImage)) { g.FillRectangle(Brushes.Transparent, 0, 0, outputImage.Width, outputImage.Height); if (convertRoundtrip) { var y = 0; foreach (var image in inputAce.Ace.Image) { g.DrawImageUnscaled(image.ImageColor, 0, y); g.DrawImageUnscaled(image.ImageMask, width, y); y += image.Height; } } else { g.DrawImageUnscaled(inputAce.Ace.Image[0].GetImage(inputAce.Ace.HasAlpha ? SimisAceImageType.ColorAndAlpha : inputAce.Ace.HasMask ? SimisAceImageType.ColorAndMask : SimisAceImageType.ColorOnly), 0, 0); } } outputImage.Save(file.Output); } else if (outputExt == ".ACE") { // *** -> ACE var inputImage = Image.FromFile(file.Input); var width = inputImage.Width; var height = inputImage.Height; // Roundtripping or not, textures have special requirements of 2^n width and height. if (convertTexture) { if (convertRoundtrip) { var expectedHeight = (int)Math.Pow(2, (int)(Math.Log(height + 1) / Math.Log(2))) - 1; if (height != expectedHeight) { throw new InvalidOperationException(String.Format("Image height {0} is not correct for round-tripping a texture. It must be 2^n-1.", height, expectedHeight)); } height = (height + 1) / 2; // Roundtripping always has two columns: color and mask. width /= 2; } else { var expectedHeight = (int)Math.Pow(2, (int)(Math.Log(height) / Math.Log(2))); if (height != expectedHeight) { throw new InvalidOperationException(String.Format("Image height {0} is not correct for a texture. It must be 2^n.", height, expectedHeight)); } } var expectedWidth = (int)Math.Pow(2, (int)(Math.Log(width) / Math.Log(2))); if (width != expectedWidth) { throw new InvalidOperationException(String.Format("Image width {0} is not correct for a texture. It must be 2^n.", width, expectedWidth)); } if (width != height) { throw new InvalidOperationException(String.Format("Image width {0} and height {1} must be equal for a texture.", width, height)); } } if (convertRoundtrip || convertTexture) { var imageCount = 1 + (int)(convertTexture ? Math.Log(height) / Math.Log(2) : 0); var aceChannels = new[] { new SimisAceChannel(8, SimisAceChannelId.Red), new SimisAceChannel(8, SimisAceChannelId.Green), new SimisAceChannel(8, SimisAceChannelId.Blue), new SimisAceChannel(8, SimisAceChannelId.Alpha), new SimisAceChannel(1, SimisAceChannelId.Mask), }; // Remove the alpha channel for DXT1. if (convertDXT1) { aceChannels = new[] { aceChannels[0], aceChannels[1], aceChannels[2], aceChannels[4] }; } var aceImages = new SimisAceImage[imageCount]; var y = 0; for (var i = 0; i < imageCount; i++) { var scale = (int)Math.Pow(2, i); var colorImage = new Bitmap(width / scale, height / scale, PixelFormat.Format32bppArgb); var maskImage = new Bitmap(width / scale, height / scale, PixelFormat.Format32bppRgb); var sourceRect = convertRoundtrip ? new Rectangle(0, y, width / scale, height / scale) : new Rectangle(0, 0, width, height); using (var g = Graphics.FromImage(colorImage)) { g.DrawImage(inputImage, new Rectangle(Point.Empty, colorImage.Size), sourceRect, GraphicsUnit.Pixel); } sourceRect.X = width; using (var g = Graphics.FromImage(maskImage)) { if (width < inputImage.Width) { g.DrawImage(inputImage, new Rectangle(Point.Empty, maskImage.Size), sourceRect, GraphicsUnit.Pixel); } else { g.FillRectangle(Brushes.White, new Rectangle(Point.Empty, maskImage.Size)); } } aceImages[i] = new SimisAceImage(colorImage, maskImage); y += colorImage.Height; } var ace = new SimisAce((convertDXT1 ? 0x10 : 0x00) + (convertTexture ? 0x05 : 0x00), width, height, convertDXT1 ? 0x12 : 0x00, 0, "Unknown", "JGR Image File", new byte[44], aceChannels, aceImages, new byte[0], new byte[0]); var aceFile = new SimisFile(file.Output, true, convertZLIB, ace); aceFile.Write(); } else { // TODO: Handle the various alpha/mask fun here. var aceChannels = new[] { new SimisAceChannel(8, SimisAceChannelId.Red), new SimisAceChannel(8, SimisAceChannelId.Green), new SimisAceChannel(8, SimisAceChannelId.Blue), new SimisAceChannel(8, SimisAceChannelId.Alpha), }; // Replace the alpha channel with mask channel for DXT1. if (convertDXT1) { aceChannels[3] = new SimisAceChannel(1, SimisAceChannelId.Mask); } var maskImage = new Bitmap(width, height, PixelFormat.Format32bppRgb); using (var g = Graphics.FromImage(maskImage)) { g.FillRectangle(Brushes.White, 0, 0, maskImage.Width, maskImage.Height); } var aceImages = new[] { new SimisAceImage(new Bitmap(inputImage), maskImage), }; var ace = new SimisAce(convertDXT1 ? 0x10 : 0x00, width, height, convertDXT1 ? 0x12 : 0x00, 0, "Unknown", "JGR Image File", new byte[44], aceChannels, aceImages, new byte[0], new byte[0]); var aceFile = new SimisFile(file.Output, true, convertZLIB, ace); aceFile.Write(); } } else { // *** -> *** Image.FromFile(file.Input).Save(file.Output); } } catch (Exception ex) { Console.Error.WriteLine(ex.ToString()); } }; if (threading > 1) { var filesEnumerator = files.GetEnumerator(); var filesFinished = false; var threads = new List <Thread>(threading); for (var i = 0; i < threading; i++) { threads.Add(new Thread(() => { ConversionFile file; while (true) { lock (filesEnumerator) { if (filesFinished || !filesEnumerator.MoveNext()) { filesFinished = true; break; } file = filesEnumerator.Current; } ConvertFile(file); } })); } foreach (var thread in threads) { thread.Start(); } foreach (var thread in threads) { thread.Join(); } } else { foreach (var file in files) { ConvertFile(file); } } }