c# - 在 XNA 中以编程方式序列化 Texture2D

标签 c# .net xna content-pipeline

我正在为我正在构建的 XNA 游戏构建一个游戏编辑器,它可以接受 JPEG/PNG,并输出一个包含 Texture2D 内容的 XNB 文件。

我有我的自定义序列化器等,我将所有内容都挖掘到使用反射等调用 ContentCompiler,进入真正的脏位,我可以实际上让那个部分为我工作自己的格式。但我现在需要序列化为 XNA 知道如何编译(在构建项目时在 Visual Studio 中)和加载(在游戏中使用最常用的 Content.Load 方法)的常规 Texture2D 格式。我不想制作自己的图像这显然是文件格式。当我尝试编译 Texture2D 时,它没有给我一个错误,它创建了 XNB 文件,但文件内容不是图像数据,它只是一些 3-4 KB 的开销(我认为是 Texture2D 对象的其他非图像属性)。

这是我用来编译的代码:

    protected void InitializeWriter()
    {
        Type compilerType = typeof(ContentCompiler);
        cc = compilerType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0].Invoke(null) as ContentCompiler;
        compileMethod = compilerType.GetMethod("Compile", BindingFlags.NonPublic | BindingFlags.Instance);
    }

    internal void Write(string objectName, string path, object objectToWrite) 
    {
        if (basePath == null)
        {
            throw new InvalidOperationException("The base path to write has not been set.");
        }
        if (cc == null) { InitializeWriter(); }
        string fullPath = Path.Combine(basePath, path, objectName + ".xnb");
        using (FileStream fs = File.Create(fullPath))
        {
            compileMethod.Invoke(cc, new object[]{
            fs, objectToWrite, TargetPlatform.Windows, GraphicsProfile.Reach, false/*true*/, fullPath, fullPath
        });
        }
    }

我有自己的内容处理器,这段代码可以完美地与它们一起工作。这只是调用了 ContentCompiler 的 Compile 方法,但使用了反射(因为它是一个内部类)。

我不明白为什么 Texture2D 序列化,但没有实际的位图数据。

编辑 抱歉,它不编译 Texture2D(它提示我的 GraphicsDevice 的循环引用),如果我尝试编译一个 Bitmap 对象,它编译没有错误但不序列化实际的位图数据)

最佳答案

好的,经过一些挖掘和数小时的研究,我已经解决了我的问题。

这是要做的事情:

您无法序列化 Texture2D 并将其加载回来。虽然加载显然没有问题(因为我们在任何 2D XNA 游戏中使用内容管理器加载 Texture2D),但我们无法保存它以便从游戏中加载它。在对该问题进行进一步调查后,我发现了一个 Texture2DContent 类(在图形管道中),我认为它会序列化为 Texture2D(结果证明是完全正确的)。

所以我只是连接了一个 Texture2DContent 类的新实例,但发现无法将其数据设置到我的位图中。搜索了所有 DLL 和基类/派生类,但没有办法。然后我实现了一个具有导入方法的 TextureImporter 类。它需要一个文件名和一个 ContentImporterContext,这是一个复杂的类,它也有来自其他深层内部工作类的构造函数,我只知道我无法正确初始化那个。所以我尝试将 null 作为我的参数传递给导入方法,单步执行代码以查看我的 NullPointerException,但奇怪的是,它起作用了,并输出了我的文件。我检查了 XNB,它只是一个有效的纹理。这是我的代码:

    TextureImporter importer = new TextureImporter();
    Texture2DContent tc = importer.Import(item, null) as Texture2DContent;
    AssetWriter.Write(item.Substring(item.Replace('\\', '/').LastIndexOf('/') + 1), tc);

其中 item 只是一个文件名,而 AssetWriter 实际上是这样做的(那里有一些方法,但我在下面将它们粘贴在一起):

   Type compilerType = typeof(ContentCompiler);
   cc = compilerType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0].Invoke(null) as ContentCompiler;
   compileMethod = compilerType.GetMethod("Compile", BindingFlags.NonPublic | BindingFlags.Instance);
   string fullPath = Path.Combine(basePath, path, objectName + ".xnb");
   using (FileStream fs = File.Create(fullPath))
   {
      compileMethod.Invoke(cc, new object[]{
      fs, objectToWrite, TargetPlatform.Windows, GraphicsProfile.Reach, false/*true*/, fullPath, fullPath
      });
   }

它就是这样工作的。该程序将所需的一切传递给内容编译器,然后由编译器完成工作。它正确处理 Texture2DContent 并将其映射到 Texture2D 的 XNB 输出,然后可以使用 contentManager 的加载方法加载。

关于c# - 在 XNA 中以编程方式序列化 Texture2D,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8856528/

相关文章:

c# - Microsoft Orleans 中每台机器有多少个 Silo

c# - 正则表达式 - 在字符串中查找 4 位数字

c# - 运行后如何隐藏WinForm?

c# - 如何使用 Mono 和 mkbundle 将一个简单的 .Net 控制台项目转换为可移植的 exe?

c# - 创建与 AspNetUsers 表的关系

c# - 为什么要使用服务(IServiceProvider)?

C# 在派生类中设置基对象

c# - 如何在网络共享文件夹的媒体元素中播放视频

xna - 我随机做错了什么?

XNA - 使用具有旋转/缩放/平移功能的 2d 相机系统获取鼠标坐标