UCGUI做汉字显示

2023-10-27

1、弄个包含中文的字体,在这里我借用大多数例子里的 “C:/windows/Font/simhei.ttf”文件。把这个文件拷贝到Datafiles文件夹的Font文件夹里。

2、随便照着一个 .Font文件,自己写一个simhei.font文件。可以用TXT写,然后保存,有的朋友说需要保存为utf8编码格式,实际上是不需要的。

3、同时注意修改你加载到程序里的scheme文件,将里面的字体文件设置成simhei.ttf。你也可以继续使用FirstWindow这个例子,这样的话直接修改源代码里的字体为simhei.tff。

4、现在在程序里进行字符编码转换,我拿代码说明问题:

std::wstring aa = L”123中文abcあいうえお”;

char buff[128] = “”;

WideCharToMultiByte( CP_UTF8, 0, aa.c_str(), aa.size(), buff, sizeof(buff), 0, 0);

button1->setText ( CEGUI::String ( CEGUI::utf8* )buff );

原理是这样的,对于utf8来说,英文字符和ansi编码 在内存布局上没什么区别,都是一个UCHAR。但是对于非英文字符,则是UCHAR+UCHAR+UCHAR。如果我们手工进行编码格式转换,会比较烦琐。

比较偷懒的方法就是,我们先用WCHAR(unicode内存布局,UCHAR+UCHAR+UCHAR+UCHAR)来储存需要显示的字符串,然后调用Win32API来帮我们把宽字符转换成char(多字节字符集内存布局)。

这就是基本方法了,然后我们可以根据这个转换方针,利用Win32API随意的转换字符编码格式,从而满足程序中的各种需求。

通过此方法可以显示中文,还没来得急高兴就发现了第二个问题:这种方法显示中文速度太慢(显示几十个字需要等上7、8秒左右)。难道没有高效的方法吗?

于是继续Google(我很懒,别人能做的事情从来不麻烦自己,懒得跟踪代码),结果还真让我找到了两篇相关的文章:一份是千里马肝的《游戏中汉字显示的实现与技巧》,另一份是免费打工仔的《让OGRE支持中文》。从中找到了原因:

原来在游戏中,是将点阵字库或tif字体里的文字写进纹理,根据需求贴到指定的位置。英文的显示非常简单,只有26个字母,就算再加一些标点、符号什么的,用一张位图,就可以足以显示所有的单词了。而中文要像处理英文那样,把所有的汉字都保存在一张位图里,那么每一种字体都要生成一个巨型位图。在GB2312中,一共有6000多个汉字,就算是用16*16,据说会有2.5M!(马肝兄说的,我没算过)

继续Google,也没有找到解决问题的直接办法,唉,再懒也得自己上阵了。

通过跟踪调试,发现了问题所在,原来罪魁祸首就是他:

const FontGlyph *Font::getGlyphData (utf32 codepoint)

{

if (codepoint > d_maxCodepoint)

return 0;

if (d_glyphPageLoaded)

{

uint page = codepoint / GLYPHS_PER_PAGE;

uint mask = 1 << (page & (BITS_PER_UINT – 1));

if (!(d_glyphPageLoaded [page / BITS_PER_UINT] & mask))

{

d_glyphPageLoaded [page / BITS_PER_UINT] |= mask;

rasterize (codepoint & ~(GLYPHS_PER_PAGE – 1),

codepoint | (GLYPHS_PER_PAGE – 1));

}

}

CodepointMap::const_iterator pos = d_cp_map.find (codepoint);

return (pos != d_cp_map.end()) ? &pos->second : 0;

}

原来CEGUI根据Unicode字符的编码顺序,为每256个字符分配一张纹理(例如编码0-255存放在纹理一,编码768-1023 存放在纹理四)。英文很容易搞定了,那么几个字符一张纹理就够了,可中文就得靠运气了,有时显示几个字就要生成几张纹理,还要将每张纹理用不需要的相邻字填满,劳民伤财!

发现了问题,我便按照千里马肝的思想对函数进行了改造,将使用的文字放入一张纹理中,因为纹理最大承载256个字,所以,当汉字超过256个时,则将不常用的去掉,将新的字符写入。

