/// <summary> /// Resolves #include declarations in the file before the code is evaluated internally by MonoGame. /// </summary> /// <remarks> /// This resolves the #include declarations before the code is processed by MonoGame. This is required /// because the code is stored as a temporary file before being processed, instead of being processed at /// the source (because once we get the code, we are not processing per-file but per-asset). /// </remarks> /// <param name="assetDependencies">The asset dependencies interface to get included files from.</param> /// <param name="dirName">The folder name that this asset resides in.</param> /// <param name="code">The code to process.</param> /// <returns>The resulting code.</returns> protected async Task <string> ResolveIncludes(IAssetDependencies assetDependencies, string dirName, string code) { var regex = new Regex("^#include <([^>]+)>\\s*$", RegexOptions.IgnoreCase | RegexOptions.Multiline); var matches = regex.Matches(code).OfType <Match>().ToList(); foreach (var currentMatch in matches) { var relName = currentMatch.Groups[1].Captures[0].Value; var relComponents = relName.Split(new[] { '\\', '/' }); var dirComponents = dirName.Split('.').ToList(); for (var i = 0; i < relComponents.Length; i++) { if (relComponents[i] == ".") { // Do nothing, same directory. } else if (relComponents[i] == "..") { // Parent directory. if (dirComponents.Count > 0) { dirComponents.RemoveAt(dirComponents.Count - 1); } } else { dirComponents.Add(relComponents[i]); } } var includeFile = await assetDependencies.GetOptionalCompileTimeFileDependency(string.Join(".", dirComponents.ToArray())).ConfigureAwait(false); if (includeFile == null) { throw new InvalidOperationException( "Unable to include " + relName + "; resolved name " + dirComponents.ToArray() + " does not exist!"); } // TODO: Calculate original filename from the PC that this asset was sourced from/ var nameOnDisk = string.Join("\\", dirComponents.ToArray()); using (var reader = new StreamReader(await includeFile.GetContentStream().ConfigureAwait(false))) { var replace = reader.ReadToEnd(); replace = "#line 1 \"" + nameOnDisk + "\"\r\n" + replace; replace = await this.ResolveIncludes(assetDependencies, Path.GetDirectoryName(includeFile.Name.Replace(".", "/")).Replace(Path.DirectorySeparatorChar, '.'), replace).ConfigureAwait(false); code = code.Replace(currentMatch.Value, replace); } } return(code); }
public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output) { var otherAnimations = new Dictionary <string, byte[]>(); if (assetFile.Extension != "x") { var otherFiles = (await assetDependencies.GetAvailableCompileTimeFiles()) .Where(x => x.Name.StartsWith(assetFile.Name + "-")) .ToArray(); foreach (var otherAnim in otherFiles) { using (var otherStream = await otherAnim.GetContentStream().ConfigureAwait(false)) { var b = new byte[otherStream.Length]; await otherStream.ReadAsync(b, 0, b.Length).ConfigureAwait(false); otherAnimations[otherAnim.Name.Substring((assetFile.Name + "-").Length)] = b; } } } var nameComponents = assetFile.Name.Split('.'); nameComponents[nameComponents.Length - 1] = "_FolderOptions"; var folderOptionsFile = await assetDependencies.GetOptionalCompileTimeFileDependency(string.Join(".", nameComponents)).ConfigureAwait(false); string[] importFolderOptions = null; if (folderOptionsFile != null) { using (var optionsReader = new StreamReader(await folderOptionsFile.GetContentStream().ConfigureAwait(false))) { importFolderOptions = optionsReader.ReadToEnd() .Trim() .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .Where(x => !x.StartsWith("#")) .ToArray(); } } var optionsFile = await assetDependencies.GetOptionalCompileTimeFileDependency(assetFile.Name + ".Options").ConfigureAwait(false); string[] importOptions = null; if (optionsFile != null) { using (var optionsReader = new StreamReader(await optionsFile.GetContentStream().ConfigureAwait(false))) { importOptions = optionsReader.ReadToEnd() .Trim() .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .Where(x => !x.StartsWith("#")) .ToArray(); } } if (importOptions == null) { importOptions = importFolderOptions; } byte[] modelData; using (var stream = await assetFile.GetContentStream().ConfigureAwait(false)) { modelData = new byte[stream.Length]; await stream.ReadAsync(modelData, 0, modelData.Length).ConfigureAwait(false); } var reader = new AssimpReader(_modelRenderConfigurations, _renderBatcher); var model = reader.Load(modelData, assetFile.Name, assetFile.Extension, otherAnimations, importOptions); var data = _modelSerializer.Serialize(model); output.SetLoader <IAssetLoader <ModelAsset> >(); output.SetByteArray("Data", data); }
public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output) { var tempPath = System.IO.Path.GetTempFileName(); try { using (var stream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None)) { using (var sourceStream = await assetFile.GetContentStream().ConfigureAwait(false)) { await sourceStream.CopyToAsync(stream).ConfigureAwait(false); } } var importer = new TextureImporter(); var monogameOutput = importer.Import(tempPath, new DummyContentImporterContext()); var originalWidth = monogameOutput.Faces[0][0].Width; var originalHeight = monogameOutput.Faces[0][0].Height; var nameComponents = assetFile.Name.Split('.'); nameComponents[nameComponents.Length - 1] = "_FolderOptions"; var folderOptionsFile = await assetDependencies.GetOptionalCompileTimeFileDependency(string.Join(".", nameComponents)).ConfigureAwait(false); string[] importFolderOptions = null; if (folderOptionsFile != null) { using (var optionsReader = new StreamReader(await folderOptionsFile.GetContentStream().ConfigureAwait(false))) { importFolderOptions = optionsReader.ReadToEnd() .Trim() .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .Where(x => !x.StartsWith("#")) .ToArray(); } } var optionsFile = await assetDependencies.GetOptionalCompileTimeFileDependency(assetFile.Name + ".Options").ConfigureAwait(false); string[] importOptions = null; if (optionsFile != null) { using (var optionsReader = new StreamReader(await optionsFile.GetContentStream().ConfigureAwait(false))) { importOptions = optionsReader.ReadToEnd() .Trim() .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .Where(x => !x.StartsWith("#")) .ToArray(); } } if (importOptions == null) { importOptions = importFolderOptions; } if (importOptions == null) { importOptions = new string[0]; } var allowResizeToPowerOfTwo = !IsPowerOfTwo((ulong)originalWidth) || !IsPowerOfTwo((ulong)originalHeight); var allowMakeSquare = originalWidth != originalHeight; var manager = new PipelineManager( Environment.CurrentDirectory, Environment.CurrentDirectory, Environment.CurrentDirectory); TextureContent content = CompileTexture(assetFile, platform, monogameOutput, importOptions, allowResizeToPowerOfTwo, allowMakeSquare, manager); Console.WriteLine("Texture " + assetFile.Name + " resized " + originalWidth + "x" + originalHeight + " -> " + content.Faces[0][0].Width + "x" + content.Faces[0][0].Height); output.SetLoader <IAssetLoader <TextureAsset> >(); output.SetPlatform(platform); output.SetByteArray("Data", CompileAndGetBytes(content)); output.SetInt32("OriginalWidth", originalWidth); output.SetInt32("OriginalHeight", originalHeight); } finally { try { File.Delete(tempPath); } catch { } } }