/// <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)
        {
            if (IntPtr.Size == 4)
            {
                throw new NotSupportedException("Font compilation is only supported under a 64-bit process.");
            }

            var json = string.Empty;

            using (var reader = new StreamReader(await assetFile.GetContentStream().ConfigureAwait(false)))
            {
                json = await reader.ReadToEndAsync().ConfigureAwait(false);
            }

            var fontDefinition = JsonConvert.DeserializeObject <FontDefinition>(json);

            foreach (var fontDesc in this.GetDescriptionsForAsset(fontDefinition))
            {
                try
                {
                    var manager = new PipelineManager(
                        Environment.CurrentDirectory,
                        Environment.CurrentDirectory,
                        Environment.CurrentDirectory);
                    var dictionary = new OpaqueDataDictionary();
                    var processor  = manager.CreateProcessor("FontDescriptionProcessor", dictionary);
                    var context    = new DummyContentProcessorContext(TargetPlatformCast.ToMonoGamePlatform(platform));
                    var content    = processor.Process(fontDesc, context);

                    output.SetLoader <IAssetLoader <FontAsset> >();
                    output.SetPlatform(platform);
                    output.SetByteArray("Data", CompileAndGetBytes(content));
                    output.SetString("FontName", fontDesc.FontName);
                    output.SetFloat("FontSize", fontDesc.Size);
                    output.SetBoolean("UseKerning", fontDesc.UseKerning);
                    output.SetFloat("Spacing", fontDesc.Spacing);

                    // Font compilation was successful.
                    return;
                }
                catch (ArgumentOutOfRangeException)
                {
                    // The user might not have the font installed...
                }
                catch (NullReferenceException)
                {
                    // The user might not have the font installed...
                }
            }

            throw new InvalidOperationException("Unable to locate any font with one of the names: " + fontDefinition.FontName);
        }
        public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output)
        {
            string level;

            using (var reader = new StreamReader(await assetFile.GetContentStream().ConfigureAwait(false)))
            {
                level = await reader.ReadToEndAsync().ConfigureAwait(false);
            }

            output.SetLoader <IAssetLoader <LevelAsset> >();
            output.SetString("LevelData", level);
            output.SetString("LevelDataFormat", "OgmoEditor");
        }
Exemple #4
0
        public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output)
        {
            TilesetJson tilesetJson;

            using (var stream = new StreamReader(await assetFile.GetContentStream().ConfigureAwait(false)))
            {
                tilesetJson = JsonConvert.DeserializeObject <TilesetJson>(await stream.ReadToEndAsync().ConfigureAwait(false));
            }

            output.SetLoader <IAssetLoader <TilesetAsset> >();
            output.SetString("TextureName", tilesetJson.TextureName);
            output.SetInt32("CellWidth", tilesetJson.CellWidth);
            output.SetInt32("CellHeight", tilesetJson.CellHeight);
        }
        public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output)
        {
            using (var reader = new StreamReader(await assetFile.GetContentStream().ConfigureAwait(false)))
            {
                var content = await reader.ReadToEndAsync().ConfigureAwait(false);

                // Validate that the XML is valid so we don't throw exceptions at runtime.
                var document = new XmlDocument();
                document.LoadXml(content);

                output.SetLoader <IAssetLoader <UserInterfaceAsset> >();
                output.SetString("UserInterfaceFormat", "XmlVersion2");
                output.SetString("UserInterfaceData", content);
            }
        }
Exemple #6
0
        public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output)
        {
            using (var content = await assetFile.GetContentStream().ConfigureAwait(false))
            {
                // Currently we just copy the raw data.  According to the XNA documentation:

                /*
                 * The Stream object must point to the head of a valid PCM wave file. Also, this wave file must be in the RIFF bitstream format.
                 * The audio format has the following restrictions:
                 * Must be a PCM wave file
                 * Can only be mono or stereo
                 * Must be 8 or 16 bit
                 * Sample rate must be between 8,000 Hz and 48,000 Hz
                 */
                output.SetLoader <IAssetLoader <AudioAsset> >();
                var bytes = new byte[content.Length];
                await content.ReadAsync(bytes, 0, bytes.Length).ConfigureAwait(false);

                output.SetByteArray("Data", bytes);
            }
        }
