forked from MonoGame/MonoGame
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ShaderInfo.cs
112 lines (86 loc) · 3.88 KB
/
ShaderInfo.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.IO;
namespace TwoMGFX
{
public class ShaderInfo
{
public string FilePath { get; private set; }
public string FileContent { get; private set; }
public ShaderProfile Profile { get; private set; }
public string OutputFilePath { get; private set; }
public bool Debug { get; private set; }
public List<TechniqueInfo> Techniques = new List<TechniqueInfo>();
public Dictionary<string, SamplerStateInfo> SamplerStates = new Dictionary<string, SamplerStateInfo>();
public List<string> Dependencies { get; private set; }
public List<string> AdditionalOutputFiles { get; private set; }
static public ShaderInfo FromFile(string path, Options options, IEffectCompilerOutput output)
{
var effectSource = File.ReadAllText(path);
return FromString(effectSource, path, options, output);
}
static public ShaderInfo FromString(string effectSource, string filePath, Options options, IEffectCompilerOutput output)
{
var macros = new Dictionary<string, string>();
macros.Add("MGFX", "1");
options.Profile.AddMacros(macros);
// If we're building shaders for debug set that flag too.
if (options.Debug)
macros.Add("DEBUG", "1");
if (!string.IsNullOrEmpty(options.Defines))
{
var defines = options.Defines.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var define in defines)
macros.Add(define, "1");
}
// Use the D3DCompiler to pre-process the file resolving
// all #includes and macros.... this even works for GLSL.
string newFile;
var fullPath = Path.GetFullPath(filePath);
var dependencies = new List<string>();
newFile = Preprocessor.Preprocess(effectSource, fullPath, macros, dependencies, output);
// Parse the resulting file for techniques and passes.
var tree = new Parser(new Scanner()).Parse(newFile, fullPath);
if (tree.Errors.Count > 0)
{
var errors = String.Empty;
foreach (var error in tree.Errors)
errors += string.Format("{0}({1},{2}) : {3}\r\n", error.File, error.Line, error.Column, error.Message);
throw new Exception(errors);
}
// Evaluate the results of the parse tree.
var result = tree.Eval() as ShaderInfo;
// Remove the samplers and techniques so that the shader compiler
// gets a clean file without any FX file syntax in it.
var cleanFile = newFile;
ParseTreeTools.WhitespaceNodes(TokenType.Technique_Declaration, tree.Nodes, ref cleanFile);
ParseTreeTools.WhitespaceNodes(TokenType.Sampler_Declaration_States, tree.Nodes, ref cleanFile);
// Setup the rest of the shader info.
result.Dependencies = dependencies;
result.FilePath = fullPath;
result.FileContent = cleanFile;
if (!string.IsNullOrEmpty(options.OutputFile))
result.OutputFilePath = Path.GetFullPath(options.OutputFile);
result.AdditionalOutputFiles = new List<string>();
// Remove empty techniques.
for (var i=0; i < result.Techniques.Count; i++)
{
var tech = result.Techniques[i];
if (tech.Passes.Count <= 0)
{
result.Techniques.RemoveAt(i);
i--;
}
}
// We must have at least one technique.
if (result.Techniques.Count <= 0)
throw new Exception("The effect must contain at least one technique and pass!");
result.Profile = options.Profile;
result.Debug = options.Debug;
return result;
}
}
}