C ++ OpenGL TGA Ошибка загрузки - PullRequest
1 голос
/ 13 января 2012

Я работал над основным учебным пособием по OpenGl по загрузке TGA-файла, который будет использоваться в качестве текстуры на 3D-объекте. Мне удалось загрузить данные из заголовка TGA, но когда я пытаюсь загрузить реальные данные изображения, происходит сбой. Я не уверен, где это идет не так. Вот мой класс загрузки текстур:

Заголовочный файл:

    struct TGA_Header 
{
    GLbyte  ID_Length;
    GLbyte  ColorMapType;
    GLbyte  ImageType;
    // Color map specifications
    GLbyte firstEntryIndex[2];      
    GLbyte colorMapLength[2];
    GLbyte colorMapEntrySize;

    //image specification
    GLshort xOrigin;
    GLshort yOrigin;
    GLshort ImageWidth;
    GLshort ImageHeight;
    GLbyte  PixelDepth;
    GLbyte ImageDescriptor;
};

class Texture
{
public:
    Texture(string in_filename, string in_name = "");
    ~Texture();

public:
    unsigned short  width;
    unsigned short  height;
    unsigned int    length;
    unsigned char   type;   
    unsigned char   *imageData;
    unsigned int    bpp;
    unsigned int    texID;

    string          name;

    static vector<Texture *> textures;

private:
    bool loadTGA(string filename);
    bool createTexture(unsigned char *imageData, int width, int height, int type);

    void swap(unsigned char * ori, unsigned char * dest, GLint size);
    void flipImage(unsigned char * image, bool flipHorizontal, bool flipVertical, GLushort width, GLushort height, GLbyte bpp);
};

Вот функция загрузки TGA в cpp:

bool Texture::loadTGA(string filename)
{
    TGA_Header TGAheader;

    ifstream file( filename.data(), std::ios::in, std::ios::binary );

    //make sure the file was opened properly
    if (!file.is_open() )
        return false;

    if( !file.read( (char *)&TGAheader, sizeof(TGAheader) ) )
        return false;


    //make sure the image is of a type we can handle
    if( TGAheader.ImageType != 2 )
        return false;

    width = TGAheader.ImageWidth;
    height = TGAheader.ImageHeight;
    bpp = TGAheader.PixelDepth;

    if( width < 0   ||              // if the width or height is less than 0, than
        height <= 0 ||              // the image is corrupt
        (bpp != 24 && bpp != 32) )  // make sure we are of the correct bit depth
    {
        return false;
    }

    //check for an alpha channel
    GLuint type = GL_RGBA;
    if ( bpp == 24 )
        type = GL_RGB;

    GLuint bytesPerPixel = bpp / 8;

    //allocate memory for the TGA so we can read it
    GLuint imageSize = width * height * bytesPerPixel;
    imageData = new GLubyte[imageSize];

    if ( imageData == NULL )
        return false;

    //make sure we are in the correct position to load the image data
    file.seekg(-imageSize, std::ios::end);

    // if something when wrong, make sure we free up the memory
    //NOTE: It never gets past this point. The conditional always fails.
    if ( !file.read( (char *)imageData, imageSize ) )
    {
        delete imageData;

        return false;
    }

    //more code is down here, but it doesnt matter because it does not pass the above function
}

Кажется, что загружаются некоторые данные, но он продолжает возвращать, что это не удалось. Любая помощь о том, почему будет принята с благодарностью. Извиняюсь, если получится немного многословно, но я не уверен, что это важно или не важно.

UPDATE: Итак, я просто переписал функцию. Команда ifsteam, которую я использовал, казалось, была причиной проблемы. В частности, он попытался бы загрузить гораздо больше байтов данных, чем я ввел. Я не знаю причину поведения, но я перечислил мой функциональный код ниже. Спасибо всем за помощь.

Ответы [ 3 ]

0 голосов
/ 13 января 2012

Проблема может быть связана с алгоритмом TGA, который не поддерживает сжатый TGA.

Убедитесь, что вы не сжимаете TGA и что порядок TGA (менее важный) находится в нижнем левом начале.

Я обычно работаю с GIMP и в тот же момент снимаю флажок сжатия RLE и устанавливаю выравнивание по левому краю.

0 голосов
/ 15 января 2012

