How to load devIL image from raw data

2019-09-03 07:44发布

问题:

I would like to create devIL image from raw texture data, but I can't seem to find a way to do it. The proper way seems to be ilLoadL with IL_RAW, but I can't get it to work. The documentation in here says that that there should be 13-byte header in the data, so i just put meaningless data there. If I put 0 to "size" parameter of ilLoadL, I'll get black texture, no matter what. Otherwise my program refuses to draw anything. ilIsImage returns true, and I can create openGL texture from it just fine. The code works if I load texture from file.

It's not much, but here's my code so far:

    //Loading:
    ilInit();
    iluInit();

    ILuint ilID;


    ilGenImages(1, &ilID);

    ilBindImage(ilID);

    ilEnable(IL_ORIGIN_SET);
    ilOriginFunc(IL_ORIGIN_LOWER_LEFT);


        //Generate 13-byte header and fill it with meaningless numbers
        for (int i = 0; i < 13; ++i){

            data.insert(data.begin() + i, i);
        }


    //This fails.
    if (!ilLoadL(IL_RAW, &data[0], size)){
        std::cout << "Fail" << std::endl;
    }

Texture creation:

        ilBindImage(ilId[i]);

        ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);

        glBindTexture(textureTarget, id[i]);

        glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);

        glTexParameterf(textureTarget, GL_TEXTURE_MIN_FILTER, filters[i]);
        glTexParameterf(textureTarget, GL_TEXTURE_MAG_FILTER, filters[i]);

        glTexImage2D(textureTarget, 0, GL_RGBA,
            ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT),
            0, GL_RGBA, GL_UNSIGNED_BYTE, ilGetData());

回答1:

If an image format has a header, you can generally assume it contains some important information necessary to correctly read the rest of the file. Filling it with "meaningless data" is inadvisable at best.

Since there is no actual struct in DevIL for the .raw header, let us take a look at the implementation of iLoadRawInternal () to figure out what those first 13-bytes are supposed to be.

// Internal function to load a raw image
ILboolean iLoadRawInternal()
{
    if (iCurImage == NULL) {
        ilSetError(IL_ILLEGAL_OPERATION);
        return IL_FALSE;
    }    

    iCurImage->Width = GetLittleUInt();   /* Bytes: 0-3   {Image Width}     */
    iCurImage->Height = GetLittleUInt();  /* Bytes: 4-7   {Image Height}    */
    iCurImage->Depth = GetLittleUInt();   /* Bytes: 8-11  {Image Depth}     */
    iCurImage->Bpp = (ILubyte)igetc();    /* Byte:  12    {Bytes per-pixel} */

NOTE: The /* comments */ are my own

GetLittleUInt () reads a 32-bit unsigned integer in little-endian order and advances the read location appropriately. igetc () does the same for a single byte.

This is equivalent to the following C structure (minus the byte order consideration):

struct RAW_HEADER {
  uint32_t width;
  uint32_t height;
  uint32_t depth;  // This is depth as in the number of 3D slices (not bit depth)
  uint8_t  bpp;    // **Bytes** per-pixel (1 = Luminance, 3 = RGB, 4 = RGBA)
};

If you read the rest of the implementation of iLoadRawInternal () in il_raw.c, you will see that without proper values in the header DevIL will not be able to calculate the correct file size. Filling in the correct values should help.