Texture2D.GetData方法的解决方法

时间:2013-11-28 21:31:41

标签: c# ios xna textures monogame

我正在使用Monogame将游戏从XNA转换为iOS 在下面的代码段中,smallDeformTexture2D,我称之为GetData方法。

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

我在使用Monogame时遇到了一些问题,因为iOS中的功能尚未实现,因为它会返回此异常。

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

我尝试从Windows中序列化XML文件中的数据,以从iOS加载整个文件。序列化文件每个重量超过100MB,这是解析时无法接受的。

基本上,我正在寻找一种解决方法,以便在不使用uint[]方法的情况下从纹理中获取数据(例如Color[]GetData)。

PS:我在Mac上,所以我不能使用Monogame SharpDX库。

提前致谢。

3 个答案:

答案 0 :(得分:1)

序列化数据实际上是一个非常聪明的解决方法,但XML对于这项工作来说非常重要。我要做的是使用自定义但简单的二进制格式,以便您可以控制输出的大小。

以下是我提出的一些应该有效的方法,但请注意我专门回答了这个问题并且没有经过测试。

保存数据..

    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);
            }
        }
    }

并加载数据..

    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;
        }
    }

二进制数据远小于XML数据。它与你没有压缩的情况一样小。请注意,二进制格式在变更方面非常严格。如果您需要更改格式,在大多数情况下写出新文件会更容易。

如果您需要对方法进行更改,请注意保持其同步。每个Write应该以完全相同的顺序和数据类型与相同的Read匹配。

我很想知道文件变小了多少。让我知道它是怎么回事?

答案 1 :(得分:1)

我回答我自己的问题,如果有人会遇到同样的问题。

按照 craftworkgame 的建议,我使用字节流保存了数据,但是由于缺少File类,我不得不使用WinRT函数:

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;
}

答案 2 :(得分:1)

如果您愿意构建自己的MonoGame版本,可以在iOS上使用Texture2D.GetData。请参阅此处的修复:https://github.com/scottlerch/MonoGame/commit/24c1c3d5398f4ed9dbd9b60c0bbdbc096311632c)。

这是来自同一问题的讨论:https://monogame.codeplex.com/discussions/442667

此修复程序已确认适用于iPad1 v5.1.1 +和iPhone4 v6.1 +。