2013-12-15 8 views
10

Ich versuche, eine TGA/BMP-Datei zu laden. Dies funktioniert gut, aber das Endergebnis sieht wie folgt aus:Laden einer TGA/BMP-Datei in C++/OpenGL

enter image description here

Das Bild, das ich zu Last bin versucht, sieht wie folgt aus:

enter image description here

Einige der Code verwende ich :

GLuint texture; 
const char* filename = "/Users/Admin/Documents/Visual Studio 2013/Projects/OpenGL/OpenGL/image.tga"; 

unsigned char* data; 
data = (unsigned char *) malloc(128 * 128 * 3); 
FILE* f; 
fopen_s(&f, filename, "rb"); 
fread(data, 128 * 128 * 3, 1, f); 

glGenTextures(1, &texture); 
glBindTexture(GL_TEXTURE_2D, texture); 

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 

Hat jemand eine Idee, was ich falsch mache?

+4

tga-Dateien haben ein Kopf sie nicht? Es sieht so aus, als ob Sie erwarten, dass es ein 128x128 Pixel raw ist. Ich weiß nicht, warum Sie erwarten, dass das funktioniert. –

+0

Ich frage mich nur, aber wenn Sie C++ verwenden, warum verwenden Sie 'malloc()'? – Vallentin

+0

Ich sah das auf einem anderen Tutorial. Ich habe verschiedene Dinge ausprobiert, zum Beispiel mit malloc(), aber das Ergebnis hat sich nicht geändert – user3075425

Antwort

15

Sie können eine Bitmap und eine tga-Datei laden, diese ..

#include <vector> 
#include <fstream> 

#ifdef __APPLE__ 
#include <OpenGL/gl.h> 
#include <OpenGL/glu.h> 
#endif 


#ifdef _WIN32 
#include <GL/gl.h> 
#include <GL/glu.h> 
#endif 


typedef union PixelInfo 
{ 
    std::uint32_t Colour; 
    struct 
    { 
     std::uint8_t B, G, R, A; 
    }; 
} *PPixelInfo; 


class BMP 
{ 
private: 
    std::uint32_t width, height; 
    std::uint16_t BitsPerPixel; 
    std::vector<std::uint8_t> Pixels; 

public: 
    BMP(const char* FilePath); 
    std::vector<std::uint8_t> GetPixels() const {return this->Pixels;} 
    std::uint32_t GetWidth() const {return this->width;} 
    std::uint32_t GetHeight() const {return this->height;} 
    bool HasAlphaChannel() {return BitsPerPixel == 32;} 
}; 

BMP::BMP(const char* FilePath) 
{ 
    std::fstream hFile(FilePath, std::ios::in | std::ios::binary); 
    if (!hFile.is_open()) throw std::invalid_argument("Error: File Not Found."); 

    hFile.seekg(0, std::ios::end); 
    std::size_t Length = hFile.tellg(); 
    hFile.seekg(0, std::ios::beg); 
    std::vector<std::uint8_t> FileInfo(Length); 
    hFile.read(reinterpret_cast<char*>(FileInfo.data()), 54); 

    if(FileInfo[0] != 'B' && FileInfo[1] != 'M') 
    { 
     hFile.close(); 
     throw std::invalid_argument("Error: Invalid File Format. Bitmap Required."); 
    } 

    if (FileInfo[28] != 24 && FileInfo[28] != 32) 
    { 
     hFile.close(); 
     throw std::invalid_argument("Error: Invalid File Format. 24 or 32 bit Image Required."); 
    } 

    BitsPerPixel = FileInfo[28]; 
    width = FileInfo[18] + (FileInfo[19] << 8); 
    height = FileInfo[22] + (FileInfo[23] << 8); 
    std::uint32_t PixelsOffset = FileInfo[10] + (FileInfo[11] << 8); 
    std::uint32_t size = ((width * BitsPerPixel + 31)/32) * 4 * height; 
    Pixels.resize(size); 

    hFile.seekg (PixelsOffset, std::ios::beg); 
    hFile.read(reinterpret_cast<char*>(Pixels.data()), size); 
    hFile.close(); 
} 

