Skip to content

Commit

Permalink
Merge pull request #150 from chirsz-ever/chirsz/support-utf8
Browse files Browse the repository at this point in the history
feat: support UTF-8
  • Loading branch information
chirsz-ever authored Apr 16, 2024
2 parents 686a6d6 + 315b277 commit e6cf510
Show file tree
Hide file tree
Showing 18 changed files with 310 additions and 418 deletions.
4 changes: 3 additions & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"_FORTIFY_SOURCE=0"
],
"includePath": [
"${workspaceFolder}/include"
"${workspaceFolder}/include",
"${workspaceFolder}/3rdparty/libpng",
"${workspaceFolder}/build/**"
]
}
]
Expand Down
5 changes: 4 additions & 1 deletion RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

遵循[如何维护更新日志](https://keepachangelog.com/zh-CN/1.0.0/)编写。

## 未发布(20.09
## 未发布(24.0a

### 更新

Expand All @@ -12,6 +12,8 @@
- 增加绘制圆角矩形的函数。
- 增加主控台系列函数。
- 现在 `ege::saveimage` 根据后缀名决定将文件保存为 png 还是 bmp 格式。
- 增加 `ege::setcodepage` 控制 EGE 如何解析程序中的 `char*` 字符串。
- 增加 `ege::setunicodecharmessage` 控制字符消息的编码。

### 修复

Expand All @@ -28,6 +30,7 @@
- 改用支持 GPU 加速的 `AlphaBlend` 函数实现 `ege::putimage_alpha`
-`ege::resize` 行为改回会填充背景色,并增加不填充背景色的 `ege::resize_f` 函数。
- 按照 CSS 颜色表修改并增加了预定义颜色值定义。
- `INIT_UNICODE` 初始化选项,改为设置 `setunicodecharmessage(true)`,现在 EGE 总是创建 Unicode 窗口。

## [20.08] - 2020-08-31

Expand Down
93 changes: 93 additions & 0 deletions demo/ege_input_demo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include <ege.h>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>

#define CHAR_MSG_MBCS 0
#define CHAR_MSG_UTF_16 1

#define FONT_HEIGHT 20
#define FONT_WIDTH 10
#define WIDTH 480
#define HEIGHT 360

int main(int argc, char** argv)
{
int mode = CHAR_MSG_MBCS;
if (argc > 1 && strcmp(argv[1], "--utf-8") == 0) {
ege::setcaption("ege input demo - UTF-8");
ege::setcodepage(EGE_CODEPAGE_UTF8);
// ege::setunicodecharmessage(false);
} else if (argc > 1 && strcmp(argv[1], "--utf-16") == 0) {
ege::setcaption("ege input demo - UTF-16");
// ege::setcodepage(EGE_CODEPAGE_ANSI);
ege::setunicodecharmessage(true);
mode = CHAR_MSG_UTF_16;
} else {
// ege::setcodepage(EGE_CODEPAGE_ANSI);
ege::setcaption("ege input demo - ANSI");
// ege::setunicodecharmessage(false);
}

ege::initgraph(WIDTH, HEIGHT);
ege::setfont(FONT_HEIGHT, FONT_WIDTH, "SimHei");

std::vector<std::vector<char> > input_strings;
std::vector<std::vector<wchar_t> > input_strings_w;

while (ege::is_run()) {
std::vector<wchar_t> chars;

while (ege::kbmsg()) {
ege::key_msg kmsg = ege::getkey();
if (kmsg.msg == ege::key_msg_char) {
chars.push_back(kmsg.key);
}
}

// print to console
if (!chars.empty()) {
for (int i = 0; i < chars.size(); ++i) {
printf("%d", chars[i]);
if (i != chars.size() - 1) {
printf(", ");
}
}
printf("\n");

if (mode == CHAR_MSG_UTF_16) {
chars.push_back(0);
input_strings_w.push_back(chars);
} else {
std::vector<char> str;
for (int i = 0; i < chars.size(); ++i) {
str.push_back((char)chars[i]);
}
str.push_back(0);
input_strings.push_back(str);
}
}

// draw to screen
ege::cleardevice();
if (mode == CHAR_MSG_UTF_16) {
if (input_strings_w.size() * FONT_HEIGHT > HEIGHT) {
input_strings_w.erase(input_strings_w.begin());
}
for (int i = 0; i < input_strings_w.size(); ++i) {
ege::outtextxy(5, i * FONT_HEIGHT, &input_strings_w[i][0]);
}
} else {
if (input_strings.size() * FONT_HEIGHT > HEIGHT) {
input_strings.erase(input_strings.begin());
}
for (int i = 0; i < input_strings.size(); ++i) {
ege::outtextxy(5, i * FONT_HEIGHT, &input_strings[i][0]);
}
}

ege::delay_fps(60);
}
return 0;
}
16 changes: 11 additions & 5 deletions demo/egedemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,11 +1093,16 @@ class SceneIntroduce : public SceneBase
SceneIntroduce()
{
memset(m_str, 0, sizeof(m_str));
strcpy(m_str, "你是刚刚学习C语言的新手吗?你是不是觉得单纯的字符输出有点无聊?C语言只能做这些吗?能不能做更有趣的?比如写游戏?\r\n本演示程序就是为了给你解开这个疑惑,本程序将带你进入精彩的C语言图形世界!不管你现在的C是刚刚开始学,还是学了一段时间,只要你有VC或者C-Free,都可以享受这个图形的盛宴。。。\r\n在正式开始前,请你百度“EGE”,下载并按里面的说明文档安装好。如果安装时遇到什么困难,可以加QQ群1060223135说明你的情况,会有人协助你解决的。\r\n(请按任意键继续)\r\n");
// 此处没有直接用宽字符串字面量初始化 m_str, 因为 VC6 会转出乱码
const char* str = "你是刚刚学习C语言的新手吗?你是不是觉得单纯的字符输出有点无聊?C语言只能做这些吗?能不能做更有趣的?比如写游戏?\r\n本演示程序就是为了给你解开这个疑惑,本程序将带你进入精彩的C语言图形世界!不管你现在的C是刚刚开始学,还是学了一段时间,只要你有VC或者C-Free,都可以享受这个图形的盛宴。。。\r\n在正式开始前,请你百度“EGE”,下载并按里面的说明文档安装好。如果安装时遇到什么困难,可以加QQ群1060223135说明你的情况,会有人协助你解决的。\r\n(请按任意键继续)\r\n";
MultiByteToWideChar(getcodepage(), 0, str, -1, m_str, 1024);

// 理想状态:
// wcscpy(m_str, L"你是刚刚学习C语言的新手吗?...");
}
SceneBase* Update()
{
char str[1024] = {0};
wchar_t str[1024] = {0};
int len = 0;
setfont(20, 0, "宋体");
for (len = 0 ; len<=0x80; delay_fps(60))
Expand All @@ -1109,8 +1114,8 @@ class SceneIntroduce : public SceneBase

for (len = 0 ; m_str[len]; delay_fps(30))
{
strncpy(str, m_str, len);
len += 2;
wcsncpy(str, m_str, len);
len += 1;
cleardevice();
setcolor(0x0);
outtextrect(102, 101, 440, 480, str);
Expand All @@ -1129,11 +1134,12 @@ class SceneIntroduce : public SceneBase
return new SceneMenu;
}
private:
char m_str[1024];
wchar_t m_str[1024];
};

int main()
{
setcodepage(EGE_CODEPAGE_UTF8);
initgraph(640, 480);
SceneBase* scene = new SceneIntroduce; //SceneIntroduce; SceneMenu
setbkmode(TRANSPARENT);
Expand Down
1 change: 1 addition & 0 deletions demo/egemouseball.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ void dealMouse(BALL* ball)
int main(void)
{
{
setcodepage(EGE_CODEPAGE_UTF8);
setinitmode(INIT_ANIMATION);
initgraph(LEN, WID);
setcaption("碰撞小球");
Expand Down
1 change: 1 addition & 0 deletions demo/test_setviewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

int main()
{
setcodepage(EGE_CODEPAGE_UTF8);
initgraph(400, 300);
setfont(24, 12, "宋体");
{
Expand Down
16 changes: 15 additions & 1 deletion include/ege.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@
#define EGEGRAYA(gray, a) EGERGBA(gray, gray, gray, a)
#define EGEAGRAY(a, gray) EGEGRAYA(gray, a)

/* you can also use 932 as shift-jis, 950 as big5 ... */
/* see https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers */
#define EGE_CODEPAGE_GB2312 936
#define EGE_CODEPAGE_UTF8 65001
#define EGE_CODEPAGE_ANSI 0

namespace ege
{

Expand Down Expand Up @@ -466,6 +472,7 @@ enum initmode_flag
INIT_TOPMOST = 0x4,
INIT_RENDERMANUAL = 0x8,
INIT_NOFORCEEXIT = 0x10,
// equal to setunicodecharmessage(true)
INIT_UNICODE = 0x20,
INIT_HIDE = 0x40,
INIT_WITHLOGO = 0x100,
Expand Down Expand Up @@ -816,7 +823,12 @@ class IMAGE;
typedef IMAGE *PIMAGE;
typedef const IMAGE *PCIMAGE;


// `codepage` sholde be `EGE_CODEPAGE_XXX`, default is `EGE_CODEPAGE_ANSI`.
void EGEAPI setcodepage(unsigned int codepage);
unsigned int EGEAPI getcodepage();
// set whether char message of `getkey()` use UTF-16
void EGEAPI setunicodecharmessage(bool enable);
bool EGEAPI getunicodecharmessage();
void EGEAPI setinitmode(int mode, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT);
int EGEAPI getinitmode();
void EGEAPI initgraph(int Width, int Height, int Flag);
Expand Down Expand Up @@ -1097,8 +1109,10 @@ void EGEAPI setfont(int nHeight, int nWidth, LPCSTR lpszFace, int nEscapement,
void EGEAPI setfont(int nHeight, int nWidth, LPCWSTR lpszFace, int nEscapement, int nOrientation,
int nWeight, int bItalic, int bUnderline, int bStrikeOut, BYTE fbCharSet,
BYTE fbOutPrecision, BYTE fbClipPrecision, BYTE fbQuality, BYTE fbPitchAndFamily, PIMAGE pimg = NULL);
EGE_DEPRECATE(setfont)
void EGEAPI setfont(const LOGFONTA *font, PIMAGE pimg = NULL);
void EGEAPI setfont(const LOGFONTW *font, PIMAGE pimg = NULL);
EGE_DEPRECATE(getfont)
void EGEAPI getfont(LOGFONTA *font, PCIMAGE pimg = NULL);
void EGEAPI getfont(LOGFONTW *font, PCIMAGE pimg = NULL);

Expand Down
83 changes: 36 additions & 47 deletions include/ege/sys_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@

#include "egecontrolbase.h"

#define EGE_CONVERT_TO_WSTR_WITH(mbStr, block) \
{ \
int bufsize = ::MultiByteToWideChar(::ege::getcodepage(), 0, mbStr, -1, NULL, 0); \
WCHAR* wStr = new WCHAR[bufsize]; \
::MultiByteToWideChar(::ege::getcodepage(), 0, mbStr, -1, &wStr[0], bufsize); \
block delete wStr; \
}

namespace ege
{

Expand Down Expand Up @@ -63,7 +71,7 @@ class sys_edit : public egeControlBase
m_callback = ::GetWindowLongPtrW(m_hwnd, GWLP_WNDPROC);
::SetWindowLongPtrW(m_hwnd, GWLP_WNDPROC, (LONG_PTR)getProcfunc());
{
char fontname[] = {'\xcb', '\xce', '\xcc', '\xe5', 0, 0};
WCHAR fontname[] = L"SimSun";
setfont(12, 6, fontname);
}
visible(false);
Expand Down Expand Up @@ -104,55 +112,31 @@ class sys_edit : public egeControlBase

void setfont(int h, int w, LPCSTR fontface)
{
{
LOGFONTA lf = {0};
lf.lfHeight = h;
lf.lfWidth = w;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = FW_DONTCARE;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfStrikeOut = 0;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = DEFAULT_PITCH;
lstrcpyA(lf.lfFaceName, fontface);
HFONT hFont = CreateFontIndirectA(&lf);
if (hFont) {
::SendMessageA(m_hwnd, WM_SETFONT, (WPARAM)hFont, 0);
::DeleteObject(m_hFont);
m_hFont = hFont;
}
}
EGE_CONVERT_TO_WSTR_WITH(fontface, { setfont(h, w, wStr); });
}

void setfont(int h, int w, LPCWSTR fontface)
{
{
LOGFONTW lf = {0};
lf.lfHeight = h;
lf.lfWidth = w;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = FW_DONTCARE;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfStrikeOut = 0;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = DEFAULT_PITCH;
lstrcpyW(lf.lfFaceName, fontface);
HFONT hFont = CreateFontIndirectW(&lf);
if (hFont) {
::SendMessageW(m_hwnd, WM_SETFONT, (WPARAM)hFont, 0);
::DeleteObject(m_hFont);
m_hFont = hFont;
}
LOGFONTW lf = {0};
lf.lfHeight = h;
lf.lfWidth = w;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = FW_DONTCARE;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfStrikeOut = 0;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = DEFAULT_PITCH;
lstrcpyW(lf.lfFaceName, fontface);
HFONT hFont = CreateFontIndirectW(&lf);
if (hFont) {
::SendMessageW(m_hwnd, WM_SETFONT, (WPARAM)hFont, 0);
::DeleteObject(m_hFont);
m_hFont = hFont;
}
}

Expand All @@ -168,7 +152,10 @@ class sys_edit : public egeControlBase
::MoveWindow(m_hwnd, m_x, m_y, m_w, m_h, TRUE);
}

void settext(LPCSTR text) { ::SendMessageA(m_hwnd, WM_SETTEXT, 0, (LPARAM)text); }
void settext(LPCSTR text)
{
EGE_CONVERT_TO_WSTR_WITH(text, { settext(wStr); });
}

void settext(LPCWSTR text) { ::SendMessageW(m_hwnd, WM_SETTEXT, 0, (LPARAM)text); }

Expand Down Expand Up @@ -215,5 +202,7 @@ class sys_edit : public egeControlBase
LONG_PTR m_callback;
};

#undef EGE_CONVERT_TO_WSTR_WITH

} // namespace ege
#endif /*EGE_SYS_EDIT_H*/
4 changes: 3 additions & 1 deletion src/ege_head.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class egeControlBase; // egeControlBase 前置声明
struct _graph_setting
{
bool has_init;
bool is_unicode;
bool unicode_char_message;

struct _graph
{
Expand Down Expand Up @@ -230,6 +230,8 @@ struct _graph_setting
double delay_ms_dwLast;
double delay_fps_dwLast;
int getch_last_key;
unsigned int codepage;
wchar_t wchar_message_low_surrogate_cache;

HBRUSH savebrush_hbr;

Expand Down
6 changes: 3 additions & 3 deletions src/egegapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1579,10 +1579,10 @@ void EGEAPI ege_drawtext(LPCSTR textstring, float x, float y, PIMAGE pimg)
{
PIMAGE img = CONVERT_IMAGE(pimg);
if (img && img->m_hDC) {
int bufferSize = MultiByteToWideChar(CP_ACP, 0, textstring, -1, NULL, 0);
int bufferSize = MultiByteToWideChar(getcodepage(), 0, textstring, -1, NULL, 0);
if (bufferSize < 128) {
WCHAR wStr[128];
MultiByteToWideChar(CP_ACP, 0, textstring, -1, wStr, 128);
MultiByteToWideChar(getcodepage(), 0, textstring, -1, wStr, 128);
ege_drawtext_p(wStr, x, y, img);
} else {
const std::wstring& wStr = mb2w(textstring);
Expand Down Expand Up @@ -1796,7 +1796,7 @@ int inputbox_getline(LPCSTR title, LPCSTR text, LPSTR buf, int len)
std::wstring buf_w(len, L'\0');
int ret = inputbox_getline(title_w.c_str(), text_w.c_str(), &buf_w[0], len);
if (ret) {
WideCharToMultiByte(CP_ACP, 0, buf_w.c_str(), -1, buf, len, 0, 0);
WideCharToMultiByte(getcodepage(), 0, buf_w.c_str(), -1, buf, len, 0, 0);
}
return ret;
}
Expand Down
Loading

0 comments on commit e6cf510

Please sign in to comment.