Сериализация Texture2D программно в XNA

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

У меня есть свои собственные сериализаторы для моих пользовательских и т. Д., И я выкопал все в вызов ContentCompiler с использованием Reflection и т. Д., Ушел в реальные грязные биты, и я МОГУ фактически заставить эту часть работать для моих собственных форматов. Но теперь мне нужно сериализовать в обычный формат 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 сериализуется, но без реальных растровых данных.

Спасибо, могу.

РЕДАКТИРОВАТЬ К сожалению, он НЕ компилирует Texture2D (он жалуется на циклическую ссылку моего GraphicsDevice), если я пытаюсь скомпилировать объект Bitmap, он компилируется без ошибок, но не сериализует фактические данные точечного рисунка)

1 ответ

Решение

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

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

Вы не можете сериализовать 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.

Другие вопросы по тегам