后来我发现汉字的引用没有太多的规律,常用的一千多汉字出现的概率没有那么悬殊(废话,要不怎么是常用呢!),没有办法很好地按照使用的频率将汉字限制在256个字以内,写进纹理,就索性一旦满了就将字全部释放掉,重新写入。(也需有我没找到,还请高手指教)

代码如下:

const FontGlyph *Font::getGlyphData (utf32 codepoint)

{

if (codepoint > d_maxCodepoint)

return 0;

if(codepoint < 256) //决定保留一张纹理放英文和字符

{

if (d_glyphPageLoaded)

{

uint page = codepoint / GLYPHS_PER_PAGE;

uint mask = 1 << (page & (BITS_PER_UINT – 1));

if (!(d_glyphPageLoaded [page / BITS_PER_UINT] & mask))

{

d_glyphPageLoaded [page / BITS_PER_UINT] |= mask;

rasterize (codepoint & ~(GLYPHS_PER_PAGE – 1),

codepoint | (GLYPHS_PER_PAGE – 1));

}

}

CodepointMap::const_iterator pos = d_cp_map.find (codepoint);

return (pos != d_cp_map.end()) ? &pos->second : 0;

}

else //显示汉字啦

{

CodepointMap::const_iterator pos;

pos = d_hz_map.find (codepoint);

if(pos != d_hz_map.end())

{

return (pos != d_hz_map.end()) ? &pos->second : 0;

}

else

{

rasterizeHZ(codepoint);

pos = d_hz_map.find (codepoint);

return (pos != d_hz_map.end()) ? &pos->second : 0;

}

}

}

void FreeTypeFont::rasterizeHZ (utf32 codepoint)

{

int num;

uint texsize = 512;

if(d_hz_map.size() < 256)

{

float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);

d_hz_map[codepoint] = FontGlyph (adv);

}

else

{

d_hz_map.clear();

ImagesetManager::getSingleton ().destroyImageset (hzImageset->getName ());

hzImageset = ImagesetManager::getSingleton ().createImageset (

d_name + “_auto_glyph_images_” ,

System::getSingleton ().getRenderer ()->createTexture ());

d_glyphImages.push_back (hzImageset);

float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);

d_hz_map[codepoint] = FontGlyph (adv);

}

CodepointMap::const_iterator hzInter = d_hz_map.find(codepoint);

if (!hzInter->second.getImage())

{

// Render the glyph

if (FT_Load_Char (d_fontFace, hzInter->first, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT |

(d_antiAliased ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO)))

{

std::stringstream err;

err << “Font::loadFreetypeGlyph – Failed to load glyph for codepoint: “;

err << static_cast<unsigned int> (hzInter->first);

err << “. Will use an empty image for this glyph!”;

Logger::getSingleton ().logEvent (err.str (), Errors);

// Create a ‘null’ image for this glyph so we do not seg later

Rect area(0, 0, 0, 0);

Point offset(0, 0);

String name;

name += hzInter->first;

hzImageset->defineImage(name, area, offset);

((FontGlyph &)hzInter->second).setImage(&hzImageset->getImage(name));

}

else

{

uint glyph_w = d_fontFace->glyph->bitmap.width + INTER_GLYPH_PAD_SPACE;

uint glyph_h = d_fontFace->glyph->bitmap.rows + INTER_GLYPH_PAD_SPACE;

// Check if glyph right margin does not exceed texture size

uint x_next = m_nHZX + glyph_w;

if (x_next > texsize)

{

m_nHZX = INTER_GLYPH_PAD_SPACE;

x_next = m_nHZX + glyph_w;

m_nHZY = m_nHZYB;

}

// Check if glyph bottom margine does not exceed texture size

uint y_bot = m_nHZY + glyph_h;

// Copy rendered glyph to memory buffer in RGBA format

drawGlyphToBuffer (hzmem_buffer + (m_nHZY * texsize) + m_nHZX, texsize);

// Create a new image in the imageset

Rect area(static_cast<float>(m_nHZX),

static_cast<float>(m_nHZY),

static_cast<float>(m_nHZX + glyph_w – INTER_GLYPH_PAD_SPACE),

static_cast<float>(m_nHZY + glyph_h – INTER_GLYPH_PAD_SPACE));

Point offset(d_fontFace->glyph->metrics.horiBearingX * static_cast<float>(FT_POS_COEF),

-d_fontFace->glyph->metrics.horiBearingY * static_cast<float>(FT_POS_COEF));

String name;

name += hzInter->first;

hzImageset->defineImage (name, area, offset);

((FontGlyph &)hzInter->second).setImage (&hzImageset->getImage (name));

// Advance to next position

m_nHZX = x_next;

if (y_bot > m_nHZYB)

{

m_nHZYB = y_bot;

}

}

}

