port: EterImageLib Image/TGAImage/DXTCImage verbatim (+ d3d.h ddraw shim)

-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>
This commit is contained in:
shenlei
2026-09-30 13:31:21 +09:00
co-authored by Claude Opus 5.5
parent 32c5a09d6e
commit 75ea2703c6
10 changed files with 2758 additions and 152 deletions
+125
View File
@@ -0,0 +1,125 @@
// 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;
}