int main() 
{ 
    BMP info = BMP("C:/Users/....../Desktop/SomeBmp.bmp"); 

    GLuint texture = 0; 
    glGenTextures(1, &texture); 
    glBindTexture(GL_TEXTURE_2D, texture); 
    glTexImage2D(GL_TEXTURE_2D, 0, info.HasAlphaChannel() ? GL_RGBA : GL_RGB, info.GetWidth(), info.GetWidth(), 0, info.HasAlphaChannel() ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, info.GetPixels().data()); 
} 

TGA ist mit:

#include <vector> 
#include <fstream> 

#ifdef __APPLE__ 
#include <OpenGL/gl.h> 
#include <OpenGL/glu.h> 
#endif 


#ifdef _WIN32 
#include <GL/gl.h> 
#include <GL/glu.h> 
#endif 

typedef union PixelInfo 
{ 
    std::uint32_t Colour; 
    struct 
    { 
     std::uint8_t R, G, B, A; 
    }; 
} *PPixelInfo; 

class Tga 
{ 
private: 
    std::vector<std::uint8_t> Pixels; 
    bool ImageCompressed; 
    std::uint32_t width, height, size, BitsPerPixel; 

public: 
    Tga(const char* FilePath); 
    std::vector<std::uint8_t> GetPixels() {return this->Pixels;} 
    std::uint32_t GetWidth() const {return this->width;} 
    std::uint32_t GetHeight() const {return this->height;} 
    bool HasAlphaChannel() {return BitsPerPixel == 32;} 
}; 

Tga::Tga(const char* FilePath) 
{ 
    std::fstream hFile(FilePath, std::ios::in | std::ios::binary); 
    if (!hFile.is_open()){throw std::invalid_argument("File Not Found.");} 

    std::uint8_t Header[18] = {0}; 
    std::vector<std::uint8_t> ImageData; 
    static std::uint8_t DeCompressed[12] = {0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; 
    static std::uint8_t IsCompressed[12] = {0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; 

    hFile.read(reinterpret_cast<char*>(&Header), sizeof(Header)); 

    if (!std::memcmp(DeCompressed, &Header, sizeof(DeCompressed))) 
    { 
     BitsPerPixel = Header[16]; 
     width = Header[13] * 256 + Header[12]; 
     height = Header[15] * 256 + Header[14]; 
     size = ((width * BitsPerPixel + 31)/32) * 4 * height; 

     if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) 
     { 
      hFile.close(); 
      throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); 
     } 

     ImageData.resize(size); 
     ImageCompressed = false; 
     hFile.read(reinterpret_cast<char*>(ImageData.data()), size); 
    } 
    else if (!std::memcmp(IsCompressed, &Header, sizeof(IsCompressed))) 
    { 
     BitsPerPixel = Header[16]; 
     width = Header[13] * 256 + Header[12]; 
     height = Header[15] * 256 + Header[14]; 
     size = ((width * BitsPerPixel + 31)/32) * 4 * height; 

     if ((BitsPerPixel != 24) && (BitsPerPixel != 32)) 
     { 
      hFile.close(); 
      throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit Image."); 
     } 

     PixelInfo Pixel = {0}; 
     int CurrentByte = 0; 
     std::size_t CurrentPixel = 0; 
     ImageCompressed = true; 
     std::uint8_t ChunkHeader = {0}; 
     int BytesPerPixel = (BitsPerPixel/8); 
     ImageData.resize(width * height * sizeof(PixelInfo)); 

     do 
     { 
      hFile.read(reinterpret_cast<char*>(&ChunkHeader), sizeof(ChunkHeader)); 

      if(ChunkHeader < 128) 
      { 
       ++ChunkHeader; 
       for(int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) 
       { 
        hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); 

        ImageData[CurrentByte++] = Pixel.B; 
        ImageData[CurrentByte++] = Pixel.G; 
        ImageData[CurrentByte++] = Pixel.R; 
        if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; 
       } 
      } 
      else 
      { 
       ChunkHeader -= 127; 
       hFile.read(reinterpret_cast<char*>(&Pixel), BytesPerPixel); 

       for(int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) 
       { 
        ImageData[CurrentByte++] = Pixel.B; 
        ImageData[CurrentByte++] = Pixel.G; 
        ImageData[CurrentByte++] = Pixel.R; 
        if (BitsPerPixel > 24) ImageData[CurrentByte++] = Pixel.A; 
       } 
      } 
     } while(CurrentPixel < (width * height)); 
    } 
    else 
    { 
     hFile.close(); 
     throw std::invalid_argument("Invalid File Format. Required: 24 or 32 Bit TGA File."); 
    } 

    hFile.close(); 
    this->Pixels = ImageData; 
} 


int main() 
{ 
    Tga info = Tga("C:/Users/...../Desktop/SomeTGA.tga"); 

    GLuint texture = 0; 
    glGenTextures(1, &texture); 
    glBindTexture(GL_TEXTURE_2D, texture); 
    glTexImage2D(GL_TEXTURE_2D, 0, info.HasAlphaChannel() ? GL_RGBA : GL_RGB, info.GetWidth(), info.GetWidth(), 0, info.HasAlphaChannel() ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, info.GetPixels().data()); 

} 
+0

Danke für deinen Code, aber was bedeutet RGB in Zeile RGB Pixel = {0}; meinst du struct RGBA? Können Sie die gesamte Klassendatei in githup bereitstellen, um mehr Leuten zu helfen? – wangdq

+0

@wangdq Korrigiert. Header hinzugefügt. – Brandon

+0

Der TGA ist für die Breite und Höhe aus.Es sollte mit 256 nicht 255 multiplizieren (0xFF) width = Header [13] * 256 + Header [12]; Höhe = Kopfzeile [15] * 256 + Kopfzeile [14]; – GambitSunob

6

Ich interpretierte diese Frage als: "Wie lade ich eine TGA-Datei? Was ich versucht habe, hat nicht funktioniert."

99% der Zeit die richtige Antwort wird nicht sein "Kopieren Sie diese Funktion, die TGA-Dateien lädt, die ich schrieb". Das ist der Ansatz, den die akzeptierte Antwort annimmt. Aber wenn Sie eine Lösung wollen, die nicht nur funktioniert, sondern auch wartungsfreundlicher ist und mit größerer Wahrscheinlichkeit behoben wird, wenn sie Fehler enthält, dann ist es besser, eine Bibliothek zu verwenden. Eine eigene Lösung zu rollen ist ein guter Weg zu lernen und sollte gefördert werden, aber es ist normalerweise nicht der beste oder einfachste Weg, etwas zu erledigen.

Verwenden Sie eine echte Bildbibliothek, anstatt zu versuchen, eine eigene Funktion zum Lesen der Bilder zu erstellen. Ihre Annahmen bezüglich des Datenformats sind nicht korrekt, daher sind die Daten, die Sie erhalten, eine Koje. Sie scheinen davon auszugehen, dass die Daten ein 128x128 Pixel grober Wert sind.

http://tgalib.sourceforge.net/ ist eine Open-Source-Bibliothek zum Lesen von TGA-Dateien. Verwenden Sie es zum Beispiel.

https://github.com/nothings/stb ist eine weitere Alternative mit einer liberaleren (public domain) Lizenz, dass TGA-Dateien zusätzlich zu dem Laden einer Menge anderer Dinge hat, die sich als nützlich für OpenGL-Programme kommen würde.

Beide Bibliotheken sind eine bessere Wahl als Kopieren-Einfügen-Code, den Sie online gefunden haben.