В этой статье речь пойдет о написании плагина для OpenSceneGraph. Плагин добавляет возможность использования формата PCX фирмы ZSoft Corporation. Код упрощен до предела и включает в себя только функцию чтения, функцию записи предлагаю написать самим. Я понимаю, что на сайте www.openscenegraph.org можно скачать исходники плагинов и посмотреть, как все работает, но форматирование исходников меня несколько удивило и я решил разложить все по полочкам. И оставить для себя заметку, чтоб не забыть.
Во-первых, нам надо создать класс, наследник класса osgDB::ReaderWriter. Плагины 3D форматов тоже используют этот класс:
Как понятно из кода выше — это описание функций плагина для чтения и записи файла, а также установки имени класса и используемого расширения файла. Остальной код приводить не буду. Его вы сможете посмотреть по ссылке в конце статьи или в исходниках OpenSceneGraph для другого примера. В нем открытие файла, проверка на соответствие расширений, наличие файла и так далее.
Хоть возвращаемый тип функций и osgDB::ReaderWriter::ReadResult, но в данном случае возвращается osg::Image. Нам, во-первых, необходимо узнать некоторые параметры изображения, такие как размеры изображения и сами данные пикселей. Альфа-канал данный формат не использует, а поддержку палитры сделаем только 256+. Данный формат используетсупер пупер сжатие данных RLE. Цитата из Вики:
Итак, открываем файл и считываем его сигнатуру. Если она правильная — идем дальше. Проверяем и остальные данные, считываем размеры, палитру (она находится в конце файла для 256 цветов).
И непосредственно сам алгоритм распаковки:
Массив imageBuffer и есть наши данные. Он состоит трех цветов, помноженных на количество пикселей. То есть это и есть наши распакованные данные. Именно они будут использоваться при установке данных изображения, а формат и размер будет выбран GL_RGB и 3 байта соответственно.
Плагин нужно скопировать в папку с плагинами. У меня это /usr/lib/osgPlugins-3.2.0/ (я использую Linux). Проверить его можно открыв с помощью osgmovie, который есть в примерах. В конце файла должен быть указан код, подключающий плагин:
Наличие плагинов дает возможность использовать OpenSceneGraph для написания движков под старые игры с новой графикой или использовать свои форматы хранения данных в играх. В следующей статье планируется написать плагин для чтения 3D формата.
Исходники: bitbucket.org/darkprof/pcx/src
Главный класс
Во-первых, нам надо создать класс, наследник класса osgDB::ReaderWriter. Плагины 3D форматов тоже используют этот класс:
class ReaderWriterPCX : public osgDB::ReaderWriter
{
public:
ReaderWriterPCX();
const char* className() const;
ReadResult readObject(std::istream& fin, const Options* options = 0) const;
ReadResult readObject(const std::string& file, const Options* options = 0) const;
ReadResult readImage(std::istream& fin, const Options* options = 0) const;
ReadResult readImage(const std::string& file, const Options* options = 0) const;
WriteResult writeImage(const osg::Image& image, std::ostream& fout, const Options* = 0) const;
WriteResult writeImage(const osg::Image& img, const std::string& fileName, const Options* options = 0) const;
private:
static ReadResult readPCXStream(std::istream& fin);
};
Как понятно из кода выше — это описание функций плагина для чтения и записи файла, а также установки имени класса и используемого расширения файла. Остальной код приводить не буду. Его вы сможете посмотреть по ссылке в конце статьи или в исходниках OpenSceneGraph для другого примера. В нем открытие файла, проверка на соответствие расширений, наличие файла и так далее.
ReaderWriterPCX::ReaderWriterPCX()
{
supportsExtension("pcx","PCX Image format");
}
const char* ReaderWriterPCX::className() const
{
return "PCX Image Reader";
}
Главная функция
Хоть возвращаемый тип функций и osgDB::ReaderWriter::ReadResult, но в данном случае возвращается osg::Image. Нам, во-первых, необходимо узнать некоторые параметры изображения, такие как размеры изображения и сами данные пикселей. Альфа-канал данный формат не использует, а поддержку палитры сделаем только 256+. Данный формат использует
Алгоритм такого сжатия очень быстрый и занимает небольшой объём памяти, однако не очень эффективен, непрактичен для сжатия фотографий и более детальной компьютерной графики.
Используется сжатие без потерь. При сохранении изображения подряд идущие пиксели одинакового цвета объединяются и вместо указания цвета для каждого пикселя указывается цвет группы пикселей и их количество. Такой алгоритм хорошо сжимает изображения, в которых присутствуют области одного цвета.
Итак, открываем файл и считываем его сигнатуру. Если она правильная — идем дальше. Проверяем и остальные данные, считываем размеры, палитру (она находится в конце файла для 256 цветов).
fin.read((char*) &pcx->Identifier, sizeof(pcx->Identifier));
if (pcx->Identifier != 0x0a) {
OSG_WARN << "Invalid PCX Identifier\n";
return 0;
}
И непосредственно сам алгоритм распаковки:
for (int h = height_ret - 1; h >= 0; --h) {
for (int w = 0; w < width_ret; ++w) {
if(!count) {
if(!fin.read((char*) &tmp, sizeof(tmp))) {
OSG_WARN << "file truncated\n";
return 0;
}
if( (tmp & 0xc0) == 0xc0) {
count = tmp & 0x3f;
if(!fin.read((char*) &tmp, sizeof(tmp))) {
OSG_WARN << "file truncated\n";
return 0;
}
} else {
count = 1;
}
}
index = h * width_ret + w;
imageBuffer[index].red = colorPalette[tmp].red;
imageBuffer[index].green = colorPalette[tmp].green;
imageBuffer[index].blue = colorPalette[tmp].blue;
--count;
}
}
Массив imageBuffer и есть наши данные. Он состоит трех цветов, помноженных на количество пикселей. То есть это и есть наши распакованные данные. Именно они будут использоваться при установке данных изображения, а формат и размер будет выбран GL_RGB и 3 байта соответственно.
Плагин нужно скопировать в папку с плагинами. У меня это /usr/lib/osgPlugins-3.2.0/ (я использую Linux). Проверить его можно открыв с помощью osgmovie, который есть в примерах. В конце файла должен быть указан код, подключающий плагин:
REGISTER_OSGPLUGIN(pcx, ReaderWriterPCX)
Эпилог
Наличие плагинов дает возможность использовать OpenSceneGraph для написания движков под старые игры с новой графикой или использовать свои форматы хранения данных в играх. В следующей статье планируется написать плагин для чтения 3D формата.
Исходники: bitbucket.org/darkprof/pcx/src