// Copy our memory buffer into the texture and free it

hzImageset->getTexture ()->loadFromMemory (hzmem_buffer, texsize, texsize, Texture::PF_RGBA);

}

转载于:https://www.cnblogs.com/skl374199080/archive/2013/06/03/3116106.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UCGUI做汉字显示 的相关文章

  • C语言如何自定义头文件——一看就废!!!

    为什么要自定义头文件 如果在一个文件中 写上成百上千行的代码 那么这些代码让人阅读起来是真的烦 因此 我们可以引入头文件 把自己写的函数放入头文件中 然后直接调用到主程序中 这样在主程序中看起来就比较清晰 那如何自定义头文件呢 第一步 我们
  • 开源堡垒机jumpserver的搭建与使用

    目录 一 准备 Python3 和 Python 虚拟环境 二 安装 Jumpserver 三 安装 SSH Server 和 WebSocket Server Coco 四 安装 Web Terminal 前端 Luna 五 安装 Win
  • 2080Ti NVIDIA显卡安装教程记录

    1 硬件安装 找到卡槽 顺位安装 找到电源插头 配套孔位即可 2 软件安装 搞个NVIDIA控制面板 此外 安装CUDA和cuDNN win10下CUDA和CUDNN的安装 超详细 亲测有效 u011473714的专栏 CSDN博客
  • Centos6.5下搭建nagios详解

    一 LAMP环境部署 1 安装php 1 安装yum源 rpm Uvh http download fedoraproject org pub epel 6 x86 64 epel release 6 8 noarch rpm rpm Uv
  • 用于灵敏性分析的方法模型(Matlab代码实现)

    目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 本代码用于灵敏性分析的方法模型 2 运行结果 3 参考文献 1 姚宏亮 苌健 王浩 李俊照 灵敏性分析下的因果网络参数的扰动学习研究 J 计算机科学与探索 2012
  • MySQL之面试真题详解

    目录 1 前言 1 1InnDB存储引擎与MyISAM存储引擎的区别 1 2关系型数据库常用的三个操作 1 3行转列 2 面试题详解 2 1建立数据表 2 1 1要求 2 1 2代码 2 2试题讲解与展示 1 前言 1 1InnDB存储引擎
  • 前端实习面试总结

    文章目录 HTML CSS 1 如何理解HTML语义化 2 哪些HTML是块级元素 内联元素 行内元素 行内块元素 3 盒模型的宽度和高度如何计算 4 margin纵向重叠的问题 5 margin负值的问题 6 BFC的理解与应用 7 fl
  • 【深度学习】空洞卷积(扩张卷积)和一般卷积的区别 Dilated Convolution

    文章目录 前言 一 感受野 二 空洞卷积 三 补充 padding 前言 目前来说有一个想法 距离寒假还有一个月 想在放寒假之前把深度学习这半年来的基础知识都补充回归一下 以写成博客的形式进行汇总 今天回顾的主要是理论方面的 空洞卷积 一
  • Python第三章 程序控制结构

    Python第三章 程序控制结构 if 选择语句 while 循环语句 for 循环语句 循环嵌套 跳转语句 if 选择语句 基础语法 if 表达式1 语句块1 elif 表达式2 语句块2 elif 表达式3 语句块3 else 语句块n
  • 周期性线程池newScheduledThreadPool详解

    线程池支持定时以及周期性执行任务 创建一个corePoolSize为传入参数 最大线程数为整形的最大数的线程池 public static ScheduledExecutorService newScheduledThreadPool in
  • 【计算机网络】实验六 综合设计实验

    实验六 综合设计实验 一 实验目的 规划设计中小型园区网络系统设计方案 给出需求分析 设计规划 设备选型等 二 实验属性 设计性实验 三 实验仪器设备及器材 Cisco2950交换机 Cisco 3560交换机 Cisco 2621 Cis
  • 记录一次在centos 8 下docker 安装reids 一直报错无法启动问题

    目录 1 首先翻看了网上大部分启动失败原因总结如下 可以使用docker logs reids查看启动失败原因 1 1启动挂载目录失败 通常是没有创建目录 1 2启动闪退 通常为配置文件 daemonize yes 没有改成 no 导致 1
  • 【RASA】KafkaEventBroker性能优化

    项目背景 实际项目中 对话数据需要存储到数据库中 就先使用rasa自带的KafkaEventBroker 用于对话消息生产 再用flink对对话数据进行消费 不过在使用的过程中会遇到性能的瓶颈 具体如下 先贴一下KafkaEventBrok
  • 区间预测

    区间预测 MATLAB实现QRGRU门控循环单元分位数回归时间序列区间预测 目录 区间预测 MATLAB实现QRGRU门控循环单元分位数回归时间序列区间预测 效果一览 基本介绍 模型描述 程序设计 参考资料 效果一览 进阶版 基础版 基本介
  • 若依quartz定时任务添加SimpleTrigger(解决超过60分钟的定时)

    在用到若依quartz时 业务的定时间隔不能整除60 例如31 91 181分钟 用Cron的表达式实现31分钟的运行时间并不是每次都间隔31分钟 Cron表达式的另一种实现逻辑就是用Cron的确切日期30 14 18 23 9 指定每次执
  • 使用JS实现一个简单的观察者模式(Observer)

    聚沙成塔 每天进步一点点 专栏简介 手撸Observer 写在最后 专栏简介 前端入门之旅 探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅 这个专栏是为那些对Web开发感兴趣 刚刚
  • 向管理转型:思维篇 转

    作者 阿蒙 在我的文章里出现最多的词语估计就是 思维 二字了 我认为一个人的思维能力是非常重要的 思维是智力的核心 思维能力包含的范围很广 常见的有逆向思维 发散思维 融合思维等等 记得曾经看过一本好象是老美写的书 思维决定一切 书里强调思
  • 前端系列之jQuery(jQueryDOM操作)

    一 如何筛选jQuery对象 div div div
  • Unity如何调用手机拍照缩放功能

    上级交代了一个任务 需要软件调用手机相机拍照缩放功能 方便用户自行搭配图片 第一个问题 如何获取手机的摄像头所拍摄的画面 unity中有一个类 WebCamTexture 继承自Texture类 访问它的静态成员devices 即可获得所有
  • openGauss学习笔记-22 openGauss 简单数据管理-HAVING子句

    文章目录 openGauss学习笔记 22 openGauss 简单数据管理 HAVING子句 22 1 语法格式 22 2 参数说明 22 3 示例 openGauss学习笔记 22 openGauss 简单数据管理 HAVING子句 H

