Workaround for Texture2D.GetData Method

Im converting a game from XNA to iOS using Monogame.
In the code smallDeform below, smallDeform is Texture2D on which I call the GetData method.

 smallDeform = Game.Content.Load<Texture2D>("Terrain/..."); smallDeform.GetData(smallDeformData, 0, smallDeform.Width * smallDeform.Height); 

I have some problem with Monogame, because the function is not yet implemented in iOS, as it returns this exception.

 #if IOS throw new NotImplementedException(); #elif ANDROID 

I tried serializing the data in an XML file from Windows to download the entire file from iOS. Serialized files weigh more than 100 MB each, which is completely unacceptable for parsing.

Basically, I'm looking for a workaround to get data (for example, uint[] or Color[] ) from a texture without using the GetData method.

PS: I am on a Mac, so I cannot use the SharpDX Monogame library.

Thanks in advance.

+6
source share
3 answers

I answer my question if someone has the same problem.

Following the suggestion of craftworkgame, I saved my data using byte streams, but due to the lack of the File class, I had to use WinRT functions:

 private async void SaveColorArray(string filename, Color[] array) { StorageFile sampleFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(filename + ".dat", CreationCollisionOption.ReplaceExisting); IRandomAccessStream writeStream = await sampleFile.OpenAsync(FileAccessMode.ReadWrite); IOutputStream outputSteam = writeStream.GetOutputStreamAt(0); DataWriter dataWriter = new DataWriter(outputSteam); for (int i = 0; i < array.Length; i++) { dataWriter.WriteByte(array[i].R); dataWriter.WriteByte(array[i].G); dataWriter.WriteByte(array[i].B); dataWriter.WriteByte(array[i].A); } await dataWriter.StoreAsync(); await outputSteam.FlushAsync(); } protected async Task<Color[]> LoadColorArray(string filename) { StorageFile sampleFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(filename + ".dat", CreationCollisionOption.OpenIfExists); IRandomAccessStream readStream = await sampleFile.OpenAsync(FileAccessMode.Read); IInputStream inputSteam = readStream.GetInputStreamAt(0); DataReader dataReader = new DataReader(inputSteam); await dataReader.LoadAsync((uint)readStream.Size); Color[] levelArray = new Color[dataReader.UnconsumedBufferLength / 4]; int i = 0; while (dataReader.UnconsumedBufferLength > 0) { byte[] colorArray = new byte[4]; dataReader.ReadBytes(colorArray); levelArray[i++] = new Color(colorArray[0], colorArray[1], colorArray[2], colorArray[3]); } return levelArray; } 
+1
source

Serializing data is actually a pretty smart workaround, but XML is very hard to work with. I would do this using a custom-made, but simple binary format so you can control the size of the output.

Here are a few methods I’ve cracked that should work, but keep in mind that I specifically asked them to answer this question, and they have not been tested.

To save data.

  private void SaveTextureData(Texture2D texture, string filename) { int width = texture.Width; int height = texture.Height; Color[] data = new Color[width * height]; texture.GetData<Color>(data, 0, data.Length); using (BinaryWriter writer = new BinaryWriter(File.Open(filename, FileMode.Create))) { writer.Write(width); writer.Write(height); writer.Write(data.Length); for (int i = 0; i < data.Length; i++) { writer.Write(data[i].R); writer.Write(data[i].G); writer.Write(data[i].B); writer.Write(data[i].A); } } } 

And download the data ..

  private Texture2D LoadTextureData(string filename) { using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open))) { var width = reader.ReadInt32(); var height = reader.ReadInt32(); var length = reader.ReadInt32(); var data = new Color[length]; for (int i = 0; i < data.Length; i++) { var r = reader.ReadByte(); var g = reader.ReadByte(); var b = reader.ReadByte(); var a = reader.ReadByte(); data[i] = new Color(r, g, b, a); } var texture = new Texture2D(GraphicsDevice, width, height); texture.SetData<Color>(data, 0, data.Length); return texture; } } 

Binary data is much smaller than XML data. This is about as small as you get without compression. Just keep in mind that binary formats are pretty tough when it comes to change. If you need to change the format, in most cases it will be easier to write new files.

If you need to make changes to methods, be careful to synchronize them. Each record must match an identical Read in the same order and data type.

I am interested to know how small the files are. Let me know how this happens?

+1
source

You can get Texture2D.GetData running on iOS if you want to create your own version of MonoGame. See the fix here: https://github.com/scottlerch/MonoGame/commit/24c1c3d5398f4ed9dbd9b60c0bbdbc096311632c ).

From discussions on the same issue here: https://monogame.codeplex.com/discussions/442667

Fixed fix for working with iPad1 v5.1.1 + and iPhone4 v6.1 +.

+1
source

Source: https://habr.com/ru/post/959011/


All Articles