Writing an image file reader plugin for OpenSceneGraph

This article will focus on writing a plugin for OpenSceneGraph. The plugin adds the ability to use the PCX format from ZSoft Corporation. The code is simplified to the limit and includes only the read function, I suggest writing the write function ourselves. I understand that on the site www.openscenegraph.org you can download the source code of the plug-ins and see how everything works, but the formatting of the source code surprised me a bit and I decided to put everything in order. And leave a note for yourself so as not to forget.

image

Main class


First, we need to create a class, a descendant of the osgDB :: ReaderWriter class. 3D plugins also use this class:

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);
};

As you can see from the code above, this is a description of the plugin's functions for reading and writing a file, as well as setting the class name and the file extension used. I will not give the rest of the code. You can see it at the link at the end of the article or in the OpenSceneGraph source code for another example. In it, opening a file, checking for compliance of extensions, the presence of a file and so on.

ReaderWriterPCX::ReaderWriterPCX()
{
  supportsExtension("pcx","PCX Image format");
}
const char* ReaderWriterPCX::className() const 
{ 
  return "PCX Image Reader"; 
}

Main function


Although the return type of functions is osgDB :: ReaderWriter :: ReadResult, in this case, osg :: Image is returned. First of all, we need to know some image parameters, such as image dimensions and the pixel data itself. The alpha channel does not use this format, and we will only support 256+ palettes. This format uses super duper RLE data compression. Quote from Wiki:
The algorithm for such compression is very fast and takes up a small amount of memory, but it is not very efficient, impractical for compressing photographs and more detailed computer graphics.

Lossless compression is used. When saving the image, successive pixels of the same color are combined and instead of specifying a color for each pixel, the color of the group of pixels and their number are indicated. Such an algorithm compresses images in which areas of the same color are present.

So, open the file and read its signature. If it is correct, move on. We check the rest of the data, read the sizes, the palette (it is at the end of the file for 256 colors).

fin.read((char*) &pcx->Identifier, sizeof(pcx->Identifier));
if (pcx->Identifier != 0x0a) {
  OSG_WARN << "Invalid PCX Identifier\n";
  return 0;
}

And the unpacking algorithm itself:

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;
  }
}

The imageBuffer array is our data. It consists of three colors times the number of pixels. That is, this is our unpacked data. They will be used when installing image data, and the format and size will be selected GL_RGB and 3 bytes, respectively.

The plugin needs to be copied to the plugins folder. I have this /usr/lib/osgPlugins-3.2.0/ (I use Linux). You can check it by opening with osgmovie, which is in the examples. At the end of the file, the code connecting the plugin should be indicated:

REGISTER_OSGPLUGIN(pcx, ReaderWriterPCX)

Epilogue


The presence of plugins makes it possible to use OpenSceneGraph to write engines for old games with new graphics or to use their own formats for storing data in games. In the next article it is planned to write a plug-in for reading 3D format.

Sources: bitbucket.org/darkprof/pcx/src

Also popular now: