2013-12-15 4 views
10

Sto provando a caricare un file tga/bmp. Questo funziona bene, ma il risultato finale è simile al seguente:Caricamento di un file tga/bmp in C++/OpenGL

enter image description here

L'immagine che sto cercando di carico simile a questo:

enter image description here

Parte del codice che sto utilizzando :

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); 

Qualcuno ha un'idea di ciò che sto facendo male?

+4

file TGA ha un colpo di testa non è vero? Sembra che tu ti aspetti che sia un raw di 128x128 pixel. Non so perché ti aspetti che funzioni. –

+0

Mi chiedo solo, ma se stai usando C++, allora perché stai usando 'malloc()'? – Vallentin

+0

L'ho visto su un altro tutorial. Ho provato diverse cose, ad esempio usando malloc(), ma il risultato non è cambiato – user3075425

risposta

15

è possibile caricare un bitmap e un file tga utilizzando questi ..

#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()); 
} 

del TGA:

#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

Grazie per il tuo codice, ma cosa significa RGB in linea RGB Pixel = {0}; volevi dire struct RGBA? Puoi fornire l'intero file di classe in githup per aiutare più persone? – wangdq

+0

@wangdq Risolto. Aggiunte anche le intestazioni. – Brandon

+0

Il TGA è spento per la larghezza e l'altezza.Dovrebbe moltiplicarsi per 256 not 255 (0xFF) width = Header [13] * 256 + Header [12]; height = Header [15] * 256 + Header [14]; – GambitSunob

6

Ho interpretato questa domanda come: "Come caricare un file TGA? Quello che ho provato non ha funzionato."

99% del tempo in cui la risposta corretta non sarà "copia e incolla questa funzione che carica i file TGA che ho scritto". Questo è l'approccio che sta prendendo la risposta accettata. Ma se vuoi una soluzione che non solo funzioni, ma che sia più manutenibile e più probabile che venga risolta se contiene bug, allora è meglio usare una libreria. Rollare la propria soluzione è un buon modo per imparare e dovrebbe essere incoraggiato, ma di solito non è il modo migliore o più semplice per fare qualcosa.

Utilizzare una libreria di immagini reale invece di provare a eseguire la propria funzione per leggerli. Le tue ipotesi sul formato dei dati non sono corrette, quindi i dati che ricevi sono a castello. Sembra che si assuma che i dati siano grezzi 128x128 pixel.

http://tgalib.sourceforge.net/ è una libreria open source per la lettura di file TGA. Usalo, per esempio.

https://github.com/nothings/stb è un'altra alternativa con un (dominio pubblico) di licenza più liberale che, oltre al caricamento di file TGA ha un sacco di altre cose che sarebbe venuto in aiuto per i programmi OpenGL.

Entrambe le librerie sono una scelta migliore rispetto al codice copia-incolla che hai trovato online.