port: Grp texture/image/buffer units toward 40250 (+ port.grp_resource)

GrpImage/GrpSubImage verbatim; GrpImageTexture DDS path through CDXTCImage
header + low-texture-memory mip bias, CreateDeviceObjects/CreateFromDiskFile
verbatim; GrpTexture::SetTextureStage via STATEMANAGER. Port-map entries for
GrpTexture/Image/SubImage/ImageTexture/IndexBuffer/VertexBuffer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-30 14:15:45 +09:00
co-authored by Claude Opus 5.5
parent 7e385f827b
commit 010e99f070
13 changed files with 1142 additions and 135 deletions
+50 -39
View File
@@ -1,82 +1,93 @@
// Platform skeleton for EterLib/GrpImage.h (40250 EterLib/GrpImage.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterLib/GrpImage.cpp, verbatim.
#include "EterLib/StdAfx.h"
#include "EterLib/GrpImage.h"
#include "../PlatformStub.h"
auto CGraphicImage::Type() -> TType
CGraphicImage::CGraphicImage(const char * c_szFileName, DWORD dwFilter) :
CResource(c_szFileName),
m_dwFilter(dwFilter)
{
static TType type = StringToType("CGraphicImage");
return type;
}
CGraphicImage::CGraphicImage(const char * c_szFileName, DWORD dwFilter) : CResource(c_szFileName), m_dwFilter(dwFilter) // initializers as in 40250
{
m_rect = {0, 0, 0, 0};
m_rect.bottom = m_rect.right = m_rect.top = m_rect.left = 0;
}
CGraphicImage::~CGraphicImage()
{
MT_PLATFORM_STUB();
}
auto CGraphicImage::CreateDeviceObjects() -> bool
bool CGraphicImage::CreateDeviceObjects()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
return m_imageTexture.CreateDeviceObjects();
}
auto CGraphicImage::DestroyDeviceObjects() -> void
void CGraphicImage::DestroyDeviceObjects()
{
MT_PLATFORM_STUB();
m_imageTexture.DestroyDeviceObjects();
}
auto CGraphicImage::GetWidth() const -> int
CGraphicImage::TType CGraphicImage::Type()
{
static TType s_type = StringToType("CGraphicImage");
return s_type;
}
bool CGraphicImage::OnIsType(TType type)
{
if (CGraphicImage::Type() == type)
return true;
return CResource::OnIsType(type);
}
int CGraphicImage::GetWidth() const
{
return m_rect.right - m_rect.left;
}
auto CGraphicImage::GetHeight() const -> int
int CGraphicImage::GetHeight() const
{
return m_rect.bottom - m_rect.top;
}
auto CGraphicImage::GetRectReference() const -> const RECT &
{
return m_rect;
}
auto CGraphicImage::GetTextureReference() const -> const CGraphicTexture &
const CGraphicTexture& CGraphicImage::GetTextureReference() const
{
return m_imageTexture;
}
auto CGraphicImage::GetTexturePointer() -> CGraphicTexture *
CGraphicTexture* CGraphicImage::GetTexturePointer()
{
return &m_imageTexture;
}
auto CGraphicImage::OnLoad(int size, const void *data) -> bool
const RECT& CGraphicImage::GetRectReference() const
{
m_imageTexture.SetFileName(GetFileName());
if (!m_imageTexture.CreateFromMemoryFile(size, data, D3DFMT_UNKNOWN, m_dwFilter)) return false;
m_rect = {0, 0, m_imageTexture.GetWidth(), m_imageTexture.GetHeight()};
return m_rect;
}
bool CGraphicImage::OnLoad(int iSize, const void * c_pvBuf)
{
if (!c_pvBuf)
return false;
m_imageTexture.SetFileName(CResource::GetFileName());
// 특정 컴퓨터에서 Unknown으로 '안'하면 튕기는 현상이 있음-_-; -비엽
if (!m_imageTexture.CreateFromMemoryFile(iSize, c_pvBuf, D3DFMT_UNKNOWN, m_dwFilter))
return false;
m_rect.left = 0;
m_rect.top = 0;
m_rect.right = m_imageTexture.GetWidth();
m_rect.bottom = m_imageTexture.GetHeight();
return true;
}
auto CGraphicImage::OnClear() -> void
void CGraphicImage::OnClear()
{
// Tracef("Image Destroy : %s\n", m_pszFileName);
m_imageTexture.Destroy();
m_rect = {0, 0, 0, 0};
memset(&m_rect, 0, sizeof(m_rect));
}
auto CGraphicImage::OnIsEmpty() const -> bool
bool CGraphicImage::OnIsEmpty() const
{
return m_imageTexture.IsEmpty();
}
auto CGraphicImage::OnIsType(TType type) -> bool
{
return type == Type() || CResource::OnIsType(type);
}
+61 -13
View File
@@ -1,9 +1,13 @@
// Platform skeleton for EterLib/GrpImageTexture.h (40250 EterLib/GrpImageTexture.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterLib/GrpImageTexture.cpp. The control flow (pack lookup, the DDS header check, the
// DXT/low-texture-memory mip bias) is 40250's; the D3D8 texture objects become platform handles:
// a memory texture (Create: the font pages, Lock/Unlock) or a file texture that carries the pack path,
// decoded by the canvas and the 3D renderer themselves (D3DXCreateTexture*/LockRect/LoadSurface).
#include "EterLib/StdAfx.h"
#include "EterLib/GrpImageTexture.h"
#include "EterBase/MappedFile.h"
#include "EterPack/EterPackManager.h"
#include "EterImageLib/DXTCImage.h"
#include "../PlatformStub.h"
#include "UIRenderCommands.h"
#include <cstring>
@@ -183,6 +187,7 @@ auto CGraphicImageTexture::Destroy() -> void
auto CGraphicImageTexture::Create(UINT width, UINT height, D3DFORMAT d3dFmt, DWORD dwFilter) -> bool
{
assert(ms_lpd3dDevice != NULL);
Destroy();
m_width = width;
@@ -216,9 +221,13 @@ auto CGraphicImageTexture::CreateDeviceObjects() -> bool
}
else
{
// PORT: file textures are decoded by the canvas from the pack path; only their size is read here
// (CreateFromMemoryFile), so there is no device object to recreate.
return !m_bEmpty;
CMappedFile mappedFile;
LPCVOID c_pvMap;
if (!CEterPackManager::Instance().Get(mappedFile, m_stFileName.c_str(), &c_pvMap))
return false;
return CreateFromMemoryFile(mappedFile.Size(), c_pvMap, m_d3dFmt, m_dwFilter);
}
m_bEmpty = false;
@@ -241,15 +250,31 @@ auto CGraphicImageTexture::CreateFromTexturePointer(const CGraphicTexture *sourc
m_lpd3dTexture = new_file_texture(m_stFileName);
}
auto CGraphicImageTexture::CreateFromDiskFile(const char *, D3DFORMAT, DWORD) -> bool
auto CGraphicImageTexture::CreateFromDiskFile(const char * c_szFileName, D3DFORMAT d3dFmt, DWORD dwFilter) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
Destroy();
SetFileName(c_szFileName);
m_d3dFmt = d3dFmt;
m_dwFilter = dwFilter;
return CreateDeviceObjects();
}
auto CGraphicImageTexture::CreateFromMemoryFile(UINT size, const void *bytes, D3DFORMAT, DWORD) -> bool
{
assert(ms_lpd3dDevice != NULL);
if (!bytes) return false;
static CDXTCImage image;
// PORT: the size check; 40250 reads the 128-byte DDS header (magic + DDSURFACEDESC2) from any buffer.
if (size >= 128 && image.LoadHeaderFromMemory((const BYTE *) bytes)) // DDS인가 확인
{
return (CreateDDSTexture(image, (const BYTE *) bytes));
}
// PORT: D3DXCreateTextureFromFileInMemoryEx — only the image size is read here (the canvas decodes the file).
const auto* data = static_cast<const unsigned char*>(bytes);
unsigned width = 0, height = 0;
if (size >= 20 && std::memcmp(data, "DDS ", 4) == 0) {
@@ -272,15 +297,38 @@ auto CGraphicImageTexture::CreateFromMemoryFile(UINT size, const void *bytes, D3
return true;
}
auto CGraphicImageTexture::CreateDDSTexture(CDXTCImage &, const BYTE *) -> bool
// PORT: D3DXCreateTexture + LockRect/Copy per level; the renderers decode the .dds from the pack path.
// The size (and the low-texture-memory top-mip skip it implies) is 40250's.
auto CGraphicImageTexture::CreateDDSTexture(CDXTCImage & image, const BYTE * /*c_pbBuf*/) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
int mipmapCount = image.m_dwMipMapCount == 0 ? 1 : image.m_dwMipMapCount;
UINT uTexBias=0;
if (IsLowTextureMemory())
uTexBias=1;
if (uTexBias>0)
{
if (mipmapCount>uTexBias)
{
image.m_nWidth>>=uTexBias;
image.m_nHeight>>=uTexBias;
}
}
DestroyDeviceObjects();
m_lpd3dTexture = new_file_texture(m_stFileName);
m_width = image.m_nWidth;
m_height = image.m_nHeight;
m_bEmpty = false;
return true;
}
auto CGraphicImageTexture::SetFileName(const char *name) -> void
{
m_stFileName = name ? name : "";
m_stFileName=name;
}
// PORT: where 40250 binds pTexture->GetD3DTexture(), the canvas gets the pack path of the file the
+115 -58
View File
@@ -1,100 +1,157 @@
// 40250 EterLib/GrpSubImage.cpp, verbatim.
#include "EterLib/StdAfx.h"
#include "EterBase/Stl.h"
#include "EterBase/FileLoader.h"
#include "EterLib/GrpSubImage.h"
#include "EterLib/ResourceManager.h"
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <map>
#include <sstream>
#include <string>
char CGraphicSubImage::m_SearchPath[256] = "D:/Ymir Work/UI/";
auto CGraphicSubImage::Type() -> TType
CGraphicSubImage::TType CGraphicSubImage::Type()
{
static TType type = StringToType("CGraphicSubImage");
return type;
static TType s_type = StringToType("CGraphicSubImage");
return s_type;
}
CGraphicSubImage::CGraphicSubImage(const char* name) : CGraphicImage(name) {}
CGraphicSubImage::~CGraphicSubImage() { m_roImage.Clear(); }
CGraphicSubImage::CGraphicSubImage(const char* c_szFileName) : CGraphicImage(c_szFileName)
{
}
CGraphicSubImage::~CGraphicSubImage()
{
m_roImage = NULL;
}
bool CGraphicSubImage::CreateDeviceObjects()
{
if (m_roImage.IsNull()) return false;
m_imageTexture.CreateFromTexturePointer(m_roImage->GetTexturePointer());
return true;
}
void CGraphicSubImage::SetImagePointer(CGraphicImage* image)
void CGraphicSubImage::SetImagePointer(CGraphicImage* pImage)
{
m_roImage.SetPointer(image);
m_roImage = pImage;
CreateDeviceObjects();
}
bool CGraphicSubImage::SetImageFileName(const char* name)
bool CGraphicSubImage::SetImageFileName(const char* c_szFileName)
{
CResource* resource = CResourceManager::Instance().GetResourcePointer(name);
if (!resource || !resource->IsType(CGraphicImage::Type())) return false;
SetImagePointer(static_cast<CGraphicImage*>(resource));
CResource* pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName);
if (!pResource->IsType(CGraphicImage::Type()))
return false;
SetImagePointer(static_cast<CGraphicImage*>(pResource));
return true;
}
void CGraphicSubImage::SetRectPosition(int left, int top, int right, int bottom)
{
m_rect = {left, top, right, bottom};
m_rect.left = left;
m_rect.top = top;
m_rect.right = right;
m_rect.bottom = bottom;
}
void CGraphicSubImage::SetRectReference(const RECT& rect) { m_rect = rect; }
void CGraphicSubImage::SetSearchPath(const char* path)
void CGraphicSubImage::SetRectReference(const RECT& c_rRect)
{
if (!path) return;
std::strncpy(m_SearchPath, path, sizeof(m_SearchPath) - 1);
m_SearchPath[sizeof(m_SearchPath) - 1] = 0;
m_rect = c_rRect;
}
bool CGraphicSubImage::OnLoad(int size, const void* bytes)
void CGraphicSubImage::SetSearchPath(const char * c_szFileName)
{
if (!bytes || size <= 0) return false;
std::istringstream input(std::string(static_cast<const char*>(bytes), static_cast<size_t>(size)));
std::map<std::string, std::string> tokens;
std::string line;
while (std::getline(input, line)) {
std::istringstream fields(line);
std::string key, value;
if (!(fields >> key >> value)) continue;
if (!value.empty() && value.front() == '"') {
value.erase(0, 1);
if (!value.empty() && value.back() == '"') value.pop_back();
strncpy(m_SearchPath, c_szFileName, sizeof(m_SearchPath)-1);
}
bool CGraphicSubImage::OnLoad(int iSize, const void* c_pvBuf)
{
if (!c_pvBuf)
return false;
CTokenVector stTokenVector;
std::map<std::string, std::string> stTokenMap;
CMemoryTextFileLoader textFileLoader;
textFileLoader.Bind(iSize, c_pvBuf);
for (DWORD i = 0; i < textFileLoader.GetLineCount(); ++i)
{
if (!textFileLoader.SplitLine(i, &stTokenVector))
continue;
if (stTokenVector.size() != 2)
return false;
stl_lowers(stTokenVector[0]);
stl_lowers(stTokenVector[1]);
stTokenMap[stTokenVector[0]] = stTokenVector[1];
}
const std::string& c_rstTitle = stTokenMap["title"];
const std::string& c_rstVersion = stTokenMap["version"];
const std::string& c_rstImage = stTokenMap["image"];
const std::string& c_rstLeft = stTokenMap["left"];
const std::string& c_rstTop = stTokenMap["top"];
const std::string& c_rstRight = stTokenMap["right"];
const std::string& c_rstBottom = stTokenMap["bottom"];
if (c_rstTitle != "subimage")
return false;
char szFileName[256];
if ("2.0"==c_rstVersion)
{
const std::string& c_rstSubFileName=GetFileNameString();
int nPos=c_rstSubFileName.find_last_of('\\', -1);
if (nPos>=0)
{
nPos++;
memcpy(szFileName, c_rstSubFileName.c_str(), nPos);
szFileName[nPos]='\0';
memcpy(szFileName+nPos, c_rstImage.c_str(), c_rstImage.length());
szFileName[nPos+c_rstImage.length()]='\0';
}
else
{
memcpy(szFileName, c_rstImage.c_str(), c_rstImage.length());
}
std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c) { return std::tolower(c); });
std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return std::tolower(c); });
tokens[key] = value;
}
if (tokens["title"] != "subimage" || tokens["image"].empty()) return false;
std::string image_path;
if (tokens["version"] == "2.0") {
const std::string parent = GetFileNameString();
const auto slash = parent.find_last_of("\\/");
image_path = slash == std::string::npos ? tokens["image"] : parent.substr(0, slash + 1) + tokens["image"];
} else {
image_path = std::string(m_SearchPath) + tokens["image"];
else
{
_snprintf(szFileName, sizeof(szFileName), "%s%s", m_SearchPath, c_rstImage.c_str());
}
if (!SetImageFileName(image_path.c_str())) return false;
SetRectPosition(std::atoi(tokens["left"].c_str()), std::atoi(tokens["top"].c_str()),
std::atoi(tokens["right"].c_str()), std::atoi(tokens["bottom"].c_str()));
SetImageFileName(szFileName);
SetRectPosition(atoi(c_rstLeft.c_str()),
atoi(c_rstTop.c_str()),
atoi(c_rstRight.c_str()),
atoi(c_rstBottom.c_str()));
return true;
}
void CGraphicSubImage::OnClear()
{
m_roImage.Clear();
m_imageTexture.Destroy();
m_rect = {0, 0, 0, 0};
m_roImage = NULL;
memset(&m_rect, 0, sizeof(m_rect));
}
bool CGraphicSubImage::OnIsEmpty() const { return m_roImage.IsNull() || m_roImage->IsEmpty(); }
bool CGraphicSubImage::OnIsType(TType type) { return type == Type() || CGraphicImage::OnIsType(type); }
bool CGraphicSubImage::OnIsEmpty() const
{
if (!m_roImage.IsNull())
if (!m_roImage->IsEmpty())
return false;
return true;
}
bool CGraphicSubImage::OnIsType(TType type)
{
if (CGraphicSubImage::Type() == type)
return true;
return CGraphicImage::OnIsType(type);
}
+6 -5
View File
@@ -1,9 +1,9 @@
// Platform skeleton for EterLib/GrpTexture.h (40250 EterLib/GrpTexture.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterLib/GrpTexture.cpp. m_lpd3dTexture is a platform texture handle: RecordingDevice resolves
// it by name (UIRenderTextureNameFromHandle), and UIRenderReleaseMemoryTexture frees it.
#include "EterLib/StdAfx.h"
#include "EterLib/GrpTexture.h"
#include "../PlatformStub.h"
#include "EterLib/StateManager.h"
#include "UIRenderCommands.h"
auto CGraphicTexture::IsEmpty() const -> bool
@@ -21,9 +21,10 @@ auto CGraphicTexture::GetHeight() const -> int
return m_height;
}
auto CGraphicTexture::SetTextureStage(int) const -> void
auto CGraphicTexture::SetTextureStage(int stage) const -> void
{
MT_PLATFORM_STUB();
assert(ms_lpd3dDevice != NULL);
STATEMANAGER.SetTexture(stage, m_lpd3dTexture);
}
auto CGraphicTexture::GetD3DTexture() const -> LPDIRECT3DTEXTURE8
+3
View File
@@ -214,6 +214,9 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME)
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>)
add_executable(port_grp_resource_test ${PROJECT_SOURCE_DIR}/tests/port/port_grp_resource_test.cpp)
target_link_libraries(port_grp_resource_test PRIVATE port_platform)
add_test(NAME port.grp_resource COMMAND $<TARGET_FILE:port_grp_resource_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)