Exemple #7
0
        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
                {
                }
            }
        }
        public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output)
        {
            var code = string.Empty;

            using (var reader = new StreamReader(await assetFile.GetContentStream().ConfigureAwait(false)))
            {
                code = await reader.ReadToEndAsync().ConfigureAwait(false);
            }

            if (!code.Contains("// uber"))
            {
                // Do nothing with this file.
                return;
            }

            var dirName = Path.GetDirectoryName(assetFile.Name.Replace(".", "/"));

            code = await ResolveIncludes(assetDependencies, dirName.Replace(Path.DirectorySeparatorChar, '.'), code).ConfigureAwait(false);

            var allPassed   = true;
            var effectCodes = new Dictionary <string, Tuple <string, byte[], byte[]> >();

            foreach (var rawLine in code.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
            {
                var line = rawLine.Trim();
                if (line.StartsWith("#line"))
                {
                    continue;
                }
                if (!line.StartsWith("// uber "))
                {
                    break;
                }

                var components = line.Substring("// uber ".Length).Split(':');
                var name       = components[0].Trim();
                var defines    = components[1].Trim();

                Console.WriteLine();
                Console.Write("Compiling uber shader variant " + name + "... ");

                var effectOutput = new EffectContent();
                effectOutput.EffectCode = this.GetEffectPrefixCode() + code;

                string tempPath = null, tempOutputPath = null;
                try
                {
                    tempPath       = Path.GetTempFileName();
                    tempOutputPath = Path.GetTempFileName();

                    using (var writer = new StreamWriter(tempPath))
                    {
                        writer.Write(effectOutput.EffectCode);
                    }

                    effectOutput.Identity = new ContentIdentity(tempPath);

                    var debugContent = EffectCompilerHelper.Compile(
                        effectOutput,
                        tempOutputPath,
                        platform,
                        true,
                        defines);
                    var releaseContent = EffectCompilerHelper.Compile(
                        effectOutput,
                        tempOutputPath,
                        platform,
                        false,
                        defines);

                    effectCodes[name] = new Tuple <string, byte[], byte[]>(defines, debugContent.GetEffectCode(), releaseContent.GetEffectCode());
                    Console.Write("done.");
                }
                catch (InvalidContentException ex)
                {
                    Console.WriteLine("failed.");
                    Console.Write(ex.Message.Trim());
                    allPassed = false;
                }
                finally
                {
                    if (tempOutputPath != null)
                    {
                        File.Delete(tempOutputPath);
                    }

                    if (tempOutputPath != null)
                    {
                        File.Delete(tempPath);
                    }
                }
            }

            Console.WriteLine();
            Console.Write("Finalizing uber shader compilation... ");

            if (!allPassed)
            {
                throw new Exception("One or more uber shader variants failed to compile (see above!)");
            }

            using (var memory = new MemoryStream())
            {
                using (var writer = new BinaryWriter(memory))
                {
                    writer.Write((uint)2);
                    writer.Write((uint)effectCodes.Count);
                    foreach (var kv in effectCodes)
                    {
                        writer.Write(kv.Key);
                        writer.Write(kv.Value.Item1);
                        writer.Write(kv.Value.Item2.Length);
                        writer.Write(kv.Value.Item2);
                        writer.Write(kv.Value.Item3.Length);
                        writer.Write(kv.Value.Item3);
                    }

                    var len  = memory.Position;
                    var data = new byte[len];
                    memory.Seek(0, SeekOrigin.Begin);
                    memory.Read(data, 0, data.Length);

                    output.SetLoader <IAssetLoader <UberEffectAsset> >();
                    output.SetPlatform(platform);
                    output.SetByteArray("Data", data);
                }
            }
        }
        public async Task CompileAsync(IAssetFsFile assetFile, IAssetDependencies assetDependencies, TargetPlatform platform, IWritableSerializedAsset output)
        {
            var code = string.Empty;

            using (var reader = new StreamReader(await assetFile.GetContentStream().ConfigureAwait(false)))
            {
                code = await reader.ReadToEndAsync().ConfigureAwait(false);
            }

            if (code.Contains("// uber"))
            {
                // Do nothing with this file.
                return;
            }

            var dirName = Path.GetDirectoryName(assetFile.Name.Replace(".", "/"));

            code = await ResolveIncludes(assetDependencies, dirName.Replace(Path.DirectorySeparatorChar, '.'), code).ConfigureAwait(false);

            var effectContent = new EffectContent();

            effectContent.EffectCode = this.GetEffectPrefixCode() + code;

            var tempPath = Path.GetTempFileName();

            using (var writer = new StreamWriter(tempPath))
            {
                writer.Write(effectContent.EffectCode);
            }

            effectContent.Identity = new ContentIdentity(tempPath);

            var tempOutputPath = Path.GetTempFileName();

            var debugContent = EffectCompilerHelper.Compile(
                effectContent,
                tempOutputPath,
                platform,
                true,
                string.Empty);
            var releaseContent = EffectCompilerHelper.Compile(
                effectContent,
                tempOutputPath,
                platform,
                false,
                string.Empty);

            using (var stream = new MemoryStream())
            {
                using (var writer = new BinaryWriter(stream))
                {
                    // Magic flag that indicates new compiled effect format.
                    writer.Write((uint)0x12345678);

                    // Version 1 of new effect format.
                    writer.Write((uint)1);

                    var debugCode   = debugContent.GetEffectCode();
                    var releaseCode = releaseContent.GetEffectCode();

                    writer.Write(debugCode.Length);
                    writer.Write(debugCode);
                    writer.Write(releaseCode.Length);
                    writer.Write(releaseCode);

                    var p = stream.Position;
                    var b = new byte[p];
                    stream.Seek(0, SeekOrigin.Begin);
                    stream.Read(b, 0, b.Length);

                    output.SetLoader <IAssetLoader <EffectAsset> >();
                    output.SetPlatform(platform);
                    output.SetByteArray("Data", b);
                }
            }

            File.Delete(tempPath);
            File.Delete(tempOutputPath);
        }