2V0-g: port the .fnt font pipeline over a FreeType GDI emulation

CGraphicText, CGraphicFontTexture and CGraphicDib are the 40250 bodies
verbatim; CGraphicTextInstance is verbatim except that its D3D draws become
UI render commands (one image quad per glyph, Bar for cursor/underline).

- platform/Win32Gdi.cpp: the GDI subset those files call, over vendored
  FreeType 2.13.3, following GDI's LOGFONT cell height, win metrics and gasp
  rules; system font lookup with substitute and CJK fallback faces
- Win32Crt: MultiByteToWideChar / WideCharToMultiByte (UTF-8 and 1252 by
  hand, other code pages through iconv)
- CGraphicImageTexture memory textures: glyph pages reach Godot as
  "mem:<id>@<revision>"; Metin2PythonHost.memory_texture + Canvas cache
- Util.cpp code page / font face table, SetDefaultCodePage at boot,
  DefaultFont_* block, fnt resource type, GetMaxTextureWidth/Height
- TextTag, StringCodec, Arabic, Vietnamese copied from 40250
- tests: port.text (Tahoma 12 metrics, alignment, CP949), port.app_loop
  and python_host_test.gd now check glyph quads instead of text commands

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-23 14:17:25 +09:00
co-authored by Claude Opus 5.5
parent 141206cb69
commit afe63bfa61
272 changed files with 137097 additions and 316 deletions
+76 -32
View File
@@ -1,71 +1,115 @@
// Platform skeleton for EterLib/GrpDIB.h (40250 EterLib/GrpDIB.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterLib/GrpDIB.cpp, verbatim. The GDI calls are the FreeType-backed platform/Win32Gdi.cpp.
#include "EterLib/StdAfx.h"
#include "EterLib/GrpDIB.h"
#include "../PlatformStub.h"
CGraphicDib::CGraphicDib()
{
MT_PLATFORM_STUB();
Initialize();
}
CGraphicDib::~CGraphicDib()
{
MT_PLATFORM_STUB();
Destroy();
}
auto CGraphicDib::Destroy() -> void
void CGraphicDib::Initialize()
{
MT_PLATFORM_STUB();
m_hDC=NULL;
m_hBmp=NULL;
m_pvBuf=NULL;
m_width=0;
m_height=0;
}
auto CGraphicDib::Create(HDC, int, int) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
void CGraphicDib::Destroy()
{
if (m_hBmp) DeleteObject(m_hBmp);
if (m_hDC) DeleteDC(m_hDC);
Initialize();
}
auto CGraphicDib::SetBkMode(int) -> void
bool CGraphicDib::Create(HDC hDC, int width, int height)
{
MT_PLATFORM_STUB();
Destroy();
m_width = width;
m_height = height;
ZeroMemory(&m_bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bmi.bmiHeader.biWidth = m_width;
m_bmi.bmiHeader.biHeight = -m_height;
m_bmi.bmiHeader.biPlanes = 1;
m_bmi.bmiHeader.biBitCount = 32;
m_bmi.bmiHeader.biCompression = BI_RGB;
m_hDC=CreateCompatibleDC(hDC);
if (!m_hDC)
{
assert(!"CGraphicDib::Create CreateCompatibleDC Error");
return false;
}
m_hBmp=CreateDIBSection(m_hDC, &m_bmi, DIB_RGB_COLORS, &m_pvBuf, NULL, 0);
if (!m_hBmp)
{
assert(!"CGraphicDib::Create CreateDIBSection Error");
return false;
}
SelectObject(m_hDC, m_hBmp);
::SetTextColor(m_hDC, RGB(255, 255, 255));
return true;
}
auto CGraphicDib::TextOut(int, int, const char *) -> void
HDC CGraphicDib::GetDCHandle()
{
MT_PLATFORM_STUB();
return m_hDC;
}
auto CGraphicDib::Put(HDC, int, int) -> void
void CGraphicDib::SetBkMode(int iBkMode)
{
MT_PLATFORM_STUB();
::SetBkMode(m_hDC, iBkMode);
}
auto CGraphicDib::GetWidth() -> int
void CGraphicDib::TextOut(int ix, int iy, const char * c_szText)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
::SetBkColor(m_hDC, 0);
::TextOut(m_hDC, ix, iy, c_szText, strlen(c_szText));
}
auto CGraphicDib::GetHeight() -> int
void CGraphicDib::Put(HDC hDC, int x, int y)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
SetDIBitsToDevice(
hDC,
x,
y,
m_width,
m_height,
0,
0,
0,
m_height,
m_pvBuf,
&m_bmi,
DIB_RGB_COLORS
);
}
auto CGraphicDib::GetPointer() -> void *
void* CGraphicDib::GetPointer()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<void *>();
return m_pvBuf;
}
auto CGraphicDib::GetDCHandle() -> HDC
int CGraphicDib::GetWidth()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<HDC>();
return m_width;
}
auto CGraphicDib::Initialize() -> void
int CGraphicDib::GetHeight()
{
MT_PLATFORM_STUB();
return m_height;
}
@@ -146,3 +146,17 @@ auto CGraphicDevice::CreateDoublePNTStreamVertexShader() -> DWORD
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
}
// 40250 GrpDevice.cpp:298-306; s_MaxTextureWidth/Height come from D3DCAPS8 in __CheckD3DCaps.
// PORT: 4096 is the texture size every Godot renderer on the target GPUs supports.
static DWORD s_MaxTextureWidth = 4096, s_MaxTextureHeight = 4096;
DWORD GetMaxTextureWidth()
{
return s_MaxTextureWidth;
}
DWORD GetMaxTextureHeight()
{
return s_MaxTextureHeight;
}
+267 -41
View File
@@ -1,90 +1,316 @@
// Platform skeleton for EterLib/GrpFontTexture.h (40250 EterLib/GrpFontTexture.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterLib/GrpFontTexture.cpp, verbatim over the GDI emulation in platform/Win32Gdi.cpp. The
// A4R4G4B4 page textures are CGraphicImageTexture memory textures the Godot canvas samples.
#include "EterLib/StdAfx.h"
#include "EterLib/GrpFontTexture.h"
#include "EterLib/GrpText.h"
#include "EterBase/Stl.h"
#include "../PlatformStub.h"
#include "EterLib/Util.h"
CGraphicFontTexture::CGraphicFontTexture()
{
MT_PLATFORM_STUB();
Initialize();
}
CGraphicFontTexture::~CGraphicFontTexture()
{
MT_PLATFORM_STUB();
Destroy();
}
auto CGraphicFontTexture::Destroy() -> void
void CGraphicFontTexture::Initialize()
{
MT_PLATFORM_STUB();
CGraphicTexture::Initialize();
m_hFontOld = NULL;
m_hFont = NULL;
m_isDirty = false;
m_bItalic = false;
}
auto CGraphicFontTexture::Create(const char *, int, bool) -> bool
bool CGraphicFontTexture::IsEmpty() const
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
return m_fontMap.size() == 0;
}
auto CGraphicFontTexture::CreateDeviceObjects() -> bool
void CGraphicFontTexture::Destroy()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
HDC hDC = m_dib.GetDCHandle();
if (hDC)
SelectObject(hDC, m_hFontOld);
m_dib.Destroy();
m_lpd3dTexture = NULL;
CGraphicTexture::Destroy();
stl_wipe(m_pFontTextureVector);
m_charInfoMap.clear();
if (m_fontMap.size())
{
TFontMap::iterator i = m_fontMap.begin();
while(i != m_fontMap.end())
{
DeleteObject((HGDIOBJ)i->second);
++i;
}
m_fontMap.clear();
}
Initialize();
}
auto CGraphicFontTexture::DestroyDeviceObjects() -> void
bool CGraphicFontTexture::CreateDeviceObjects()
{
MT_PLATFORM_STUB();
return true;
}
auto CGraphicFontTexture::CheckTextureIndex(DWORD) -> bool
void CGraphicFontTexture::DestroyDeviceObjects()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CGraphicFontTexture::SelectTexture(DWORD) -> void
bool CGraphicFontTexture::Create(const char* c_szFontName, int fontSize, bool bItalic)
{
MT_PLATFORM_STUB();
Destroy();
strncpy(m_fontName, c_szFontName, sizeof(m_fontName)-1);
m_fontSize = fontSize;
m_bItalic = bItalic;
m_x = 0;
m_y = 0;
m_step = 0;
DWORD width = 256,height = 256;
if (GetMaxTextureWidth() > 512)
width = 512;
if (GetMaxTextureHeight() > 512)
height = 512;
if (!m_dib.Create(ms_hDC, width, height))
return false;
HDC hDC = m_dib.GetDCHandle();
m_hFont = GetFont(GetDefaultCodePage());
m_hFontOld=(HFONT)SelectObject(hDC, m_hFont);
SetTextColor(hDC, RGB(255, 255, 255));
SetBkColor(hDC, 0);
if (!AppendTexture())
return false;
return true;
}
auto CGraphicFontTexture::UpdateTexture() -> bool
HFONT CGraphicFontTexture::GetFont(WORD codePage)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
HFONT hFont = NULL;
TFontMap::iterator i = m_fontMap.find(codePage);
if(i != m_fontMap.end())
{
hFont = i->second;
}
else
{
LOGFONT logFont;
memset(&logFont, 0, sizeof(LOGFONT));
logFont.lfHeight = m_fontSize;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = (BYTE) m_bItalic;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = GetCharsetFromCodePage(codePage);
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = ANTIALIASED_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
//Tracenf("font: %s", GetFontFaceFromCodePage(codePage));
strcpy(logFont.lfFaceName, m_fontName); //GetFontFaceFromCodePage(codePage));
//strcpy(logFont.lfFaceName, GetFontFaceFromCodePage(codePage));
hFont = CreateFontIndirect(&logFont);
m_fontMap.insert(TFontMap::value_type(codePage, hFont));
}
return hFont;
}
auto CGraphicFontTexture::GetCharacterInfomation(WORD, wchar_t) -> TCharacterInfomation *
bool CGraphicFontTexture::AppendTexture()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<TCharacterInfomation *>();
CGraphicImageTexture * pNewTexture = new CGraphicImageTexture;
if (!pNewTexture->Create(m_dib.GetWidth(), m_dib.GetHeight(), D3DFMT_A4R4G4B4))
{
delete pNewTexture;
return false;
}
m_pFontTextureVector.push_back(pNewTexture);
return true;
}
auto CGraphicFontTexture::UpdateCharacterInfomation(TCharacterKey) -> TCharacterInfomation *
bool CGraphicFontTexture::UpdateTexture()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<TCharacterInfomation *>();
if(!m_isDirty)
return true;
m_isDirty = false;
CGraphicImageTexture * pFontTexture = m_pFontTextureVector.back();
if (!pFontTexture)
return false;
WORD* pwDst;
int pitch;
if (!pFontTexture->Lock(&pitch, (void**)&pwDst))
return false;
pitch /= 2;
int width = m_dib.GetWidth();
int height = m_dib.GetHeight();
DWORD * pdwSrc = (DWORD*)m_dib.GetPointer();
for (int y = 0; y < height; ++y, pwDst += pitch, pdwSrc += width)
for (int x = 0; x < width; ++x)
pwDst[x]=pdwSrc[x];
pFontTexture->Unlock();
return true;
}
auto CGraphicFontTexture::IsEmpty() const -> bool
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::GetCharacterInfomation(WORD codePage, wchar_t keyValue)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
TCharacterKey code(codePage, keyValue);
TCharacterInfomationMap::iterator f = m_charInfoMap.find(code);
if (m_charInfoMap.end() == f)
{
return UpdateCharacterInfomation(code);
}
else
{
return &f->second;
}
}
auto CGraphicFontTexture::Initialize() -> void
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterInfomation(TCharacterKey code)
{
MT_PLATFORM_STUB();
HDC hDC = m_dib.GetDCHandle();
SelectObject(hDC, GetFont(code.first));
wchar_t keyValue = code.second;
if (keyValue == 0x08)
keyValue = L' '; // 탭은 공백으로 바꾼다 (아랍 출력시 탭 사용: NAME:\tTEXT -> TEXT\t:NAME 로 전환됨 )
ABCFLOAT stABC;
SIZE size;
if (!GetTextExtentPoint32W(hDC, &keyValue, 1, &size) || !GetCharABCWidthsFloatW(hDC, keyValue, keyValue, &stABC))
return NULL;
size.cx = stABC.abcfB;
if( stABC.abcfA > 0.0f )
size.cx += ceilf(stABC.abcfA);
if( stABC.abcfC > 0.0f )
size.cx += ceilf(stABC.abcfC);
size.cx++;
LONG lAdvance = ceilf( stABC.abcfA + stABC.abcfB + stABC.abcfC );
int width = m_dib.GetWidth();
int height = m_dib.GetHeight();
if (m_x + size.cx >= (width - 1))
{
m_y += (m_step + 1);
m_step = 0;
m_x = 0;
if (m_y + size.cy >= (height - 1))
{
if (!UpdateTexture())
{
return NULL;
}
if (!AppendTexture())
return NULL;
m_y = 0;
}
}
TextOutW(hDC, m_x, m_y, &keyValue, 1);
int nChrX;
int nChrY;
int nChrWidth = size.cx;
int nChrHeight = size.cy;
int nDIBWidth = m_dib.GetWidth();
DWORD*pdwDIBData=(DWORD*)m_dib.GetPointer();
DWORD*pdwDIBBase=pdwDIBData+nDIBWidth*m_y+m_x;
DWORD*pdwDIBRow;
pdwDIBRow=pdwDIBBase;
for (nChrY=0; nChrY<nChrHeight; ++nChrY, pdwDIBRow+=nDIBWidth)
{
for (nChrX=0; nChrX<nChrWidth; ++nChrX)
{
pdwDIBRow[nChrX]=(pdwDIBRow[nChrX]&0xff) ? 0xffff : 0;
}
}
float rhwidth = 1.0f / float(width);
float rhheight = 1.0f / float(height);
TCharacterInfomation& rNewCharInfo = m_charInfoMap[code];
rNewCharInfo.index = static_cast<short>(m_pFontTextureVector.size() - 1);
rNewCharInfo.width = size.cx;
rNewCharInfo.height = size.cy;
rNewCharInfo.left = float(m_x) * rhwidth;
rNewCharInfo.top = float(m_y) * rhheight;
rNewCharInfo.right = float(m_x+size.cx) * rhwidth;
rNewCharInfo.bottom = float(m_y+size.cy) * rhheight;
rNewCharInfo.advance = (float) lAdvance;
m_x += size.cx;
if (m_step < size.cy)
m_step = size.cy;
m_isDirty = true;
return &rNewCharInfo;
}
auto CGraphicFontTexture::AppendTexture() -> bool
bool CGraphicFontTexture::CheckTextureIndex(DWORD dwTexture)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
if (dwTexture >= m_pFontTextureVector.size())
return false;
return true;
}
auto CGraphicFontTexture::GetFont(WORD) -> HFONT
void CGraphicFontTexture::SelectTexture(DWORD dwTexture)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<HFONT>();
assert(CheckTextureIndex(dwTexture));
m_lpd3dTexture = m_pFontTextureVector[dwTexture]->GetD3DTexture();
}
@@ -4,7 +4,11 @@
#include "EterLib/GrpImageTexture.h"
#include "../PlatformStub.h"
#include "UIRenderCommands.h"
#include <cstring>
#include <map>
#include <mutex>
namespace {
unsigned little16(const unsigned char* data) { return data[0] | (unsigned(data[1]) << 8); }
@@ -36,33 +40,150 @@ bool jpeg_size(const unsigned char* data, unsigned size, unsigned* width, unsign
}
return false;
}
// PORT: the IDirect3DTexture8 behind a CGraphicImageTexture::Create texture. Lock hands out the
// pixels in the texture's own format (40250 writes A4R4G4B4 words into the font pages); Unlock
// converts them to ARGB32 for the canvas and bumps the revision in the texture's name.
struct MemoryTexture : IDirect3DTexture8
{
unsigned id = 0;
int width = 0;
int height = 0;
D3DFORMAT format = D3DFMT_UNKNOWN;
std::vector<unsigned char> native;
std::vector<std::uint32_t> argb;
std::uint32_t revision = 0;
};
std::mutex g_memory_mutex;
std::map<unsigned, MemoryTexture*> g_memory;
unsigned g_memory_next_id = 1;
int bytes_per_pixel(D3DFORMAT format)
{
switch (format) {
case D3DFMT_A4R4G4B4: case D3DFMT_R5G6B5: case D3DFMT_A1R5G5B5: case D3DFMT_X1R5G5B5: case D3DFMT_X4R4G4B4:
return 2;
default:
return 4;
}
}
std::uint32_t expand(unsigned value, int bits)
{
return bits == 4 ? value * 0x11 : bits == 5 ? (value << 3) | (value >> 2) : bits == 6 ? (value << 2) | (value >> 4) : value;
}
std::uint32_t native_to_argb(D3DFORMAT format, const unsigned char* p)
{
const unsigned w = p[0] | (unsigned(p[1]) << 8);
switch (format) {
case D3DFMT_A4R4G4B4:
return (expand(w >> 12, 4) << 24) | (expand((w >> 8) & 15, 4) << 16) | (expand((w >> 4) & 15, 4) << 8) | expand(w & 15, 4);
case D3DFMT_X4R4G4B4:
return 0xFF000000u | (expand((w >> 8) & 15, 4) << 16) | (expand((w >> 4) & 15, 4) << 8) | expand(w & 15, 4);
case D3DFMT_R5G6B5:
return 0xFF000000u | (expand(w >> 11, 5) << 16) | (expand((w >> 5) & 63, 6) << 8) | expand(w & 31, 5);
case D3DFMT_A1R5G5B5: case D3DFMT_X1R5G5B5:
return ((format == D3DFMT_X1R5G5B5 || (w & 0x8000)) ? 0xFF000000u : 0) | (expand((w >> 10) & 31, 5) << 16) |
(expand((w >> 5) & 31, 5) << 8) | expand(w & 31, 5);
case D3DFMT_X8R8G8B8:
return 0xFF000000u | (p[2] << 16) | (p[1] << 8) | p[0];
default:
return (std::uint32_t(p[3]) << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
}
}
MemoryTexture* live_memory_texture(const IDirect3DTexture8* texture)
{
for (const auto& entry : g_memory)
if (entry.second == texture) return entry.second;
return nullptr;
}
}
void UIRenderReleaseMemoryTexture(IDirect3DTexture8* texture)
{
std::lock_guard<std::mutex> lock(g_memory_mutex);
if (MemoryTexture* memory = live_memory_texture(texture)) {
g_memory.erase(memory->id);
delete memory;
}
}
bool UIRenderMemoryTexture(const std::string& name, UIMemoryTexture* out)
{
if (name.compare(0, 4, "mem:") != 0 || !out) return false;
const unsigned id = unsigned(std::strtoul(name.c_str() + 4, nullptr, 10));
std::lock_guard<std::mutex> lock(g_memory_mutex);
auto it = g_memory.find(id);
if (it == g_memory.end()) return false;
out->width = it->second->width;
out->height = it->second->height;
out->revision = it->second->revision;
out->argb = it->second->argb;
return true;
}
CGraphicImageTexture::CGraphicImageTexture()
{
MT_PLATFORM_STUB();
Initialize();
}
CGraphicImageTexture::~CGraphicImageTexture()
{
MT_PLATFORM_STUB();
Destroy();
}
auto CGraphicImageTexture::Destroy() -> void
{
CGraphicTexture::Destroy();
Initialize();
}
auto CGraphicImageTexture::Create(UINT, UINT, D3DFORMAT, DWORD) -> bool
auto CGraphicImageTexture::Create(UINT width, UINT height, D3DFORMAT d3dFmt, DWORD dwFilter) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
Destroy();
m_width = width;
m_height = height;
m_d3dFmt = d3dFmt;
m_dwFilter = dwFilter;
return CreateDeviceObjects();
}
auto CGraphicImageTexture::CreateDeviceObjects() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
if (m_stFileName.empty())
{
// PORT: ms_lpd3dDevice->CreateTexture(m_width, m_height, 1, 0, m_d3dFmt, D3DPOOL_MANAGED) becomes a
// memory texture the canvas fetches by name.
if (m_width <= 0 || m_height <= 0)
return false;
auto* memory = new MemoryTexture();
memory->width = m_width;
memory->height = m_height;
memory->format = m_d3dFmt;
memory->native.assign(size_t(m_width) * size_t(m_height) * size_t(bytes_per_pixel(m_d3dFmt)), 0);
memory->argb.assign(size_t(m_width) * size_t(m_height), 0);
{
std::lock_guard<std::mutex> lock(g_memory_mutex);
memory->id = g_memory_next_id++;
g_memory[memory->id] = memory;
}
m_lpd3dTexture = memory;
}
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;
}
m_bEmpty = false;
return true;
}
auto CGraphicImageTexture::CreateFromTexturePointer(const CGraphicTexture *source) -> void
@@ -117,9 +238,16 @@ auto CGraphicImageTexture::SetFileName(const char *name) -> void
}
// PORT: where 40250 binds pTexture->GetD3DTexture(), the canvas gets the pack path of the file the
// texture was decoded from (m_stFileName is protected, hence the derived accessor).
// texture was decoded from (m_stFileName is protected, hence the derived accessor), or the name of the
// memory texture bound to it (a CGraphicFontTexture after SelectTexture).
std::string UIRenderTextureName(const CGraphicTexture* texture)
{
if (!texture) return {};
if (texture->GetD3DTexture()) {
std::lock_guard<std::mutex> lock(g_memory_mutex);
if (const MemoryTexture* memory = live_memory_texture(texture->GetD3DTexture()))
return "mem:" + std::to_string(memory->id) + "@" + std::to_string(memory->revision);
}
struct Access : CGraphicImageTexture {
static const std::string& name(const CGraphicImageTexture* t) { return t->*(&Access::m_stFileName); }
};
@@ -127,18 +255,38 @@ std::string UIRenderTextureName(const CGraphicTexture* texture)
return image ? Access::name(image) : std::string();
}
auto CGraphicImageTexture::Lock(int *, void **, int) -> bool
// PORT: LockRect/UnlockRect on the memory texture (one level; the lock is on the whole surface).
auto CGraphicImageTexture::Lock(int* pRetPitch, void** ppRetPixels, int) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
std::lock_guard<std::mutex> lock(g_memory_mutex);
MemoryTexture* memory = live_memory_texture(m_lpd3dTexture);
if (!memory)
return false;
*pRetPitch = memory->width * bytes_per_pixel(memory->format);
*ppRetPixels = memory->native.data();
return true;
}
auto CGraphicImageTexture::Unlock(int) -> void
{
MT_PLATFORM_STUB();
std::lock_guard<std::mutex> lock(g_memory_mutex);
MemoryTexture* memory = live_memory_texture(m_lpd3dTexture);
assert(memory != NULL);
if (!memory)
return;
const int bpp = bytes_per_pixel(memory->format);
for (size_t i = 0; i < memory->argb.size(); ++i)
memory->argb[i] = native_to_argb(memory->format, memory->native.data() + i * size_t(bpp));
++memory->revision;
}
auto CGraphicImageTexture::Initialize() -> void
{
MT_PLATFORM_STUB();
CGraphicTexture::Initialize();
m_stFileName = "";
m_d3dFmt=D3DFMT_UNKNOWN;
m_dwFilter=0;
}
+72 -32
View File
@@ -1,62 +1,102 @@
// Platform skeleton for EterLib/GrpText.h (40250 EterLib/GrpText.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterLib/GrpText.cpp, verbatim.
#include "EterLib/StdAfx.h"
#include "EterBase/Utils.h"
#include "EterLib/GrpText.h"
#include "../PlatformStub.h"
auto CGraphicText::Type() -> TType
CGraphicText::CGraphicText(const char* c_szFileName) : CResource(c_szFileName)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<TType>();
}
CGraphicText::CGraphicText(const char * c_szFileName) : CResource(c_szFileName) // initializers as in 40250
{
MT_PLATFORM_STUB();
}
CGraphicText::~CGraphicText()
{
MT_PLATFORM_STUB();
}
auto CGraphicText::CreateDeviceObjects() -> bool
bool CGraphicText::CreateDeviceObjects()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
return m_fontTexture.CreateDeviceObjects();
}
auto CGraphicText::DestroyDeviceObjects() -> void
void CGraphicText::DestroyDeviceObjects()
{
MT_PLATFORM_STUB();
m_fontTexture.DestroyDeviceObjects();
}
auto CGraphicText::GetFontTexturePointer() -> CGraphicFontTexture *
CGraphicFontTexture* CGraphicText::GetFontTexturePointer()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<CGraphicFontTexture *>();
return &m_fontTexture;
}
auto CGraphicText::OnLoad(int, const void *) -> bool
CGraphicText::TType CGraphicText::Type()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
static TType s_type = StringToType("CGraphicText");
return s_type;
}
auto CGraphicText::OnClear() -> void
bool CGraphicText::OnLoad(int /*iSize*/, const void* /*c_pvBuf*/)
{
MT_PLATFORM_STUB();
static char strName[32];
int size;
bool bItalic = false;
// format
// 굴림.fnt "굴림" 폰트 기본 사이즈 12 로 로딩
// 굴림:18.fnt "굴림" 폰트 사이즈 18 로 로딩
// 굴림:14i.fnt "굴림" 폰트 사이즈 14 & 이탤릭으로 로딩
const char * p = strrchr(GetFileName(), ':');
if (p)
{
strncpy(strName, GetFileName(), MIN(31, p - GetFileName()));
++p;
static char num[8];
int i = 0;
while (*p && isdigit(*p))
{
num[i++] = *(p++);
}
num[i] = '\0';
if(*p == 'i')
bItalic = true;
size = atoi(num);
}
else
{
p = strrchr(GetFileName(), '.');
if (!p)
{
assert(!"CGraphicText::OnLoadFromFile there is no extension (ie: .fnt)");
strName[0] = '\0';
}
else
strncpy(strName, GetFileName(), MIN(31, p - GetFileName()));
size = 12;
}
if (!m_fontTexture.Create(strName, size, bItalic))
return false;
return true;
}
auto CGraphicText::OnIsEmpty() const -> bool
void CGraphicText::OnClear()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
m_fontTexture.Destroy();
}
auto CGraphicText::OnIsType(TType) -> bool
bool CGraphicText::OnIsEmpty() const
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
return m_fontTexture.IsEmpty();
}
bool CGraphicText::OnIsType(TType type)
{
if (CGraphicText::Type() == type)
return true;
return CResource::OnIsType(type);
}
File diff suppressed because it is too large Load Diff
+14 -10
View File
@@ -4,6 +4,7 @@
#include "EterLib/GrpTexture.h"
#include "../PlatformStub.h"
#include "UIRenderCommands.h"
auto CGraphicTexture::IsEmpty() const -> bool
{
@@ -27,34 +28,37 @@ auto CGraphicTexture::SetTextureStage(int) const -> void
auto CGraphicTexture::GetD3DTexture() const -> LPDIRECT3DTEXTURE8
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<LPDIRECT3DTEXTURE8>();
return m_lpd3dTexture;
}
// PORT: safe_release(m_lpd3dTexture); the only textures this platform creates are memory textures.
auto CGraphicTexture::DestroyDeviceObjects() -> void
{
MT_PLATFORM_STUB();
if (m_lpd3dTexture)
UIRenderReleaseMemoryTexture(m_lpd3dTexture);
m_lpd3dTexture = NULL;
}
CGraphicTexture::CGraphicTexture()
{
m_bEmpty = true;
m_width = m_height = 0;
m_lpd3dTexture = nullptr;
Initialize();
}
CGraphicTexture::~CGraphicTexture()
{
MT_PLATFORM_STUB();
}
auto CGraphicTexture::Destroy() -> void
{
m_bEmpty = true;
m_width = m_height = 0;
DestroyDeviceObjects();
Initialize();
}
auto CGraphicTexture::Initialize() -> void
{
MT_PLATFORM_STUB();
m_lpd3dTexture = NULL;
m_width = 0;
m_height = 0;
m_bEmpty = true;
}
@@ -30,8 +30,22 @@ std::uint32_t UIRenderColor(const Color& color) {
}
class CGraphicTexture;
// A file-backed texture is named by its pack path; a memory texture (CGraphicImageTexture::Create,
// filled through Lock/Unlock: the CGraphicFontTexture glyph pages) by "mem:<id>@<revision>", the
// revision counting Unlocks so the canvas knows when to fetch the pixels again.
std::string UIRenderTextureName(const CGraphicTexture* texture);
// The pixels of memory texture "mem:<id>" (the part of the name before '@'), as 0xAARRGGBB.
struct UIMemoryTexture {
int width = 0;
int height = 0;
std::uint32_t revision = 0;
std::vector<std::uint32_t> argb;
};
bool UIRenderMemoryTexture(const std::string& name, UIMemoryTexture* out);
struct IDirect3DTexture8;
void UIRenderReleaseMemoryTexture(IDirect3DTexture8* texture);
// A textured quad from 40250's TPDTVertex[4] (TL, TR, BL, BR) positions and texture coordinates.
// PORT: D3D8 puts pixel centres on integers, which is why 40250 subtracts 0.5 from every vertex; the
// Godot canvas puts them on .5, so the quad is shifted back by +0.5 here.
+100 -9
View File
@@ -1,18 +1,109 @@
// 40250 EterLib/Util.cpp 的“默认代码页”那一小块。
// 40250 EterLib/Util.cpp:140-297, the default code page and font face.
//
// Util.cpp 本身是逻辑单元(LoadTextData / base64 / TokenTo*),但代码页这几个函数和它们旁边的
// GetFontFaceFromCodePage 是连在一起的,后者靠 GDI 的 EnumFontFamiliesEx 枚举字体,win32 shim 里没有,
// 真正的实现要等 2V0-f 的文字渲染。所以整份 Util.cpp 的移植留到那时,这里只放现在真正被调用到的
// GetDefaultCodePage:EterPythonLib/PythonWindow.cpp 的 CTextLine::OnChangePosition 用它判断 CP_ARABIC。
//
// 默认值和 40250 一致:gs_codePage = 0,也就是“还没有 SetDefaultCodePage”。40250 在
// PythonApplication 里根据 locale 调 SetDefaultCodePage(),那条路径同样等 2V0-d。
// The rest of Util.cpp (LoadTextData / base64 / TokenTo*) is logic and not here. The 9x face table has
// CP949/Shift-JIS/GBK/Big5 literals, so this block is copied by hand instead of port_copy.
#include "EterLib/StdAfx.h"
#include "EterLib/Util.h"
#include "EterLocale/CodePageId.h"
static DWORD gs_codePage = 0;
static std::string gs_fontFace="";
static DWORD gs_codePage=0;
int GetCharsetFromCodePage(WORD codePage)
{
switch( codePage )
{
case CP_932:
return SHIFTJIS_CHARSET;
case CP_949:
return HANGUL_CHARSET;
case CP_936:
return GB2312_CHARSET;
case CP_950:
return CHINESEBIG5_CHARSET;
case CP_1253:
return GREEK_CHARSET;
case CP_1254:
return TURKISH_CHARSET;
case CP_1255:
return HEBREW_CHARSET;
case CP_1256:
return ARABIC_CHARSET;
case CP_1257:
return BALTIC_CHARSET;
case CP_1258:
return VIETNAMESE_CHARSET;
case CP_874:
return THAI_CHARSET;
case CP_1250:
return EASTEUROPE_CHARSET;
case CP_1251:
return RUSSIAN_CHARSET;
default:
return DEFAULT_CHARSET;
}
}
const char* GetFontFaceFromCodePageNT(WORD codePage)
{
switch( codePage )
{
case CP_932:
return "MS PGothic";
case CP_949:
return "GulimChe";
case CP_936:
return "SimSun";
case CP_950:
return "MingLiU";
case CP_874:
return "Tahoma";
case CP_1252:
return "Arial";
case CP_1256:
return "Tahoma";
case CP_1258:
return "Tahoma";
case CP_65001:
return "Arial";
default:
return "Arial";
}
}
DWORD GetDefaultCodePage()
{
return gs_codePage;
}
const char * GetDefaultFontFace()
{
return gs_fontFace.c_str();
}
// PORT: 40250 asks EnumFontFamiliesEx for the 9x (native-script) face name, then the NT one. The native
// names never match a font file here; CreateFontIndirect (platform/Win32Gdi.cpp) substitutes a missing
// face, so the NT name is the answer.
const char* GetFontFaceFromCodePage(WORD codePage)
{
return GetFontFaceFromCodePageNT(codePage);
}
void SetDefaultFontFace(const char* fontFace)
{
gs_fontFace=fontFace;
}
bool SetDefaultCodePage(DWORD codePage)
{
gs_codePage=codePage;
std::string fontFace=GetFontFaceFromCodePage(codePage);
if (fontFace.empty())
return false;
SetDefaultFontFace(fontFace.c_str());
return true;
}