1
\$\begingroup\$

I'm trying to create a custom Monogame content pipeline extension that packs a bunch of individual sprites into a single sprite. I need help figuring out how to write and read the texture in the pipeline.

My writer outputs a Texture2DContent (wrapped in SpriteSheetContent model object) that contains a single BitmapContent. My reader then attempts to create a Texture2D from the serialized data, but encounters an exception when setting the data. I cannot make heads or tails of the exception since it's so cryptic.

Where am I going wrong?

Models

public class SpriteSheetContent
{
    public Texture2DContent Texture { get; } = new Texture2DContent();
}

public class SpriteSheet
{
    public Texture2D Texture;
}

Processor

    public override SpriteSheetContent Process( SpriteSheetDeclaration declaration, ContentProcessorContext context )
    {
        var spriteSheetContent = new SpriteSheetContent();

        BitmapContent sprite = <omitted code that creates a single bitmap content>;
        spriteSheetContent.Texture.Mipmaps.Add( sprite );

        return spriteSheetContent;
    }

Writer

[ContentTypeWriter]
public class SpriteBoxWriter : ContentTypeWriter<SpriteSheetContent>
{
    protected override void Write( ContentWriter writer, SpriteSheetContent spriteSheetContent )
    {
        BitmapContent bitmapContent = spriteSheetContent.Texture.Faces[0][0];
        bitmapContent.TryGetFormat( out SurfaceFormat format );

        writer.Write( (int)format );
        writer.Write( bitmapContent.Width );
        writer.Write( bitmapContent.Height );

        byte[] pixelData = bitmapContent.GetPixelData();

        writer.Write( pixelData.Length );
        writer.Write( pixelData );
    }

    public override string GetRuntimeType( TargetPlatform targetPlatform )
    {
        return typeof( SpriteSheet ).AssemblyQualifiedName;
    }

    public override string GetRuntimeReader( TargetPlatform targetPlatform )
    {
        return "Monogame.SpriteBox.SpriteSheetReader, Monogame.SpriteBox";
    }
}

Reader

public class SpriteSheetReader : ContentTypeReader<SpriteSheet>
{
    protected override SpriteSheet Read( ContentReader reader, SpriteSheet existingInstance )
    {
        SpriteSheet spriteSheet = existingInstance == null ? new SpriteSheet() : existingInstance;

        var format = (SurfaceFormat)reader.ReadInt32();
        int width = reader.ReadInt32();
        int height = reader.ReadInt32();

        var graphicsDeviceManager = (GraphicsDeviceManager)reader.ContentManager.ServiceProvider.GetService( typeof( IGraphicsDeviceManager ) );
        spriteSheet.Texture = new Texture2D( graphicsDeviceManager.GraphicsDevice, width, height, mipmap: false, format: format );

        int pixelDataLength = reader.ReadInt32();
        byte[] pixelData = reader.ReadBytes( pixelDataLength );

        spriteSheet.Texture.SetData( pixelData ); // this line results in the exception

        return spriteSheet;
    }
}

Exception

SharpDX.SharpDXException
  HResult=0x80070057
  Message=HRESULT: [0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid Arguments], Message: The parameter is incorrect.

  Source=SharpDX
  StackTrace:
   at SharpDX.Result.CheckError()
   at SharpDX.Direct3D11.Device.CreateTexture2D(Texture2DDescription& descRef, DataBox[] initialDataRef, Texture2D texture2DOut)
   at Microsoft.Xna.Framework.Graphics.Texture2D.CreateTexture()
   at Microsoft.Xna.Framework.Graphics.Texture2D.PlatformSetData[T](Int32 level, T[] data, Int32 startIndex, Int32 elementCount)
   at Microsoft.Xna.Framework.Graphics.Texture2D.SetData[T](T[] data)
   at Monogame.SpriteBox.SpriteSheetReader.ReadTexture(ContentReader reader, SpriteSheet spriteSheet) in D:\Projects\Game Development\Monogame.SpriteBox\SpriteBox\SpriteSheetReader.cs:line 45
   at Monogame.SpriteBox.SpriteSheetReader.Read(ContentReader reader, SpriteSheet existingInstance) in D:\Projects\Game Development\Monogame.SpriteBox\SpriteBox\SpriteSheetReader.cs:line 14
   at Microsoft.Xna.Framework.Content.ContentTypeReader`1.Read(ContentReader input, Object existingInstance)
   at Microsoft.Xna.Framework.Content.ContentReader.InnerReadObject[T](T existingInstance)
   at Microsoft.Xna.Framework.Content.ContentReader.ReadObject[T]()
   at Microsoft.Xna.Framework.Content.ContentReader.ReadAsset[T]()
   at Microsoft.Xna.Framework.Content.ContentManager.ReadAsset[T](String assetName, Action`1 recordDisposableObject)
   at Microsoft.Xna.Framework.Content.ContentManager.Load[T](String assetName)
   at Game1.Game1.LoadContent() in D:\Projects\Game Development\Monogame.SpriteBox\Game1\Game1.cs:line 48
   at Microsoft.Xna.Framework.Game.Initialize()
   at Game1.Game1.Initialize() in D:\Projects\Game Development\Monogame.SpriteBox\Game1\Game1.cs:line 35
   at Microsoft.Xna.Framework.Game.DoInitialize()
   at Microsoft.Xna.Framework.Game.Run(GameRunBehavior runBehavior)
   at Microsoft.Xna.Framework.Game.Run()
   at Game1.Program.Main() in D:\Projects\Game Development\Monogame.SpriteBox\Game1\Program.cs:line 18

Other approach I've tried already

I thought simply doing writer.WriteObject<Texture2DContent>( spriteSheetContent.Texture ) in the writer, and then doing spriteSheet.Texture = reader.ReadObject<Texture2D>() in the reader would work. However, this results in the same type of exception.

I even came across Monogame's Texture2DWriter and Texture2DReader, but using their examples leads to the same exception.

\$\endgroup\$
1
\$\begingroup\$

Well, the answer was simple and something else entirely. It dawned on me that maybe I was packing too many individual textures into a single texture; it turns out I was.

I'm not sure what the texture size limit is in this context, but I must have been exceeding it. I removed a bunch of textures that were being packed to a safe amount, and the code worked as expected.

Edit

Confirmed... HiDef profile max texture size is 4096x4096 and Reach profile is 2048x2048. I was using Reach profile for my tests, and my single texture was larger than the limit.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.