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.