Сериализация 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.