Загрузка файла tga/bmp в C++/OpenGL
Я пытаюсь загрузить файл tga/bmp. Это работает нормально, но конечный результат выглядит так:
Изображение, которое я пытаюсь загрузить, выглядит так:
Часть кода, который я использую:
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);
У кого-нибудь есть идея, что я делаю не так?
2 ответа
Вы можете загрузить растровое изображение и файл 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-х:
#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());
}
Я интерпретировал этот вопрос как: "Как загрузить файл TGA? То, что я пробовал, не сработало".
В 99% случаев правильный ответ не будет "скопировать и вставить эту функцию, которая загружает файлы TGA, которые я написал". Это подход, который принимает принятый ответ. Но если вам нужно решение, которое не только работает, но и будет более ремонтопригодным и с большей вероятностью будет исправлено, если оно будет содержать ошибки, то лучше использовать библиотеку. Использование собственного решения - хороший способ обучения, и его следует поощрять, но обычно это не лучший и не самый простой способ что-то сделать.
Используйте реальную библиотеку изображений вместо того, чтобы пытаться свернуть собственную функцию для их чтения. Ваши предположения о формате данных неверны, поэтому данные, которые вы получаете, являются ложными. Похоже, вы предполагаете, что данные имеют размер 128x128 пикселей.
http://tgalib.sourceforge.net/ - библиотека с открытым исходным кодом для чтения файлов TGA. Используйте это, например.
https://github.com/nothings/stb - это еще одна альтернатива с более либеральной (общедоступной) лицензией, которая помимо загрузки файлов TGA имеет много других вещей, которые могут пригодиться для программ OpenGL.
Обе библиотеки являются лучшим выбором, чем код для вставки, который вы нашли в Интернете.