-fno-strict-aliasing on the port targets: 40250 relies on MSVC's lack of type-based alias analysis (DXTCImage reads Color8888 through DWORD*). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
126 lines
4.5 KiB
C++
126 lines
4.5 KiB
C++
// 40250 EterImageLib (CImage, CTGAImage, CDXTCImage), verbatim on the platform.
|
|
#include "EterImageLib/StdAfx.h"
|
|
#include "EterImageLib/TGAImage.h"
|
|
#include "EterImageLib/DXTCImage.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
|
|
namespace {
|
|
// "DDS " + a 124-byte DDSURFACEDESC2 (linear size, FourCC) + the blocks of one 4x4 level.
|
|
std::vector<BYTE> MakeDDS(const char* fourcc, const std::vector<BYTE>& blocks)
|
|
{
|
|
std::vector<BYTE> dds(4 + 124, 0);
|
|
memcpy(&dds[0], "DDS ", 4);
|
|
DWORD* h = reinterpret_cast<DWORD*>(&dds[4]);
|
|
h[0] = 124;
|
|
h[1] = 0x1 | 0x2 | 0x4 | 0x1000 | 0x80000; // CAPS|HEIGHT|WIDTH|PIXELFORMAT|LINEARSIZE
|
|
h[2] = 4;
|
|
h[3] = 4;
|
|
h[4] = DWORD(blocks.size());
|
|
h[18] = 32; // ddpfPixelFormat.dwSize (offset 72)
|
|
h[19] = 0x4; // DDPF_FOURCC
|
|
memcpy(&h[20], fourcc, 4);
|
|
dds.insert(dds.end(), blocks.begin(), blocks.end());
|
|
return dds;
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
int failures = 0;
|
|
auto check = [&failures](bool ok, const char *name) {
|
|
if (!ok) {
|
|
std::fprintf(stderr, "FAIL %s\n", name);
|
|
++failures;
|
|
}
|
|
};
|
|
|
|
// CImage: Clear, PutImage clips nothing, FlipTopToBottom swaps rows.
|
|
{
|
|
CImage a, b;
|
|
a.Create(4, 2);
|
|
a.Clear(0x11111111);
|
|
b.Create(2, 1);
|
|
b.Clear(0x22222222);
|
|
a.PutImage(1, 1, &b);
|
|
check(a.GetLinePointer(1)[1] == 0x22222222 && a.GetLinePointer(1)[3] == 0x11111111 && a.GetLinePointer(0)[1] == 0x11111111, "PutImage");
|
|
a.FlipTopToBottom();
|
|
check(a.GetLinePointer(0)[2] == 0x22222222 && a.GetLinePointer(1)[2] == 0x11111111, "FlipTopToBottom");
|
|
check(!a.IsEmpty() && a.GetWidth() == 4 && a.GetHeight() == 2, "CImage size");
|
|
}
|
|
|
|
// CTGAImage: SaveToDiskFile writes the rows as stored with a bottom-left origin (desc 0x08), so loading
|
|
// the file back flips it (the CTGAImage(CImage&) constructor pre-flips for that). RLE saving is not
|
|
// exercised: 40250 never sets m_pdwEndPtr (no caller saves compressed; TargaResource only loads).
|
|
{
|
|
CTGAImage img;
|
|
img.Create(5, 3);
|
|
DWORD* p = img.GetBasePointer();
|
|
for (int i = 0; i < 15; ++i)
|
|
p[i] = 0x80000000u + DWORD(i);
|
|
char path[] = "/tmp/mt_tga_XXXXXX";
|
|
close(mkstemp(path));
|
|
check(img.SaveToDiskFile(path), "TGA SaveToDiskFile");
|
|
CTGAImage back;
|
|
check(back.LoadFromDiskFile(path), "TGA LoadFromDiskFile");
|
|
bool flipped = back.GetWidth() == 5 && back.GetHeight() == 3;
|
|
for (int y = 0; flipped && y < 3; ++y)
|
|
for (int x = 0; x < 5; ++x)
|
|
flipped = flipped && back.GetLinePointer(y)[x] == p[(2 - y) * 5 + x];
|
|
check(flipped, "TGA raw round trip is flipped");
|
|
check(back.GetHeader().width == 5 && back.GetHeader().colorBits == 32, "TGA header");
|
|
remove(path);
|
|
}
|
|
// RLE (type 10), 32-bit, top-left origin: a run packet then a raw packet, BGRA bytes.
|
|
{
|
|
std::vector<BYTE> tga(18, 0);
|
|
tga[2] = 10;
|
|
tga[12] = 5;
|
|
tga[14] = 1;
|
|
tga[16] = 32;
|
|
tga[17] = 0x28;
|
|
const BYTE body[] = {0x82, 1, 2, 3, 4, 0x01, 5, 6, 7, 8, 9, 10, 11, 12};
|
|
tga.insert(tga.end(), body, body + sizeof(body));
|
|
CTGAImage img;
|
|
check(img.LoadFromMemory(int(tga.size()), tga.data()), "TGA RLE load");
|
|
DWORD* p = img.GetBasePointer();
|
|
check(p[0] == 0x04030201 && p[2] == 0x04030201 && p[3] == 0x08070605 && p[4] == 0x0C0B0A09, "TGA RLE pixels");
|
|
}
|
|
|
|
// CDXTCImage DXT1: 565 endpoints shifted to 888 without replication, 4-colour mode thirds, rows LSB first.
|
|
{
|
|
std::vector<BYTE> block = {0x00, 0xF8, 0x1F, 0x00, 0xE4, 0x00, 0x00, 0x00};
|
|
std::vector<BYTE> dds = MakeDDS("DXT1", block);
|
|
CDXTCImage image;
|
|
check(image.LoadFromMemory(dds.data()), "DXT1 LoadFromMemory");
|
|
check(image.m_CompFormat == PF_DXT1 && image.m_nWidth == 4 && image.m_dwMipMapCount == 1, "DXT1 header");
|
|
DWORD px[16] = {};
|
|
image.Decompress(0, px);
|
|
check(px[0] == 0xFFF80000 && px[1] == 0xFF0000F8 && px[2] == 0xFFA50052 && px[3] == 0xFF5200A5, "DXT1 row 0");
|
|
check(px[4] == 0xFFF80000 && px[15] == 0xFFF80000, "DXT1 index 0 rows");
|
|
}
|
|
|
|
// CDXTCImage DXT5: alpha0/alpha1 with 3-bit indices, then the colour block.
|
|
{
|
|
std::vector<BYTE> block = {0x80, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0xF8, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
std::vector<BYTE> dds = MakeDDS("DXT5", block);
|
|
CDXTCImage image;
|
|
check(image.LoadFromMemory(dds.data()) && image.m_CompFormat == PF_DXT5, "DXT5 load");
|
|
DWORD px[16] = {};
|
|
image.Decompress(0, px);
|
|
check(px[0] == 0x10F80000 && px[1] == 0x80F80000 && px[15] == 0x80F80000, "DXT5 alpha");
|
|
}
|
|
|
|
// A format other than DXT1/3/5 is refused.
|
|
{
|
|
std::vector<BYTE> dds = MakeDDS("ATI2", std::vector<BYTE>(16, 0));
|
|
CDXTCImage image;
|
|
check(!image.LoadFromMemory(dds.data()), "unknown FourCC refused");
|
|
}
|
|
return failures ? 1 : 0;
|
|
}
|