C++ OpenGL TGA加载失败

问题描述:

我一直在通过加载TGA文件的基本OpenGl教程,将其用作3D对象上的纹理。我已经能够从TGA头部加载数据,但是当我尝试加载实际的图像数据时,它失败了。我不确定它出错的地方。这里是我的纹理加载类:C++ OpenGL 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 
} 

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

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

+3

你是怎么从调试学到了什么? – 2012-01-13 06:00:05

+0

不幸的是,并不多。 imageData指针肯定会加载某种类型的数据,但它无论如何都会失败。 – Donutfiend84 2012-01-13 06:34:34

+2

请注意,您应该使用'delete [] imageData',虽然 – rotoglup 2012-01-13 07:00:09

因此,我从使用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; 
} 

我不熟悉C++,很抱歉。

您确定该行file.seekg(-imageSize, std::ios::end);不应该是file.seekg(headerSize, std::ios::start);

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

您还应该检查ColorMapType != 0

P.S.这里的if(width < 0 || height <=0宽度检查也应该是<=

+0

我曾尝试过: file.seekg(18,std :: ios :: beg); 但是由于它似乎没有影响结果,所以我将它改回来了。 – Donutfiend84 2012-01-13 06:31:39

+0

我不认为这是一个很好的做法,坚持只在明显错位的情况下才“正常工作”的解决方案。在这种情况下,它应该是'beg'和某种'SizeOf(tgaHeader)'而不是'18'。至于问题 - 调试器是你的朋友 - 检查你有什么'file.read'错误。 – Kromster 2012-01-13 06:51:39

+0

你也应该检查'ColorMapType!= 0' – Kromster 2012-01-13 07:46:37

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

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

我通常使用GIMP,并在相同的时刻,取消RLE压缩并放置左下对齐。

+1

这就是为什么有一个检查:'如果(TGAheader.ImageType!= 2)返回false;'。类型2代表未压缩的TGA。如果TGA顺序颠倒,它不会影响加载,只是在渲染中颠倒显示图像。 – Kromster 2012-01-13 07:45:04