在 C++/OpenGL 中加载 tga/bmp 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20595340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loading a tga/bmp file in C++/OpenGL
提问by user3075425
I'm trying to load a tga/bmp file. This works fine, but the end result looks like this:
我正在尝试加载 tga/bmp 文件。这工作正常,但最终结果如下所示:
The image I'm trying to load looks like this:
我尝试加载的图像如下所示:
Some of the code I'm using:
我正在使用的一些代码:
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);
Does anybody have an idea what I'm doing wrong?
有人知道我做错了什么吗?
回答by Brandon
You can load a bitmap and a tga file using these..
您可以使用这些加载位图和 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 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:
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());
}
回答by Tim Seguine
I interpreted this question as: "How do I load a TGA file? What I tried didn't work."
我将这个问题解释为:“如何加载 TGA 文件?我尝试的方法无效。”
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.
99% 的情况下,正确的答案不会是“复制并粘贴这个加载我编写的 TGA 文件的函数”。这就是公认的答案所采用的方法。但是,如果您想要一个不仅有效的解决方案,而且如果它包含错误,则更易于维护并且更可能被修复,那么最好使用库。滚动你自己的解决方案是一种很好的学习方式,应该受到鼓励,但这通常不是完成某件事的最佳或最简单的方法。
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.
使用真实的图像库,而不是尝试使用自己的函数来读取它们。你对数据格式的假设不正确,所以你得到的数据是胡说八道。您似乎假设数据是 128x128 像素的原始数据。
http://tgalib.sourceforge.net/is an open source library for reading TGA files. Use it, for example.
http://tgalib.sourceforge.net/是一个用于读取 TGA 文件的开源库。例如,使用它。
https://github.com/nothings/stbis 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.
https://github.com/nothings/stb是另一种具有更自由(公共领域)许可证的替代方案,除了加载 TGA 文件外,还有很多其他东西可以为 OpenGL 程序派上用场。
Both libraries are a better choice than copy-pasting code you found online.
这两个库都是比您在网上找到的复制粘贴代码更好的选择。