Created
March 13, 2017 19:21
-
-
Save jackmott/98690081046e2c49387e49794b8061a7 to your computer and use it in GitHub Desktop.
Hot Swappable Shaders for MonoGame
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
HotSwap shader sytem for MonoGame | |
HotSwap code only exists for debug builds | |
Edit paths to match your project | |
Construct in your Initialize method | |
Add shaders in LoadContent (or whenever) | |
Call CheckForChanges in Update() or periodically however you like | |
mgcb.exe usually located in C:\Program Files (x86)\MSBuild\MonoGame\v3.0\Tools | |
*/ | |
using Microsoft.Xna.Framework.Graphics; | |
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using Microsoft.Xna.Framework.Content; | |
using System.IO; | |
using System.Diagnostics; | |
namespace PRPG{ | |
public class ShaderManager { | |
#if DEBUG | |
ContentManager TempContent; | |
DateTime LastUpdate; | |
const string mgcbPathExe = "c:/projects/prpgcs/Content/MGCB/mgcb.exe"; | |
const string contentPath = "c:/projects/prpgcs/Content"; | |
#endif | |
public Dictionary<string, Effect> Shaders; | |
ContentManager Content; | |
GraphicsDevice Device; | |
public ShaderManager(ContentManager content, GraphicsDevice device) { | |
Content = content; | |
Device = device; | |
Shaders = new Dictionary<string, Effect>(); | |
#if DEBUG | |
TempContent = new ContentManager(Content.ServiceProvider, Content.RootDirectory); | |
LastUpdate = DateTime.Now; | |
#endif | |
} | |
#if DEBUG | |
public void CheckForChanges() { | |
var files = Directory.GetFiles(contentPath, "*.fx"); | |
foreach (var file in files) { | |
var t = File.GetLastWriteTime(file); | |
if (t > LastUpdate) { | |
ShaderChanged(file); | |
LastUpdate = t; | |
} | |
} | |
} | |
public void ShaderChanged(string path) { | |
string name = Path.GetFileNameWithoutExtension(path); | |
Process pProcess = new Process { | |
StartInfo = | |
{ | |
FileName = mgcbPathExe, | |
Arguments = "/platform:DesktopGL /config: /profile:Reach /compress:False /importer:EffectImporter /processor:EffectProcessor /processorParam:DebugMode=Auto /build:"+name+".fx", | |
CreateNoWindow = true, | |
WorkingDirectory = contentPath, | |
UseShellExecute = false, | |
RedirectStandardError = true, | |
RedirectStandardOutput = true | |
} | |
}; | |
//Get program output | |
string stdError = null; | |
StringBuilder stdOutput = new StringBuilder(); | |
pProcess.OutputDataReceived += (sender, args) => stdOutput.Append(args.Data); | |
try { | |
pProcess.Start(); | |
pProcess.BeginOutputReadLine(); | |
stdError = pProcess.StandardError.ReadToEnd(); | |
pProcess.WaitForExit(); | |
string builtPath = contentPath+"/" + name + ".xnb"; | |
string movePath = "C:/projects/prpgcs/PRPG/bin/DesktopGL/AnyCPU/Debug/Content/" + name + ".xnb"; | |
File.Copy(builtPath, movePath, true); | |
ContentManager newTemp = new ContentManager(TempContent.ServiceProvider, TempContent.RootDirectory); | |
var newShaders = new Dictionary<string, Effect>(); | |
foreach (var shaderName in Shaders.Keys) { | |
var effect = newTemp.Load<Effect>(shaderName); | |
newShaders.Add(shaderName.ToLower(), effect); | |
} | |
TempContent.Unload(); | |
TempContent.Dispose(); | |
TempContent = newTemp; | |
Shaders = newShaders; | |
} | |
catch (Exception e) { | |
//todo log | |
} | |
finally { | |
} | |
} | |
#endif | |
public Effect GetShader(string name) { | |
return Shaders[name.ToLower()]; | |
} | |
public void AddShader(string name) { | |
if (!Shaders.ContainsKey(name.ToLower())) { | |
var shader = Content.Load<Effect>(name); | |
Shaders.Add(name.ToLower(), shader); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment