Loading OTF files at runtime

I would like to achieve something like this thread where - instead of relying on the Content Pipeline - I load and use fonts that are available.

My goal is to be able to drop an otf file into my game directory and call something like SpriteFont x = Load("blah.otf") and then use that like any SpriteFont that I loaded through the content pipeline.

Based on that thread, I decided the easiest way is to try loading an existing OTF file, using a previously-made .spritefont file (I combined these in the content pipeline and loaded the font via the XNB successfully).

Anyway, I tried the following:

  • Find my local copy of MonoGame.Framework.Content.Pipeline.dll
  • Add it as a reference to my project
  • Try to copy this MonoGame test code
  • Add a build hook to copy my spritefont file to bin\Debug\netcoreapp3.1\Content\blah.spritefont

Here’s what my cobbled-together code looks like:

public static void TRY_TO_LOAD_OTF()
{
    var platform = TargetPlatform.DesktopGL;
    var outputFormat = TextureProcessorOutputFormat.Color;
    var manager = new PipelineManager(".", ".", ".");
     var e = new PipelineBuildEvent();
    var context = new PipelineProcessorContext(manager, e);
    var processor = new LocalizedFontProcessor() {                
        TextureFormat = outputFormat,
        PremultiplyAlpha = true,
    };

    LocalizedFontDescription fontDescription = null;
    using (var fs = File.OpenRead(Path.Combine("Content", "OpenSans.spritefont")))
    {
        using (var input = XmlReader.Create(new StreamReader(fs)))
        {
            fontDescription = IntermediateSerializer.Deserialize<LocalizedFontDescription>(input, "");
            fontDescription.Identity = new ContentIdentity("OpenSans.spritefont");
        }
    }

    var output = processor.Process(fontDescription, context);
    Console.WriteLine($"Herp? {output}");
}

The line that fails is in the double using statements, fontDescription = IntermediateSerializer.Deserialize<LocalizedFontDescription>(input, "");

It throws this exception:

Exception has occurred: CLR/System.MethodAccessExceptionAn unhandled exception of type 'System.MethodAccessException' occurred in MonoGame.Framework.Content.Pipeline.dll: 'Attempt by method 'Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.ReflectiveSerializer.GetElementInfo(Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.IntermediateSerializer, System.Reflection.MemberInfo, ElementInfo ByRef)' to access method 'MonoGame.Utilities.ReflectionHelpers.GetCustomAttribute<Microsoft.Xna.Framework.Content.ContentSerializerIgnoreAttribute>(System.Reflection.MemberInfo)' failed.'   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.ReflectiveSerializer.GetElementInfo(IntermediateSerializer serializer, MemberInfo member, ElementInfo& info)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.ReflectiveSerializer.Initialize(IntermediateSerializer serializer)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.IntermediateSerializer.GetTypeSerializer(Type type)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.ReflectiveSerializer.Initialize(IntermediateSerializer serializer)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.IntermediateSerializer.GetTypeSerializer(Type type)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.ReflectiveSerializer.Initialize(IntermediateSerializer serializer)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.IntermediateSerializer.GetTypeSerializer(Type type)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.IntermediateReader.ReadObject[T](ContentSerializerAttribute format)
   at Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate.IntermediateSerializer.Deserialize[T](XmlReader input, String referenceRelocationPath)

Please advise what I’m doing wrong.

I’d recommend ignoring the content pipeline entirely and look into something like this: https://github.com/rds1983/SpriteFontPlus It will be probably much easier to implement and it’s portable. Or at least you can use it as an inspiration for your own solution.

2 Likes

Oh hey, a pre-baked solution … that’s awesome! I will look into it, thanks so much!

Thanks so much, that worked like a charm! YAY!