Сериализация Texture2D программно в XNA - PullRequest
3 голосов
/ 14 января 2012

Я создаю игровой редактор для создаваемой игры XNA, который будет принимать JPEG / PNG, и выводить файл XNB с содержимым Texture2D.

У меня есть свои собственные сериализаторы для моегообычай и т. д., и я выкопал все в вызов ContentCompiler с помощью Reflection и т. д., углубился в реальные грязные биты, и я CAN фактически заставил эту часть работать для моих собственных форматов.Но теперь мне нужно сериализовать в обычный формат Texture2D, который XNA знает, как скомпилировать (в Visual Studio при сборке проекта) и загрузить (в игре с наиболее часто используемым методом Content.Load. Я не хочу создавать свое собственное изображениеОчевидно, что формат файла для этого. Когда я пытаюсь скомпилировать Texture2D, он не выдает ошибку, он создает файл XNB, но содержимое файла не является данными изображения, это всего лишь 3-4 КБ накладных расходов (которые яя думаю, что это другие свойства, отличные от изображения объекта 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, но с использованием Reflection (поскольку это внутренний класс).

Я не понимаю, почему Texture2D сериализуется, но без фактических растровых данных.

EDIT Извините, он НЕ компилирует Texture2D (он жалуется на циклическую ссылку на мой GraphicsDevice), если я пытаюсь скомпилировать объект Bitmapт, он компилируется без ошибок, но не сериализует фактические данные растрового изображения)

1 Ответ

1 голос
/ 15 января 2012

Хорошо, после нескольких копаний и часов исследований я решил свою проблему.

Вот что нужно сделать:

Вы не можете сериализовать Texture2D и загрузить его обратно. Хотя загрузка, очевидно, выполняется без проблем (поскольку мы загружаем Texture2D с помощью менеджера контента в любой игре 2D XNA), мы не можем сохранить его для загрузки из игры. После дальнейшего изучения проблемы я обнаружил класс 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 и отображает его на XNB-вывод Texture2D, который затем может быть загружен с помощью метода load для contentManager.

...