#pragma once #include #include #include #include typedef union PixelInfo { std::uint32_t Colour; struct { std::uint8_t B, G, R, A; }; } *PPixelInfo; class Tga { private: std::vector Pixels; bool ImageCompressed; std::uint32_t width, height, size, BitsPerPixel; public: Tga(const char* FilePath); std::vector 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 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(&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(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(&ChunkHeader), sizeof(ChunkHeader)); if (ChunkHeader < 128) { ++ChunkHeader; for (int I = 0; I < ChunkHeader; ++I, ++CurrentPixel) { hFile.read(reinterpret_cast(&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(&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; }