Okay I think I solved it, and I’m pretty sure its not optimal, but here is my solution:
I created a CustomEffectProcessor that creates a CustomEffect from EffectContent. This was neccesary because i wanted to save the type information. So that when I read it, I know what class I have to instantiate. Something like this:
The CustomEffect:
public class CustomEffect : CompiledEffectContent {
public string Type { get; set; }
public CustomEffect(byte[] effectCode, string type) : base(effectCode) {
Type = type;
}
}
The processor:
[ContentProcessor(DisplayName = "Custom Effect Processor")]
public class CustomEffectProcessor : ContentProcessor<EffectContent, CustomEffect> {
[DefaultValue(typeof(EShaderType), "Effect")]
public EShaderType Type { get; set; }
public override CustomEffect Process(EffectContent input, ContentProcessorContext context) {
EffectProcessor ep = new EffectProcessor();
CompiledEffectContent c = ep.Process(input, context);
return new CustomEffect(c.GetEffectCode(), Type.ToString());
}
}
The writer:
[ContentTypeWriter]
public class CustomEffectWriter : ContentTypeWriter<CustomEffect> {
public override string GetRuntimeReader(TargetPlatform targetPlatform) {
return "CustomContentPipelineExtension.CustomEffectReader, CustomContentPipelineExtension";
}
protected override void Write(ContentWriter output, CustomEffect value) {
var code = value.GetEffectCode();
output.Write(value.Type);
output.Write(code.Length);
output.Write(code);
}
}
And finally the reader:
public class CustomEffectReader : ContentTypeReader<Effect> {
private byte[] scratchBuffer;
public static GraphicsDevice Device; // monkey patch for ContentReader.GraphicsDevice is internal... Dont forget to initialize this in your Game.Initialize method
//copied from the MonoGame ContentManager for being internal too
internal byte[] GetScratchBuffer(int size) {
size = Math.Max(size, 1024 * 1024);
if (scratchBuffer == null || scratchBuffer.Length < size)
scratchBuffer = new byte[size];
return scratchBuffer;
}
protected override Effect Read(ContentReader input, Effect existingInstance) {
string shaderType = input.ReadString();
int dataSize = input.ReadInt32();
byte[] data = GetScratchBuffer(dataSize);
input.Read(data, 0, dataSize);
Effect effect;
if(shaderType == "Effect") {
effect = new Effect(Device, data, 0, dataSize);
} else {
// instantiate other types
}
effect.Name = input.AssetName;
return effect;
}
}
The idea was to guide the whole model import through, starting with how the shader is serialized and deserialized, so when the actual Effect is being instantiated I can decide on the type based on the shader. One little catch is that inside the CustomEffectProcessor there is a Type property, you have to set that in the Content Pipeline tool, also you have to keep an enum updated for that, but I think thats much more manageable than manually handling textures and shaders. I did not test it extensively yet, I just wanted to let you guys know that I might worked around my issue.
Cheers