Итак, я переключился с использования ifstream на FILE.Ifstream пытался загрузить гораздо больше байтов, чем я перечислил в аргументах.Вот новый код.(ПРИМЕЧАНИЕ: он все еще нуждается в optomized. Я полагаю, что некоторые неиспользуемые переменные плавают вокруг, но это работает отлично.).Еще раз всем спасибо за помощь.

Заголовочный файл:

    //struct to hold tga data
struct TGA_Header
{
    GLbyte  ID_Length;
    GLbyte  ColorMapType;
    GLbyte  ImageType;
    // Color map specifications
    GLbyte firstEntryIndex[2];      
    GLbyte colorMapLength[2];
    GLbyte colorMapEntrySize;

    //image specification
    GLshort xOrigin;
    GLshort yOrigin;
    GLshort ImageWidth;
    GLshort ImageHeight;
    GLbyte  PixelDepth;
    GLbyte ImageDescriptor;
};

class Texture
{
public:
    //functions
    Texture(string in_filename, string in_name = "");
    ~Texture();

public:
    //vars
    unsigned char   *imageData;
    unsigned int    texID;

    string          name;

    //temp global access point for accessing all loaded textures
    static vector<Texture *> textures;

private:
    //can add additional load functions for other image types
    bool loadTGA(string filename);
    bool createTexture(unsigned char *imageData, int width, int height, int type);

    void swap(unsigned char * ori, unsigned char * dest, GLint size);
    void flipImage(unsigned char * image, bool flipHorizontal, bool flipVertical, GLushort width, GLushort height, GLbyte bpp);
};

#endif

Вот функция загрузки TGA:

    bool Texture::loadTGA(string filename)
{
    //var for swapping colors
    unsigned char colorSwap = 0;

    GLuint type;
    TGA_Header TGAheader;

    FILE* file = fopen(filename.c_str(), "rb");

    unsigned char Temp_TGAheader[18];

    //check to make sure the file loaded
    if( file == NULL )
        return false;   

    fread(Temp_TGAheader, 1, sizeof(Temp_TGAheader), file);

    //pull out the relavent data. 2 byte data (short) must be converted
    TGAheader.ID_Length = Temp_TGAheader[0];
    TGAheader.ImageType = Temp_TGAheader[2];
    TGAheader.ImageWidth = *static_cast<unsigned short*>(static_cast<void*>(&Temp_TGAheader[12]));
    TGAheader.ImageHeight = *static_cast<unsigned short*>(static_cast<void*>(&Temp_TGAheader[14]));
    TGAheader.PixelDepth = Temp_TGAheader[16];


    //make sure the image is of a type we can handle
    if( TGAheader.ImageType != 2 || TGAheader.ImageWidth <= 0 || TGAheader.ImageHeight <= 0 )
    {
        fclose(file);
        return false;
    }

    //set the type
    if ( TGAheader.PixelDepth == 32 )
    {
        type = GL_RGBA;
    } 
    else if ( TGAheader.PixelDepth == 24 ) 
    {
        type = GL_RGB;
    }
    else 
    {
        //incompatable image type
        return false;
    }


    //remember bits != bytes. To convert we need to divide by 8
    GLuint bytesPerPixel = TGAheader.PixelDepth / 8;

    //The Memory Required For The TGA Data  
    unsigned int imageSize = TGAheader.ImageWidth * TGAheader.ImageHeight * bytesPerPixel;// Calculate 

    //request the needed memory
    imageData = new GLubyte[imageSize];

    if ( imageData == NULL ) // just in case
        return false;

    if( fread(imageData, 1, imageSize, file) != imageSize )
    {       
        //Kill it
        delete [] imageData;
        fclose(file);                                           
        return false;   
    }       

    fclose(file);

    for (unsigned int x = 0; x < imageSize; x +=bytesPerPixel)  
    {
        colorSwap = imageData[x];       
        imageData[x] = imageData[x + 2];        
        imageData[x + 2] = colorSwap;   
    }   

    createTexture( imageData, TGAheader.ImageWidth, TGAheader.ImageHeight, type );

    return true;
}
0 голосов
/ 13 января 2012

Я не знаком с C ++, извините.

Вы уверены, что эта строка file.seekg(-imageSize, std::ios::end); не должна быть file.seekg(headerSize, std::ios::start);?

Имеет больше смысла искать с начала, чем с конца.

Вы также должны проверить на ColorMapType != 0.

P.S. Здесь if( width < 0 || height <=0 проверка ширины также должна быть <=.

...