随机推荐

  • 小程序接入微信支付V3接口开发教程

    前言 最近做了一个小程序对接微信支付的需求 查看微信支付文档 还是感觉有点凌乱 所以做一个统一整理 供大家参考 API参考官方文档 https pay weixin qq com wiki doc apiv3 open pay chapte
  • EF Core 7.0 使用教程 (VSCode命令)

    第一步 安装EF Core 安装指令 dotnet tool install global dotnet ef 卸载指令 dotnet tool uninstall global dotnet ef 不可以重复安装 会出现问题 我这里是日语
  • 用ChatGPT 处理复杂 Excel 数据并进行数据分析

    用ChatGPT 处理复杂 Excel 数据的方法 由于目前 ChatGPT 还不支持上传文件以及对大数据量的处理 所以我们只能换一种思路结合 Excel 和 ChatGPT 的协作 整体思路 我们告诉 ChatGTP 我们想要实现什么样的
  • linux:通过端口查对应的服务/应用的位置

    1 根据端口查看对应的进程 lsof i port 2 根据进程号PID查看对应的应用 ps axu grep PID 3 根据应用名称查所在位置 find name 应用名称 4 根据进程号PID查看对应的端口 netstat anp g
  • c盘中可以删除的文件有哪些?

    win7系统很占用空间 所以说 如果你的c盘空间不够强大的话 是无法承载win7系统的 但是即便是安装了win7系统 我们也可以对c盘的空间进行优化 下面小编就来告诉大家 c盘中可以删除的文件有哪些 打开c盘 我们可以看到里面的组织构架 里
  • GW1NSR-LV4CQN48GC6/I5 FPGA呼吸灯

    环境 pwm v cat pwm v module Pwm input clk input 31 0 period input 31 0 duty output pwmout reg 31 0 counter reg r pwmout al
  • iframe+ajaxSubmit结合--续篇(判断图片(文件)大小,上传图片,验证码刷新)

    人们似乎慢慢遗忘了iframe 毕竟在ajax未诞生前 都是用iframe来实现无刷新的效果 当请教iframe实现无刷新知识时 他们说从来没用过 iframe是什么 无奈 只有自己摸索 毕竟我属入门级别 下面的方法从效率上好不好 我也说不
  • 傻瓜式学习webpack(五)——css的抽离和html的自动引入js/css

    一 以前面四篇文章为基础 我们接下来利用webpack进行css的抽离 这里需要安装一个插件 在安装之前 首先要说明一下 如果没有第四篇文章为前提 也就是图片没有进行处理的话 在抽离css的时候 它将无法解析css中的url 所以在抽离之前
  • Linux svn server 给指定文件夹设置相应的读写权限

    简介 在使用Linux搭建SVN服务器的时候 需要给仓库中不同的文件夹设置不同的权限 1 在svn目录中有Dan和Mango两个文件夹 2 进入svn conf目录下 使用vim命令 vi authz配置的authz权限 3 输入相应的指令
  • 第七课旋转物体

    类似于平移 在内容编辑器中的transform rotation更改即可 这样精确
  • JWT 创建Token 提示:secret key byte array cannot be null or empty.

    使用JWT生成Token提示 java lang IllegalArgumentException secret key byte array cannot be null or empty 详细错误信息 java lang Illegal
  • Java面试题(十九个模块)面试必备

    关注我 带了熟悉Java趣事 Java进阶攻略等着你 本文分为十九个模块 分别是 Java 基础 容器 多线程 反射 对象拷贝 Java Web 异常 网络 设计模式 Spring Spring MVC Spring Boot Spring
  • Batch Gradient Descent(python)

    import numpy as np import tensorflow as tf def GradientDescent x y theta m n x shape m is training example while n is fe
  • 金蝶牵手IBM也许是个灾难

    从去年6月开始金蝶 用友与微软 IBM SAP ORACLE 等等陷入了n方收购传闻 前几天终于有了消息 金蝶接受ibm与雷曼兄弟的投资 因本人对金蝶和用友的公司与产品比较的熟悉 所以我认为对金蝶也许不是一件好事 大家都知道ibm的核心是j
  • 关于APP弱网测试

    一 网络测试的一般流程 step1 首先要考虑网络正常的情况 各个模块的功能正常可用 页面元素 数据显示正常 step2 其次要考虑无网络的情况 APP各个功能在无网络情况下是否可用 APP各个页面之间切换是否正常 发送网络请求时是否会导致
  • Base64 —— 编码/解码

    Base64是基于64个字符来表示二进制数据的方法 由于2的6次方等于64 所以每6位为一个字符 对应某个字符 在Base64中的表示字符包括A Z a z 0 9 这样共有62个字符 从左往右依次代表0 61 剩下两个字符 代表62 代表
  • 做期货的阶段(做期货的几个阶段)

    如何自己做好期货 学习交易大致有三阶段 直观直觉阶段 看到涨就做多 看到跌就做空 结果半赢半输 学习积累的阶段 看到涨跌不觉涨跌 想得很多 结果赢少赔多 领悟后再次直观直觉的阶段 看到涨还是涨于是做多 看到跌还是跌于是做空 终于赢比输多 这
  • ae在哪里直接复制合成_AE如何复制同一合成下图层的效果到另一个图层上

    如何把一个图层的动画 效果等属性 比如缩放位移动画 模糊 斜面阴影 径向擦除等 复制到同一合成下的另一个图层上呢 1 合成里面有一个素材01和素材02 素材01上面有效果控件和缩放位移动画 而02上面没有任何效果和动画 现在想把01里面的效
  • Linux 内核编译报错及解决办法记录

    Linux 内核编译报错及解决办法记录 Can t use defined array Maybe you should just omit the defined at kernel timeconst pl line 373 根据错误的
  • UCGUI做汉字显示

    1 弄个包含中文的字体 在这里我借用大多数例子里的 C windows Font simhei ttf 文件 把这个文件拷贝到Datafiles文件夹的Font文件夹里 2 随便照着一个 Font文件 自己写一个simhei font文件