1

我一直在学习有关加载 TGA 文件的基本 OpenGL 教程,以用作 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);
};

这是cpp中的加载TGA函数:

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
}

它似乎加载了一些数据,但它不断返回它失败。任何有关为什么的帮助将不胜感激。如果它有点罗嗦,我很抱歉,但我不确定什么是重要的或不重要的。

更新:所以,我只是重写了函数。我使用的 ifsteam 似乎是问题的原因。具体来说,它会尝试加载比我输入的数据字节多得多的数据。我不知道行为的原因,但我在下面列出了我的功能代码。感谢大家的帮助。

4

3 回答 3

0

我不熟悉C++,抱歉。

你确定这条线file.seekg(-imageSize, std::ios::end);不应该是file.seekg(headerSize, std::ios::start);吗?

从头开始比从头开始更有意义。

您还应该检查ColorMapType != 0.

PS 这里的if( width < 0 || height <=0宽度检查也应该如此<=

于 2012-01-13T06:19:41.870 回答
0

问题可能取决于不支持压缩 TGA 的 TGA 算法。

确保您不压缩 TGA,并且 TGA 顺序(不太重要)位于左下角原点。

我通常使用 GIMP,同时,取消选中 RLE 压缩并将左下对齐。

于 2012-01-13T07:41:47.120 回答
0

所以,我从使用 ifstream 改为使用 FILE。ifstream 试图加载比我在参数中列出的更多的字节。这是新代码。(注意:它仍然需要优化。我相信有一些未使用的变量浮动,但它工作得很好。)。再次感谢大家的帮助。

头文件:

    //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;
}
于 2012-01-15T12:49:46.053 回答