2
\$\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 Answer 1

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\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .