Loading a tga/bmp file in C++/OpenGL

前端 未结 2 1855
甜味超标
甜味超标 2020-12-17 19:42

I\'m trying to load a tga/bmp file. This works fine, but the end result looks like this:

\"enter

相关标签:
2条回答
  • 2020-12-17 20:15

    I interpreted this question as: "How do I load a TGA file? What I tried didn't work."

    99% of the time the right answer is not going to be "copy and paste this function that loads TGA files which I wrote". That is the approach that the accepted answer is taking. But if you want a solution that not only works, but will be more maintainable and more likely to be fixed if it contains bugs, then it is better to use a library. Rolling your own solution is a fine way to learn and should be encouraged, but it is not usually the best or easiest way to get something done.

    Use a real image library instead of trying to roll your own function to read them. Your assumptions on the data format are not correct, so the data you are getting is bunk. You appear to be assuming that the data is a 128x128 pixel raw.

    http://tgalib.sourceforge.net/ is an open source library for reading TGA files. Use it, for example.

    https://github.com/nothings/stb is another alternative with a more liberal (public domain) license that in addition to loading TGA files has a lot of other things that would come in handy for OpenGL programs.

    Both libraries are a better choice than copy-pasting code you found online.

    0 讨论(0)
  • 2020-12-17 20:33

    You can load a bitmap and a tga file using these..

    #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's:

    #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 讨论(0)
提交回复
热议问题