public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context) { if (Environment.OSVersion.Platform != PlatformID.Unix) { return(base.Process(input, context)); } var code = ResolveCode(input); var platform = context.TargetPlatform; var version = typeof(EffectContent).Assembly.GetName().Version; string error = String.Empty; byte[] buf = Mgfx.RunMGCB(code, platform.ToString(), WinePath, CompilerPath, out error); var resultSer = JsonConvert.SerializeObject(new Result() { Compiled = buf, Error = error }); var result = JsonDeSerializer(resultSer); if (!string.IsNullOrEmpty(result.Error)) { throw new Exception(result.Error); } if (result.Compiled == null || result.Compiled.Length == 0) { throw new Exception("There was an error compiling the effect"); } return(new CompiledEffectContent(result.Compiled)); return(null); }
/// <summary> /// Processes a PaletteInfo object into a PaletteMaterialContent object. /// </summary> /// <param name="input">The PaletteInfo to process.</param> /// <param name="context">The processor context.</param> /// <returns>The processed PaletteMaterialContent</returns> public override PaletteMaterialContent Process(PaletteInfo input, ContentProcessorContext context) { #if XNA4 throw new NotImplementedException(); #else // Set all the variables based on the input. EffectProcessor effectProcessor = new EffectProcessor(); EffectContent effectContent = new EffectContent(); effectContent.EffectCode = input.SourceCode; CompiledEffect compiled; if (context.TargetPlatform == TargetPlatform.Xbox360) { compiled = Effect.CompileEffectFromSource( input.SourceCode, null, null, CompilerOptions.None, TargetPlatform.Xbox360); } else { compiled = effectProcessor.Process(effectContent, context); } PaletteMaterialContent content = new PaletteMaterialContent(); content.PaletteSize = input.PaletteSize; content.ByteCode = compiled.GetEffectCode(); BasicMaterialContent basic = input.BasicContent; content.Alpha = basic.Alpha; content.DiffuseColor = basic.DiffuseColor; content.EmissiveColor = basic.EmissiveColor; content.Name = basic.Name; content.SpecularColor = basic.SpecularColor; content.SpecularPower = basic.SpecularPower; content.Texture = basic.Texture; content.VertexColorEnabled = basic.VertexColorEnabled; return(content); #endif }
static byte[] GetEffectCode(string filename) { var basePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Content"); var effectFileName = System.IO.Path.Combine(basePath, filename + ".fx"); EffectContent effectSource = new EffectContent { Identity = new ContentIdentity(effectFileName), EffectCode = File.ReadAllText(effectFileName), }; EffectProcessor processor = new EffectProcessor(); CompiledEffectContent compiledEffect = processor.Process(effectSource, new ProcessorContext()); return(compiledEffect.GetEffectCode()); #if DEBUG_SHADER_CODE // NOTE: We may need to implement a CompilerIncludeHandler here if we ever use #include in our shaders. var compiledEffect = Effect.CompileEffectFromFile(effectFileName, null, null, CompilerOptions.Debug, TargetPlatform.Windows); if (!compiledEffect.Success) { throw new InvalidOperationException(compiledEffect.ErrorsAndWarnings); } return(compiledEffect.GetEffectCode()); #else // We have to use a file stream instead of passing the file name directly because the latter method just botches up non-ASCII paths. :( //using (var effectFileStream = File.OpenRead(effectFileName)) //{ // // NOTE: We may need to implement a CompilerIncludeHandler here if we ever use #include in our shaders. // var compiledEffect = Effect.CompileEffectFromFile(effectFileStream, null, null, CompilerOptions.None, TargetPlatform.Windows); // if (!compiledEffect.Success) // throw new InvalidOperationException(compiledEffect.ErrorsAndWarnings); // return compiledEffect.GetEffectCode(); //} #endif }
/// <summary> /// Processes a PaletteInfo object into a PaletteMaterialContent object. /// </summary> /// <param name="input">The PaletteInfo to process.</param> /// <param name="context">The processor context.</param> /// <returns>The processed PaletteMaterialContent</returns> public override PaletteMaterialContent Process(PaletteInfo input, ContentProcessorContext context) { // Set all the variables based on the input. EffectProcessor effectProcessor = new EffectProcessor(); EffectContent effectContent = new EffectContent(); effectContent.EffectCode = input.SourceCode; CompiledEffect compiled = effectProcessor.Process(effectContent, context); PaletteMaterialContent content = new PaletteMaterialContent(); content.PaletteSize = input.PaletteSize; content.ByteCode = compiled.GetEffectCode(); BasicMaterialContent basic = input.BasicContent; content.Alpha = basic.Alpha; content.DiffuseColor = basic.DiffuseColor; content.EmissiveColor = basic.EmissiveColor; content.Name = basic.Name; content.SpecularColor = basic.SpecularColor; content.SpecularPower = basic.SpecularPower; content.Texture = basic.Texture; content.VertexColorEnabled = basic.VertexColorEnabled; return(content); }
private static string ResolveCode(EffectContent input) { var sb = new StringBuilder(); foreach (var line in input.EffectCode.Split('\n')) { if (line.StartsWith("//", StringComparison.InvariantCultureIgnoreCase)) { continue; } if (line.StartsWith("#include", StringComparison.InvariantCultureIgnoreCase)) { var startIndex = line.IndexOf("\"", StringComparison.InvariantCultureIgnoreCase) + 1; var file = line.Substring(startIndex, line.IndexOf("\"", startIndex, StringComparison.InvariantCultureIgnoreCase) - startIndex); var root = Path.GetDirectoryName(input.Identity.SourceFilename); ReadInclude(sb, Path.Combine(root ?? throw new NullReferenceException("Malformed .fx file"), file)); } else { sb.AppendLine(line.Trim()); } } return(sb.ToString()); }
public static byte[] GetEffectCodeBytes(string filename) { EffectContent content = importer.Import("./" + filename, new CustomImporterContext( )); CompiledEffectContent compiled = processor.Process(content, new CustomProcessorContext( )); return(compiled.GetEffectCode( )); }
string ResolveCode(EffectContent input) { StringBuilder sb = new StringBuilder(); foreach (var line in input.EffectCode.Split(new char [] { '\n' })) { if (line.StartsWith("//", StringComparison.InvariantCultureIgnoreCase)) { continue; } if (line.StartsWith("#include", StringComparison.InvariantCultureIgnoreCase)) { // read the file var startIndex = line.IndexOf("\"", StringComparison.InvariantCultureIgnoreCase) + 1; var file = line.Substring(startIndex, line.IndexOf("\"", startIndex, StringComparison.InvariantCultureIgnoreCase) - startIndex); var root = Path.GetDirectoryName(input.Identity.SourceFilename); ReadInclude(sb, Path.Combine(root, file)); } else { sb.AppendLine(line.Trim()); } } return(sb.ToString()); }
string ExpandIncludes(EffectContent input) { var sb = new StringBuilder(); var root = Path.GetDirectoryName(input.Identity.SourceFilename); Include(sb, input.EffectCode.Split('\n'), root); return(sb.ToString()); }
public static Effect Compile(GraphicsDevice g, string file) { EffectImporter ei = new EffectImporter(); EffectContent ec = ei.Import(file, new XNADynImporterContext()); EffectProcessor ep = new EffectProcessor(); var cec = ep.Process(ec, new XNADynProcessorContext()); return(new Effect(g, cec.GetEffectCode())); }
static int Main(string[] args) { // Make sure we have the right number of commandline arguments. if (args.Length != 4) { Console.Error.WriteLine("Usage: CompileEffect <targetPlatform> <targetProfile> <input.fx> <output.bin>"); return(1); } // Parse the commandline arguments. TargetPlatform targetPlatform; if (!Enum.TryParse(args[0], true, out targetPlatform)) { Console.Error.WriteLine("Invalid target platform {0}. Valid options are {1}.", args[0], GetEnumValues <TargetPlatform>()); return(1); } GraphicsProfile targetProfile; if (!Enum.TryParse(args[1], true, out targetProfile)) { Console.Error.WriteLine("Invalid target profile {0}. Valid options are {1}.", args[1], GetEnumValues <GraphicsProfile>()); return(1); } string inputFilename = args[2]; string outputFilename = args[3]; try { Console.WriteLine("Compiling {0} -> {1} for {2}, {3}", Path.GetFileName(inputFilename), outputFilename, targetPlatform, targetProfile); ContentBuildLogger logger = new CustomLogger(); // Import the effect source code. EffectImporter importer = new EffectImporter(); ContentImporterContext importerContext = new CustomImporterContext(logger); EffectContent sourceEffect = importer.Import(inputFilename, importerContext); // Compile the effect. EffectProcessor processor = new EffectProcessor(); ContentProcessorContext processorContext = new CustomProcessorContext(targetPlatform, targetProfile, logger); CompiledEffectContent compiledEffect = processor.Process(sourceEffect, processorContext); // Write out the compiled effect code. File.WriteAllBytes(outputFilename, compiledEffect.GetEffectCode()); } catch (Exception e) { Console.Error.WriteLine("Error: {0}", e.Message); return(1); } return(0); }
public static byte[] ReadBytesFromSourceFile(string fileName) { EffectImporter importer = new EffectImporter( ); EffectProcessor processor = new EffectProcessor( ); EffectContent content = importer.Import(fileName, new ShaderImporterContext( )); CompiledEffectContent compiled = processor.Process(content, new ShaderProcessorContext( )); return(compiled.GetEffectCode( )); }
private static bool AttemptEffectCompilation( ContentProcessorContext context, StitchedEffectContent input, StitchedEffectSymbol stitchedEffect, ShaderProfile shaderProfile, out CompiledEffectContent compiledEffect) { // Generate effect code. StringWriter writer = new StringWriter(); EffectCodeGenerator codeGenerator = new EffectCodeGenerator(stitchedEffect, shaderProfile, writer); codeGenerator.GenerateCode(); string effectCode = writer.ToString(); // Save effect code so that if there are errors, we'll be able to view the generated .fx file. string tempEffectFile = GetTempEffectFileName(input); File.WriteAllText(tempEffectFile, effectCode, Encoding.GetEncoding(1252)); // Process effect code. EffectProcessor effectProcessor = new EffectProcessor { DebugMode = EffectProcessorDebugMode.Auto, Defines = null }; EffectContent effectContent = new EffectContent { EffectCode = effectCode, Identity = new ContentIdentity(tempEffectFile), Name = input.Name }; try { compiledEffect = effectProcessor.Process(effectContent, context); // This is only needed if the compilation was successful - if it failed, // a more specific error message (with link to the generated file) // will be shown to the user. context.Logger.LogImportantMessage(string.Format("{0} : Stitched effect generated (double-click this message to view).", tempEffectFile)); return(true); } catch (InvalidContentException ex) { if (ErrorIndicatesNeedForShaderModel3(ex.Message)) { compiledEffect = null; return(false); } throw; } }
public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context) { if (Environment.OSVersion.Platform != PlatformID.Unix) { return(base.Process(input, context)); } string hlslCode = ExpandIncludes(input.EffectCode); byte[] compiled = Compile(context.TargetPlatform, input.Identity, hlslCode); return(new CompiledEffectContent(compiled)); }
public static CompiledEffectContent Compile(EffectContent output, string tempOutputPath, TargetPlatform platform, bool isDebug, string defines) { var processor = new EffectProcessor(); var context = new DummyContentProcessorContext(TargetPlatformCast.ToMonoGamePlatform(platform)); context.ActualOutputFilename = tempOutputPath; processor.DebugMode = isDebug ? EffectProcessorDebugMode.Debug : EffectProcessorDebugMode.Optimize; processor.Defines = defines + ";" + GetPlatformDefineForEffect(platform) + ";" + (isDebug ? "CONFIGURATION_DEBUG" : "CONFIGURATION_RELEASE"); return(processor.Process(output, context)); }
static byte[] GetEffectCode(string filename) { var basePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Content"); var effectFileName = System.IO.Path.Combine(basePath, filename + ".fx"); var input = new EffectContent() { // Bizarrely, MonoGame loads the content from the identity's filename and ignores the EffectCode property, so we don't need to bother loading the file ourselves Identity = new ContentIdentity(effectFileName), }; var context = new ProcessorContext(); var processor = new EffectProcessor(); var effect = processor.Process(input, context); return(effect.GetEffectCode()); }
/// <summary> /// The compile. /// </summary> /// <param name="asset"> /// The asset. /// </param> /// <param name="platform"> /// The platform. /// </param> public void Compile(EffectAsset asset, TargetPlatform platform) { if (string.IsNullOrEmpty(asset.Code)) { return; } var output = new EffectContent(); output.EffectCode = this.GetEffectPrefixCode() + asset.Code; var tempPath = Path.GetTempFileName(); using (var writer = new StreamWriter(tempPath)) { writer.Write(output.EffectCode); } output.Identity = new ContentIdentity(tempPath); var tempOutputPath = Path.GetTempFileName(); var processor = new EffectProcessor(); var context = new DummyContentProcessorContext(TargetPlatformCast.ToMonoGamePlatform(platform)); context.ActualOutputFilename = tempOutputPath; var content = processor.Process(output, context); asset.PlatformData = new PlatformData { Platform = platform, Data = content.GetEffectCode() }; File.Delete(tempPath); File.Delete(tempOutputPath); try { asset.ReloadEffect(); } catch (NoAssetContentManagerException) { } }
public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context) { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { return(base.Process(input, context)); } var code = ResolveCode(input); var platform = context.TargetPlatform; var version = typeof(EffectContent).Assembly.GetName().Version; var client = new HttpClient { Timeout = TimeSpan.FromMinutes(5), BaseAddress = new Uri("http://127.0.0.1:60321/") }; var response = client.PostAsync("api/Effect", new StringContent(JsonSerializer(new Data { Platform = platform.ToString(), Code = code, Version = $"{version}", }), Encoding.UTF8, "application/json")).Result; if (!response.IsSuccessStatusCode) { throw new Exception(response.StatusCode.ToString()); } var data = response.Content.ReadAsStringAsync().Result; var result = JsonDeSerializer(data); if (!string.IsNullOrEmpty(result.Error)) { throw new Exception(result.Error); } if (result.Compiled == null || result.Compiled.Length == 0) { throw new Exception("There was an error compiling the effect"); } return(new CompiledEffectContent(result.Compiled)); }
public override Effect Load(IResource resource, LoaderParameters parameters) { FileInfo info = new FileInfo(resource.FullName); if (!info.Exists) { throw new FileNotFoundException("Effect file does not exist in directory"); } EffectContent content = new EffectContent(); content.Identity = new ContentIdentity(resource.FullName); content.EffectCode = File.ReadAllText(resource.FullName); CompiledEffectContent compiled = _processor.Process(content, _xnaContext); Effect effect = new Effect(compiled.GetEffectCode()); effect.Name = resource.Name; return(effect); }
public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context) { if (Environment.OSVersion.Platform != PlatformID.Unix) { return(base.Process(input, context)); } var code = ExpandIncludes(input); var platform = context.TargetPlatform; var buf = RunMGCB(code, DockerImage, platform.ToString(), out var error); if (!string.IsNullOrEmpty(error)) { throw new Exception(error); } if (buf == null || buf.Length == 0) { throw new Exception("There was an error compiling the effect"); } return(new CompiledEffectContent(buf)); }
public IProgram Link(Shader shader, IEnumerable <object> units) { var sources = units.Cast <Tuple <ShaderType, SourceDescription> >(); //var frag = sources.Where(t => t.Item1 == ShaderType.FragmentShader).Select(t => t.Item2); //var vert = sources.Where(t => t.Item1 == ShaderType.VertexShader).Select(t => t.Item2); var all = sources.Select(t => t.Item2); var merged = all.Skip(1).Aggregate(all.First(), (current, d) => current.Merge(d)); // XNA doesnt support shader compilation so we have to generate a .fx file // with everything merged var cp = new SLContentProcessorContext(); var ep = new EffectProcessor(); var ec = new EffectContent { EffectCode = merged.ToHlslFx() }; var compiledEffect = ep.Process(ec, cp); return(new Program(compiledEffect)); }
public Effect?Build(GraphicsDevice device, string path) { var content = new EffectContent { Identity = new ContentIdentity(path), EffectCode = File.ReadAllText(path) }; var processor = new EffectProcessor(); try { var compiled = processor.Process(content, new ProcessorContext(this.Logger, path)); return(new Effect(device, compiled.GetEffectCode())); } catch (InvalidContentException cex) { var match = this.EffectCompilerPattern.Match(cex.Message); if (match.Success) { var line = match.Captures[0].Value; var message = $"At {line}"; this.Logger.Error($"Failed to reload {path}\n\n{message}"); } else { this.Logger.Error(cex, "Failed to reload {@file}", path); } } catch (Exception ex) { this.Logger.Error(ex, "Failed to reload {@file}", path); } return(null); }
private Exception ProcessErrorsAndWarnings(string errorsAndWarnings, EffectContent input, ContentProcessorContext context) { // Split the errors by lines. var errors = errorsAndWarnings.Split('\n'); // Process each error line extracting the location and message information. for (var i = 0; i < errors.Length; i++) { // Skip blank lines. if (errors[i].StartsWith(Environment.NewLine)) { break; } // find some unique characters in the error string var openIndex = errors[i].IndexOf('('); var closeIndex = errors[i].IndexOf(')'); // can't process the message if it has no line counter if (openIndex == -1 || closeIndex == -1) { continue; } // find the error number, then move forward into the message var errorIndex = errors[i].IndexOf('X', closeIndex); if (errorIndex < 0) { return(new InvalidContentException(errors[i], input.Identity)); } // trim out the data we need to feed the logger var fileName = errors[i].Remove(openIndex); var lineAndColumn = errors[i].Substring(openIndex + 1, closeIndex - openIndex - 1); var description = errors[i].Substring(errorIndex); // when the file name is not present, the error can be found in the root file if (string.IsNullOrEmpty(fileName)) { fileName = input.Identity.SourceFilename; } // ensure that the file data points toward the correct file var fileInfo = new FileInfo(fileName); if (!fileInfo.Exists) { var parentFile = new FileInfo(input.Identity.SourceFilename); fileInfo = new FileInfo(Path.Combine(parentFile.Directory.FullName, fileName)); } fileName = fileInfo.FullName; // construct the temporary content identity and file the error or warning var identity = new ContentIdentity(fileName, input.Identity.SourceTool, lineAndColumn); if (errors[i].Contains("warning")) { description = "A warning was generated when compiling the effect.\n" + description; context.Logger.LogWarning(string.Empty, identity, description, string.Empty); } else if (errors[i].Contains("error")) { description = "Unable to compile the effect.\n" + description; return(new InvalidContentException(description, identity)); } } // if no exceptions were created in the above loop, generate a generic one here return(new InvalidContentException(errorsAndWarnings, input.Identity)); }
public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context) { //System.Diagnostics.Debugger.Launch(); // If this isn't a MonoGame platform then do the default processing. var platform = ContentHelper.GetMonoGamePlatform(); if (platform == MonoGamePlatform.None) { return(base.Process(input, context)); } var options = new Options(); options.SourceFile = input.Identity.SourceFilename; options.DX11Profile = platform == MonoGamePlatform.Windows8 ? true : false; options.Debug = DebugMode == EffectProcessorDebugMode.Debug; options.OutputFile = context.OutputFilename; // Parse the MGFX file expanding includes, macros, and returning the techniques. ShaderInfo shaderInfo; try { shaderInfo = ShaderInfo.FromFile(options.SourceFile, options); } catch (Exception ex) { // TODO: Extract good line numbers from mgfx parser! throw new InvalidContentException(ex.Message, input.Identity, ex); } // Create the effect object. DXEffectObject effect = null; try { effect = DXEffectObject.FromShaderInfo(shaderInfo); } catch (Exception ex) { throw ProcessErrorsAndWarnings(ex.Message, input, context); } // Write out the effect to a runtime format. CompiledEffectContent result; try { using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) effect.Write(writer, options); result = new CompiledEffectContent(stream.GetBuffer()); } } catch (Exception ex) { throw new InvalidContentException("Failed to serialize the effect!", input.Identity, ex); } return(result); }
public override TOutput Process(TInput input, ContentProcessorContext context) { Dictionary <string, Q3BSPMaterialContent> processedDictionary = new Dictionary <string, Q3BSPMaterialContent>(); #region Initialize StreamWriter, if necessary #if DEBUG StreamWriter sw = new StreamWriter(context.OutputFilename.Substring(0, context.OutputFilename.LastIndexOf('.')) + ".compiled.txt"); #else StreamWriter sw = null; #endif #endregion for (int i = 0; i < input.Count; i++) { Q3BSPMaterialContent shader = input[i]; #region Throw any errors in the parsed shader if (shader.stages.Count > 8) { throw new InvalidContentException(shader.shaderName + " has " + shader.stages.Count + " stages, but the maximum supported is 8."); } if (processedDictionary.ContainsKey(shader.shaderName)) { context.Logger.LogWarning("", new ContentIdentity(), "Material " + shader.shaderName + " is defined more than once."); continue; //throw new InvalidContentException("Material " + shader.shaderName + " is defined more than once."); } #endregion #region Log any needed warnings if (shader.stages.Count > 4 && shaderModel == ShaderModel.ShaderModel1) { context.Logger.LogWarning("", new ContentIdentity(), shader.shaderName + " has more than 4 stages, Shader Model 2.0 is required."); } #endregion EffectProcessor processor = new EffectProcessor(); processor.DebugMode = EffectProcessorDebugMode.Debug; EffectContent effectContent = new EffectContent(); effectContent.EffectCode = GenerateEffectFromShader(shader, sw); #region Compile the Effect #if DEBUG CompiledEffectContent compiledEffect = processor.Process(effectContent, context); //CompiledEffect compiledEffect = Effect.CompileEffectFromSource(GenerateEffectFromShader(shader, sw), null, null, CompilerOptions.Debug, TargetPlatform.Windows); #else processor.DebugMode = EffectProcessorDebugMode.Auto; CompiledEffectContent compiledEffect = processor.Process(effectContent, context); //CompiledEffect compiledEffect = Effect.CompileEffectFromSource(GenerateEffectFromShader(shader, sw), null, null, CompilerOptions.None, TargetPlatform.Windows); #endif #endregion /* * if (compiledEffect.ErrorsAndWarnings.Contains("error")) * { * throw new InvalidContentException(shader.shaderName + ": " + compiledEffect.ErrorsAndWarnings); * } */ shader.compiledEffect = compiledEffect; shader.ShaderCode = compiledEffect.GetEffectCode(); processedDictionary.Add(shader.shaderName, shader); } #if DEBUG sw.Flush(); sw.Dispose(); #endif return(processedDictionary); }
public void Compile(UberEffectAsset asset, TargetPlatform platform) { if (string.IsNullOrEmpty(asset.Code)) { return; } var allPassed = true; var effectCodes = new Dictionary <string, Tuple <string, byte[], byte[]> >(); foreach (var rawLine in asset.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 output = new EffectContent(); output.EffectCode = this.GetEffectPrefixCode() + asset.Code; string tempPath = null, tempOutputPath = null; try { tempPath = Path.GetTempFileName(); tempOutputPath = Path.GetTempFileName(); using (var writer = new StreamWriter(tempPath)) { writer.Write(output.EffectCode); } output.Identity = new ContentIdentity(tempPath); var debugContent = EffectCompilerHelper.Compile( output, tempOutputPath, platform, true, defines); var releaseContent = EffectCompilerHelper.Compile( output, 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); asset.PlatformData = new PlatformData { Platform = platform, Data = data }; } } try { asset.ReadyOnGameThread(); } catch (NoAssetContentManagerException) { } }
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); }
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 void Compile(EffectAsset asset, TargetPlatform platform) { if (string.IsNullOrEmpty(asset.Code)) { return; } var output = new EffectContent(); output.EffectCode = this.GetEffectPrefixCode() + asset.Code; var tempPath = Path.GetTempFileName(); using (var writer = new StreamWriter(tempPath)) { writer.Write(output.EffectCode); } output.Identity = new ContentIdentity(tempPath); var tempOutputPath = Path.GetTempFileName(); var debugContent = EffectCompilerHelper.Compile( output, tempOutputPath, platform, true, string.Empty); var releaseContent = EffectCompilerHelper.Compile( output, 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); asset.PlatformData = new PlatformData { Platform = platform, Data = b }; } } File.Delete(tempPath); File.Delete(tempOutputPath); try { asset.ReloadEffect(); } catch (NoAssetContentManagerException) { } }
public override T Load <T>(string assetName) { var g = (IGraphicsDeviceService)ServiceProvider.GetService(typeof(IGraphicsDeviceService)); if (typeof(T) == typeof(Texture2D)) { if (_textures.ContainsKey(assetName)) { return((T)(object)_textures[assetName]); } using (var img = Image.FromFile(ContentProjectManager.GetTexturePath(assetName))) { var bmp = new Bitmap(img); var data = new uint[bmp.Width * bmp.Height]; for (var y = 0; y < bmp.Height; ++y) { for (var x = 0; x < bmp.Width; ++x) { var pixel = bmp.GetPixel(x, y); data[x + y * bmp.Width] = Microsoft.Xna.Framework.Color.FromNonPremultiplied(pixel.R, pixel.G, pixel.B, pixel.A). PackedValue; } } if (g != null) { var t = new Texture2D(g.GraphicsDevice, img.Width, img.Height); t.SetData(data); _textures.Add(assetName, t); return((T)(object)t); } else { throw new InvalidOperationException("Must wait with loading until graphics device is initialized."); } } } else if (typeof(T) == typeof(Effect)) { if (_shaders.ContainsKey(assetName)) { return((T)(object)_shaders[assetName]); } var shaderPath = ContentProjectManager.GetShaderPath(assetName); if (shaderPath != null) { using (var file = File.OpenText(shaderPath)) { var sourceCode = file.ReadToEnd(); var effectSource = new EffectContent { EffectCode = sourceCode, Identity = new ContentIdentity { SourceFilename = assetName } }; var processor = new EffectProcessor(); var compiledEffect = processor.Process(effectSource, new DummyProcessorContext()); var effect = new Effect(g.GraphicsDevice, compiledEffect.GetEffectCode()); _shaders.Add(assetName, effect); return((T)(object)effect); } } } else if (typeof(T) == typeof(ParticleEffect)) { using (var xmlReader = XmlReader.Create(ContentProjectManager.GetEffectPath(assetName))) { var effect = IntermediateSerializer.Deserialize <ParticleEffect>(xmlReader, null); effect.Initialise(); effect.LoadContent(this); return((T)(object)effect); } } else if (typeof(T) == typeof(IFactory[])) { return((T)(object)FactoryManager.GetFactoriesFromFile(assetName).ToArray()); } else if (typeof(T) == typeof(ItemPool[])) { return((T)(object)ItemPoolManager.GetItemPools().ToArray()); } else if (typeof(T) == typeof(AttributePool[])) { return((T)(object)AttributePoolManager.GetAttributePools().ToArray()); } return(default(T)); }
public override EffectBinary Process(EffectSourceCode input, ContentProcessorContext context) { // Remove comments Regex commentRegex = new Regex("//.*$", RegexOptions.IgnoreCase | RegexOptions.Multiline); string effectCode = commentRegex.Replace(input.EffectCode, ""); // Remove carriage returns and line feeds commentRegex = new Regex(@"(\r\n)|\n", RegexOptions.IgnoreCase); effectCode = commentRegex.Replace(effectCode, ""); // Check effect validity // EffectProcessor should check almost all potential errors in the effect code EffectContent content = new EffectContent { EffectCode = effectCode }; EffectProcessor compiler = new EffectProcessor { DebugMode = EffectProcessorDebugMode.Auto }; compiler.Process(content, context); // If we are here, the effect is assumed to be ok! // Extract techniques IEnumerable <EffectTechnique> techniques = ExtractTechniques(effectCode); // Now we have to find entry points for each pass and compile them Compiler helper = new Compiler(); EffectBinary result = new EffectBinary(); foreach (var technique in techniques) { EffectTechniqueBinary effectTechniqueBinary = new EffectTechniqueBinary { Name = technique.Name }; foreach (var pass in technique.Passes) { List <string> errors = new List <string>(); // Compiling vertex shader CompilerResult vsResult = helper.Process(effectCode, errors, "vs_2_0", pass.VertexShaderEntryPoint, 3, false, true); // This should not happen but... if (errors.Count > 0) { ExceptionHelper.RaiseException(String.Join("\n", errors)); } // Compiling pixel shader CompilerResult psResult = helper.Process(effectCode, errors, "ps_2_0", pass.PixelShaderEntryPoint, 3, false, true); // This should not happen but... if (errors.Count > 0) { ExceptionHelper.RaiseException(String.Join("\n", errors)); } // Generating a pass binary EffectPassBinary passBinary = new EffectPassBinary { Name = pass.Name, RenderStates = pass.RenderStates, VertexShaderByteCode = vsResult.ShaderCode, VertexShaderParameters = Encoding.Unicode.GetBytes(vsResult.ConstantsDefinition), PixelShaderByteCode = psResult.ShaderCode, PixelShaderParameters = Encoding.Unicode.GetBytes(psResult.ConstantsDefinition) }; effectTechniqueBinary.PassBinaries.Add(passBinary); } result.TechniquesBinaries.Add(effectTechniqueBinary); } return(result); }