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
File diff suppressed because it is too large Load Diff
+133 -81
View File
@@ -1,92 +1,144 @@
// Platform skeleton for EterImageLib/Image.h (40250 EterImageLib/Image.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterImageLib/Image.cpp, verbatim.
#include "EterImageLib/StdAfx.h"
#include <assert.h>
#include "EterImageLib/Image.h"
#include "../PlatformStub.h"
CImage::CImage(CImage & image)
{
Initialize();
int w = image.GetWidth();
int h = image.GetHeight();
Create(w, h);
DWORD * pdwDest = GetBasePointer();
DWORD * pdwSrc = image.GetBasePointer();
memcpy(pdwDest, pdwSrc, w * h * sizeof(DWORD));
}
void CImage::SetFileName(const char* c_szFileName)
{
m_stFileName = c_szFileName;
}
const std::string& CImage::GetFileNameString()
{
return m_stFileName;
}
void CImage::PutImage(int x, int y, CImage* pImage)
{
assert(x >= 0 && x + pImage->GetWidth() <= GetWidth());
assert(y >= 0 && y + pImage->GetHeight() <= GetHeight());
int len = pImage->GetWidth() * sizeof(DWORD);
for (int j = 0; j < pImage->GetHeight(); ++j)
{
DWORD * pdwDest = GetLinePointer(y + j) + x;
memcpy(pdwDest, pImage->GetLinePointer(j), len);
}
}
DWORD* CImage::GetBasePointer()
{
assert(m_pdwColors != NULL);
return m_pdwColors;
}
DWORD* CImage::GetLinePointer(int line)
{
assert(m_pdwColors != NULL);
return m_pdwColors + line * m_width;
}
int CImage::GetWidth() const
{
assert(m_pdwColors != NULL);
return m_width;
}
int CImage::GetHeight() const
{
assert(m_pdwColors != NULL);
return m_height;
}
void CImage::Clear(DWORD color)
{
assert(m_pdwColors != NULL);
for (int y = 0; y < m_height; ++y)
{
DWORD * colorLine = &m_pdwColors[y * m_width];
for (int x = 0; x < m_width; ++x)
colorLine[x] = color;
}
}
void CImage::Create(int width, int height)
{
Destroy();
m_width = width;
m_height = height;
m_pdwColors = new DWORD[m_width*m_height];
}
void CImage::Destroy()
{
if (m_pdwColors)
{
delete [] m_pdwColors;
m_pdwColors = NULL;
}
}
void CImage::Initialize()
{
m_pdwColors = NULL;
m_width = 0;
m_height = 0;
}
bool CImage::IsEmpty() const
{
return (m_pdwColors == NULL) ? true : false;
}
void CImage::FlipTopToBottom()
{
DWORD * swap = new DWORD[m_width * m_height];
int row;
UINT width = GetWidth();
UINT height = GetHeight();
DWORD * end_row;
DWORD * start_row;
for (row = 0; row < GetHeight() / 2; row++)
{
end_row = &(m_pdwColors[width * (height - row - 1)]);
start_row = &(m_pdwColors[width * row]);
memcpy(swap, end_row, width * sizeof(DWORD));
memcpy(end_row, start_row, width * sizeof(DWORD));
memcpy(start_row, swap, width * sizeof(DWORD));
}
delete [] swap;
}
CImage::CImage()
{
MT_PLATFORM_STUB();
}
CImage::CImage(CImage &)
{
MT_PLATFORM_STUB();
Initialize();
}
CImage::~CImage()
{
MT_PLATFORM_STUB();
}
auto CImage::Destroy() -> void
{
MT_PLATFORM_STUB();
}
auto CImage::Create(int, int) -> void
{
MT_PLATFORM_STUB();
}
auto CImage::Clear(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CImage::GetWidth() const -> int
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
}
auto CImage::GetHeight() const -> int
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
}
auto CImage::GetBasePointer() -> DWORD *
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD *>();
}
auto CImage::GetLinePointer(int) -> DWORD *
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD *>();
}
auto CImage::PutImage(int, int, CImage *) -> void
{
MT_PLATFORM_STUB();
}
auto CImage::FlipTopToBottom() -> void
{
MT_PLATFORM_STUB();
}
auto CImage::SetFileName(const char *) -> void
{
MT_PLATFORM_STUB();
}
auto CImage::GetFileNameString() -> const std::string &
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<const std::string &>();
}
auto CImage::IsEmpty() const -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CImage::Initialize() -> void
{
MT_PLATFORM_STUB();
Destroy();
}
+329 -36
View File
@@ -1,72 +1,365 @@
// Platform skeleton for EterImageLib/TGAImage.h (40250 EterImageLib/TGAImage.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterImageLib/TGAImage.cpp, verbatim.
#include "EterImageLib/StdAfx.h"
#include <assert.h>
#include "EterBase/MappedFile.h"
#include "EterImageLib/TGAImage.h"
#include "../PlatformStub.h"
CTGAImage::CTGAImage()
CTGAImage::CTGAImage() : m_dwFlag(0)
{
MT_PLATFORM_STUB();
}
CTGAImage::CTGAImage(CImage &)
{
MT_PLATFORM_STUB();
}
CTGAImage::~CTGAImage()
{
MT_PLATFORM_STUB();
}
auto CTGAImage::Create(int, int) -> void
CTGAImage::CTGAImage(CImage &image) : m_dwFlag(0)
{
MT_PLATFORM_STUB();
int w = image.GetWidth();
int h = image.GetHeight();
Create(w, h);
DWORD * pdwDest = GetBasePointer();
memcpy(pdwDest, image.GetBasePointer(), w * h * sizeof(DWORD));
FlipTopToBottom();
}
auto CTGAImage::LoadFromMemory(int, const BYTE *) -> bool
void CTGAImage::Create(int width, int height)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
memset(&m_Header, 0, sizeof(m_Header));
m_Header.imgType = 2;
m_Header.width = (short) width;
m_Header.height = (short) height;
m_Header.colorBits = 32;
m_Header.desc = 0x08; // alpha channel 있음
CImage::Create(width, height);
}
auto CTGAImage::LoadFromDiskFile(const char *) -> bool
bool CTGAImage::LoadFromMemory(int iSize, const BYTE * c_pbMem)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
memcpy(&m_Header, c_pbMem, 18);
c_pbMem += 18;
iSize -= 18;
CImage::Create(m_Header.width, m_Header.height);
UINT hxw = m_Header.width * m_Header.height;
BYTE r, g, b, a;
DWORD i;
DWORD * pdwDest = GetBasePointer();
switch (m_Header.imgType)
{
case 3: // 알파만 있는 것 (1bytes per pixel, 거의 안쓰임)
{
for (i = 0; i < hxw; ++i)
{
a = (char) *(c_pbMem++);
pdwDest[i] = (a << 24) | (a << 16) | (a << 8) | a;
}
}
break;
case 2: // 압축 안된 TGA
{
if (m_Header.colorBits == 16) // 16bit
{
for (i = 0; i < hxw; ++i)
{
WORD w;
memcpy(&w, c_pbMem, sizeof(WORD));
c_pbMem += sizeof(WORD);
iSize -= sizeof(WORD);
b = (BYTE) (w & 0x1F);
g = (BYTE) ((w >> 5) & 0x1F);
r = (BYTE) ((w >> 10) & 0x1F);
b <<= 3;
g <<= 3;
r <<= 3;
a = 0xff;
pdwDest[i] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
else if (m_Header.colorBits == 24) // 24bit
{
for (i = 0; i < hxw; ++i)
{
r = (BYTE) *(c_pbMem++); --iSize;
g = (BYTE) *(c_pbMem++); --iSize;
b = (BYTE) *(c_pbMem++); --iSize;
a = 0xff;
pdwDest[i] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
else if (m_Header.colorBits == 32) // 32bit
{
int size = GetWidth();
size *= GetHeight() * 4;
memcpy(pdwDest, c_pbMem, size);
c_pbMem += size;
iSize -= size;
}
}
break;
case 10: // 압축 된 TGA (RLE)
{
BYTE rle;
if (m_Header.colorBits == 24)
{
i = 0;
while (i < hxw)
{
rle = (BYTE) *(c_pbMem++); --iSize;
if (rle < 0x80) // 압축 안된 곳
{
rle++;
while (rle)
{
b = (BYTE) *(c_pbMem++); --iSize;
g = (BYTE) *(c_pbMem++); --iSize;
r = (BYTE) *(c_pbMem++); --iSize;
a = 0xff;
pdwDest[i++] = (a << 24) | (r << 16) | (g << 8) | b;
if (i > hxw)
{
assert(!"RLE overflow");
printf("RLE overflow");
return false;
}
--rle;
}
}
else
{
// 압축 된 곳
rle -= 127;
b = (BYTE) *(c_pbMem++); --iSize;
g = (BYTE) *(c_pbMem++); --iSize;
r = (BYTE) *(c_pbMem++); --iSize;
a = 0xff;
while (rle)
{
pdwDest[i++] = (a << 24) | (r << 16) | (g << 8) | b;
if (i > hxw)
{
assert(!"RLE overflow");
printf("RLE overflow");
return false;
}
--rle;
}
}
}
}
else if (m_Header.colorBits == 32)
{
i = 0;
while (i < hxw)
{
rle = (BYTE) *(c_pbMem++); --iSize;
if (rle < 0x80)
{
rle++;
while (rle)
{
b = (BYTE) *(c_pbMem++); --iSize;
g = (BYTE) *(c_pbMem++); --iSize;
r = (BYTE) *(c_pbMem++); --iSize;
a = (BYTE) *(c_pbMem++); --iSize;
pdwDest[i++] = (a << 24) | (r << 16) | (g << 8) | b;
if (i > hxw)
{
assert(!"RLE overflow");
printf("RLE overflow");
return false;
}
--rle;
}
}
else
{
rle -= 127;
b = (BYTE) *(c_pbMem++); --iSize;
g = (BYTE) *(c_pbMem++); --iSize;
r = (BYTE) *(c_pbMem++); --iSize;
a = (BYTE) *(c_pbMem++); --iSize;
while (rle)
{
pdwDest[i++] = (a << 24) | (r << 16) | (g << 8) | b;
if (i > hxw)
{
assert(!"RLE overflow");
printf("RLE overflow");
return false;
}
--rle;
}
}
}
}
}
break;
}
if (!(m_Header.desc & 0x20))
{
FlipTopToBottom();
}
return true;
}
auto CTGAImage::SaveToDiskFile(const char *) -> bool
bool CTGAImage::LoadFromDiskFile(const char * c_szFileName)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
CMappedFile file;
const BYTE * c_pbMap;
if (!file.Create(c_szFileName, (const void **) &c_pbMap, 0, 0))
return false;
return LoadFromMemory(file.Size(), c_pbMap);
}
auto CTGAImage::SetCompressed(bool) -> void
int CTGAImage::GetRLEPixelCount(const DWORD * data)
{
MT_PLATFORM_STUB();
int r = 0;
DWORD pixel;
r = 1;
if (data >= m_pdwEndPtr)
return 0;
pixel = *data;
while ((r < 127) && (data < m_pdwEndPtr))
{
if (pixel != *(++data))
return r;
r++;
}
return r;
}
auto CTGAImage::SetAlphaChannel(bool) -> void
int CTGAImage::GetRawPixelCount(const DWORD * data)
{
MT_PLATFORM_STUB();
int i = 0;
if (data >= m_pdwEndPtr)
return 0;
while ((data < m_pdwEndPtr) && (i < 127))
{
int rle = GetRLEPixelCount(data);
if (rle >= 4)
break;
data++;
i++;
}
return i;
}
auto CTGAImage::GetHeader() -> TGA_HEADER &
void CTGAImage::SetCompressed(bool isCompress)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<TGA_HEADER &>();
if (isCompress)
m_Header.imgType = 10;
else
m_Header.imgType = 2;
}
auto CTGAImage::GetRawPixelCount(const DWORD *) -> int
void CTGAImage::SetAlphaChannel(bool isExist)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
if (isExist)
m_Header.desc |= 0x08;
else
m_Header.desc &= ~0x08;
}
auto CTGAImage::GetRLEPixelCount(const DWORD *) -> int
bool CTGAImage::SaveToDiskFile(const char* c_szFileName)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
FILE * fp = fopen(c_szFileName, "wb");
if (!fp)
return false;
fwrite(&m_Header, 18, 1, fp);
if (m_Header.imgType == 10) // RLE 압축으로 저장
{
DWORD * data = GetBasePointer();
while (data < m_pdwEndPtr)
{
int rle = GetRLEPixelCount(data);
if (rle < 4)
{
int raw = GetRawPixelCount(data);
if (raw == 0)
break;
fputc(raw - 1, fp);
while (raw)
{
fwrite(data, sizeof(DWORD), 1, fp);
data++;
raw--;
}
}
else
{
fputc((rle - 1) | 0x80, fp);
fwrite(data, sizeof(DWORD), 1, fp);
data += rle;
}
}
}
else
{
int size = GetWidth();
size *= GetHeight() * 4;
fwrite(GetBasePointer(), size, 1, fp);
}
fclose(fp);
return true;
}
TGA_HEADER & CTGAImage::GetHeader()
{
return m_Header;
}
+6
View File
@@ -43,6 +43,9 @@ endif()
set(MT_PORT_WARNING_FLAGS)
if(NOT MSVC)
set(MT_PORT_WARNING_FLAGS -Wno-unknown-pragmas -Wno-format-security)
# MSVC does no type-based alias analysis and 40250 relies on it (DXTCImage reads a Color8888 through a
# DWORD*; clang -O2 then loads the colour before it is written).
list(APPEND MT_PORT_WARNING_FLAGS -fno-strict-aliasing)
endif()
target_compile_options(port_logic PUBLIC ${MT_PORT_WARNING_FLAGS})
# 40250 headers keep `#pragma comment(lib, "d3d8.lib")` etc. verbatim; clang turns them into ELF
@@ -208,6 +211,9 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
add_executable(port_input_test ${PROJECT_SOURCE_DIR}/tests/port/port_input_test.cpp)
target_link_libraries(port_input_test PRIVATE port_platform)
add_test(NAME port.input COMMAND $<TARGET_FILE:port_input_test>)
add_executable(port_eter_image_test ${PROJECT_SOURCE_DIR}/tests/port/port_eter_image_test.cpp)
target_link_libraries(port_eter_image_test PRIVATE port_platform)
add_test(NAME port.eter_image COMMAND $<TARGET_FILE:port_eter_image_test>)
# MilesLib: the 40250 sound managers over the Miles emulation (platform/MilesLib/MilesAil.cpp).
add_executable(port_miles_test ${PROJECT_SOURCE_DIR}/tests/port/port_miles_test.cpp)
+122
View File
@@ -0,0 +1,122 @@
#pragma once
// Shim for the DirectX 7 <d3d.h> on non-Windows targets: the <ddraw.h> surface description 40250
// EterImageLib/DXTCImage.cpp copies straight out of a .dds file (the 124 bytes after the "DDS " magic).
//
// PORT: lpSurface is a pointer in <ddraw.h>, 4 bytes in the 32-bit client; it is a DWORD here so the
// structure keeps the on-disk layout on 64-bit targets.
#include "../win32/windows.h"
#define DDSD_CAPS 0x00000001l
#define DDSD_HEIGHT 0x00000002l
#define DDSD_WIDTH 0x00000004l
#define DDSD_PITCH 0x00000008l
#define DDSD_PIXELFORMAT 0x00001000l
#define DDSD_MIPMAPCOUNT 0x00020000l
#define DDSD_LINEARSIZE 0x00080000l
#define DDPF_ALPHAPIXELS 0x00000001l
#define DDPF_FOURCC 0x00000004l
#define DDPF_RGB 0x00000040l
#define DDPF_ALPHAPREMULT 0x00008000l
typedef struct _DDCOLORKEY
{
DWORD dwColorSpaceLowValue;
DWORD dwColorSpaceHighValue;
} DDCOLORKEY;
typedef struct _DDPIXELFORMAT
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwFourCC;
union
{
DWORD dwRGBBitCount;
DWORD dwYUVBitCount;
DWORD dwZBufferBitDepth;
DWORD dwAlphaBitDepth;
DWORD dwLuminanceBitCount;
DWORD dwBumpBitCount;
DWORD dwPrivateFormatBitCount;
};
union
{
DWORD dwRBitMask;
DWORD dwYBitMask;
DWORD dwStencilBitDepth;
DWORD dwLuminanceBitMask;
DWORD dwBumpDuBitMask;
DWORD dwOperations;
};
union
{
DWORD dwGBitMask;
DWORD dwUBitMask;
DWORD dwZBitMask;
DWORD dwBumpDvBitMask;
};
union
{
DWORD dwBBitMask;
DWORD dwVBitMask;
DWORD dwStencilBitMask;
DWORD dwBumpLuminanceBitMask;
};
union
{
DWORD dwRGBAlphaBitMask;
DWORD dwYUVAlphaBitMask;
DWORD dwLuminanceAlphaBitMask;
DWORD dwRGBZBitMask;
DWORD dwYUVZBitMask;
};
} DDPIXELFORMAT;
typedef struct _DDSCAPS2
{
DWORD dwCaps;
DWORD dwCaps2;
DWORD dwCaps3;
DWORD dwCaps4;
} DDSCAPS2;
typedef struct _DDSURFACEDESC2
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwHeight;
DWORD dwWidth;
union
{
LONG lPitch;
DWORD dwLinearSize;
};
union
{
DWORD dwBackBufferCount;
DWORD dwDepth;
};
union
{
DWORD dwMipMapCount;
DWORD dwRefreshRate;
DWORD dwSrcVBHandle;
};
DWORD dwAlphaBitDepth;
DWORD dwReserved;
DWORD lpSurface;
union
{
DDCOLORKEY ddckCKDestOverlay;
DWORD dwEmptyFaceColor;
};
DDCOLORKEY ddckCKDestBlt;
DDCOLORKEY ddckCKSrcOverlay;
DDCOLORKEY ddckCKSrcBlt;
DDPIXELFORMAT ddpfPixelFormat;
DDSCAPS2 ddsCaps;
DWORD dwTextureStage;
} DDSURFACEDESC2, *LPDDSURFACEDESC2;
static_assert(sizeof(DDPIXELFORMAT) == 32 && sizeof(DDSURFACEDESC2) == 124, "the .dds header layout");