136 lines
3.5 KiB
C
136 lines
3.5 KiB
C
|
#pragma once
|
||
|
#include <vector>
|
||
|
#include <gl\glut.h>
|
||
|
#include <Windows.h>
|
||
|
#include <fstream>
|
||
|
|
||
|
typedef union PixelInfo
|
||
|
{
|
||
|
std::uint32_t Colour;
|
||
|
struct
|
||
|
{
|
||
|
std::uint8_t B, G, R, 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] * 0xFF + Header[12];
|
||
|
height = Header[15] * 0xFF + 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] * 0xFF + Header[12];
|
||
|
height = Header[15] * 0xFF + 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.");
|
||
|
}
|
||
|
|
||
|
//fix color mix
|
||
|
std::uint8_t temp;
|
||
|
unsigned int it = 0;
|
||
|
while (1)
|
||
|
{
|
||
|
temp = ImageData[it];
|
||
|
ImageData[it] = ImageData[it + 2];
|
||
|
ImageData[it + 2] = temp;
|
||
|
BitsPerPixel == 32 ? it += 2 : it += 3;
|
||
|
|
||
|
if (it + 2 >= size)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hFile.close();
|
||
|
this->Pixels = ImageData;
|
||
|
}
|