Files

131 lines
3.4 KiB
C++
Raw Permalink Normal View History

// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <TestFramework.h>
#include <Image/LoadTGA.h>
#include <Image/Surface.h>
#pragma pack (1)
struct TGAHeader
{
uint8 mIDLength;
uint8 mColorMapType;
uint8 mImageType;
uint16 mColorMapFirstEntryIndex;
uint16 mColorMapLength;
uint8 mColorMapEntrySize;
uint16 mXOrigin;
uint16 mYOrigin;
uint16 mWidth;
uint16 mHeight;
uint8 mPixelDepth;
uint8 mImageDescriptor;
};
#pragma pack ()
Ref<Surface> LoadTGA(istream &inStream)
{
bool loaded = true;
// Read header
TGAHeader header;
inStream.read((char *)&header, sizeof(header));
if (inStream.fail())
return nullptr;
// Get properties
int bytes_per_pixel = (header.mPixelDepth + 7) >> 3;
int scan_width = bytes_per_pixel * header.mWidth;
// Check type
if (header.mImageType < 1 || header.mImageType > 2)
{
Trace("Not a readable TGA");
return nullptr;
}
// Check compression
if ((header.mImageType == 1 && header.mColorMapType != 1) || (header.mImageType == 2 && header.mColorMapType != 0))
{
Trace("Not an uncompressed TGA");
return nullptr;
}
Ref<Surface> surface;
if (header.mPixelDepth == 8)
{
// Determine pixel format
ESurfaceFormat format;
int pixel_size;
switch (header.mColorMapEntrySize)
{
case 15: format = ESurfaceFormat::X1R5G5B5; pixel_size = 2; break;
case 16: format = ESurfaceFormat::X1R5G5B5; pixel_size = 2; break;
case 24: format = ESurfaceFormat::R8G8B8; pixel_size = 3; break;
case 32: format = ESurfaceFormat::A8R8G8B8; pixel_size = 4; break;
default: Trace("Has invalid format"); return nullptr;
}
// Seek to beginning of palette
inStream.seekg(sizeof(TGAHeader) + header.mIDLength);
// Load palette
int pal_bytes = pixel_size * header.mColorMapLength;
uint8 *palette = new uint8 [pal_bytes];
inStream.read((char *)palette, pal_bytes);
loaded = loaded && !inStream.fail();
// Convert pixel data to a surface
surface = new SoftwareSurface(header.mWidth, header.mHeight, format);
surface->Lock(ESurfaceLockMode::Write);
uint8 *scan_line = new uint8 [scan_width];
for (int y = header.mHeight - 1; y >= 0; --y)
{
// Load one scan line
inStream.read((char *)scan_line, scan_width);
loaded = loaded && !inStream.fail();
// Copy one scan line
uint8 *in_pixel = scan_line;
uint8 *out_pixel = (uint8 *)surface->GetScanLine(y);
for (int x = 0; x < header.mWidth; ++x, ++in_pixel, out_pixel += pixel_size)
memcpy(out_pixel, palette + (*in_pixel - header.mColorMapFirstEntryIndex) * pixel_size, pixel_size);
}
surface->UnLock();
// Release temporaries
delete [] palette;
delete [] scan_line;
}
else
{
// Determine pixel format
ESurfaceFormat format;
switch (header.mPixelDepth)
{
case 15: format = ESurfaceFormat::X1R5G5B5; break;
case 16: format = ESurfaceFormat::X1R5G5B5; break;
case 24: format = ESurfaceFormat::R8G8B8; break;
case 32: format = ESurfaceFormat::A8R8G8B8; break;
default: Trace("Invalid format"); return nullptr;
}
// Convert pixel data to a surface
surface = new SoftwareSurface(header.mWidth, header.mHeight, format, scan_width);
surface->Lock(ESurfaceLockMode::Write);
for (int y = header.mHeight - 1; y >= 0; --y)
{
inStream.read((char *)surface->GetScanLine(y), scan_width);
loaded = loaded && !inStream.fail();
}
surface->UnLock();
}
return loaded? surface : Ref<Surface>(nullptr);
}