冒险解谜游戏中文网 ChinaAVG
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数修改2
[打印本页]
作者:
shane007
时间:
2023-9-6 15:25
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数修改2
本帖最后由 shane007 于 2023-9-6 15:32 编辑
3 Z) M$ p. K; U3 C
# |" e4 E$ L6 D
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
8 c/ j4 X9 ]" `
本代码经过分析以及改写之后,将取代游戏原有的显示函数。
, c, \7 \$ |% w, D7 M4 T$ O/ ]
K8 |" i$ S( Z
代码详细说明如下
/ ]- \) U/ |+ D, Q1 h) i$ e- }! Z
0 V8 ~7 E% l' J+ c7 l! B: h0 F: B4 W
在上述 renderString 函数中,我们有以下关键部分的解释:
, A! g: S7 }: c% E T0 |; S7 ^
% j! K3 W3 a' v# p( r
glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
8 \5 J9 R: m4 a2 n8 N7 }
- ]# L; E6 `6 ~8 V
glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
- E& N# \; h, X0 D7 H
+ m5 N+ B% f8 E& ~
glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
6 C) t- {( U+ @( f* \% `
+ d1 _- X. J Y+ U' p! d7 | ~1 C
for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
0 w9 ~! A9 T: C* ?
' b: L8 Q! Q) H0 ?1 k, o: m; R
FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
5 y" e8 ~7 @% `! F; T; O
, \7 w! }$ |$ K9 y
计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
; K! p4 }3 M8 d2 s5 a
5 z( C! v6 ?9 ^* F
使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
$ @; Z4 `: g( i7 o' n, A0 Q, z: {
' |9 v7 e& p( N
x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
4 ~) v" p: _( ^; `1 Z; {
; ?% ?* r0 W5 x4 K% H
最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
0 L0 Y+ \9 R! c: V0 a* t
2 U: a4 p1 K ~% ~$ Z/ M
总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
% a9 J1 B# y/ x8 P
复制代码
: C1 Q6 N" n5 R# }
p3 W+ d: ~1 h4 t N, M
字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:
; l- t& G" U, O% ^
( O* K0 M; b/ Q5 j2 p/ t1 W
参数:
( o( \' v4 {1 k% X" R; r3 E$ \
0 p! z6 p) u/ I4 a* c( K/ S
face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
) Y3 X5 Z/ j, E q, `% M5 w
char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
8 n. ~* j9 g j
load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
# D1 L9 m4 a+ ^$ S- F, M1 d
功能:
r6 E$ X* m( H7 b) g+ g w
. W% S. g4 Y; [+ D2 E/ m
FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
+ k' b( K4 Q: y0 X& p4 X
如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
# d: Y/ F9 k5 i K4 u$ J
这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
4 y: {4 w9 ^3 k* I. ]; `
使用示例:
: k9 b) V0 ]2 z5 e4 v' z
' }1 l; P2 Y# d& H4 f" e" `
c
2 b7 m1 E3 e( P* X" v
Copy code
" \, K& p, b+ `. X; V. g8 Q
FT_Load_Char(face, 'A', FT_LOAD_RENDER);
, r! c& L4 c$ x p
这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
& T/ ]$ d4 W+ K
8 F1 Y; K/ c# D% Z9 b: r
错误处理:
" x, d$ ]8 q+ P% i3 q/ C: t
3 e4 [( c8 r2 ~( j& M
如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
8 _4 c o7 H4 v, x" c
总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
8 O( i5 r" K; {. ~9 O T
- d! j8 \+ Z% ~( e7 Y5 X7 O
代码
" w! P X; h: _, x" a8 J6 X# O: Q
% C: m9 D1 r* y
4 _ B' [' u" p5 L& T# t
4 Z0 B2 {9 C' @1 Q) B; G( l& N
3 f+ v) `5 G1 B i
#include <stdio.h>
( ?$ p9 R% [5 i! C; O" q [- D
#include <stdlib.h>
4 O& L( V# C: a- s
#include <GL/glew.h>
; |# Y/ A5 T3 c$ G
#include <GLFW/glfw3.h>
) I3 N" P* ]3 l$ k: y
#include <ft2build.h>
A/ B* ]6 H8 l% S7 D
#include FT_FREETYPE_H
+ o/ |/ M7 M4 r3 |" U4 o
* s& f [5 N6 _" B0 s+ @4 E$ o
// 定义字形数据的字节数组
0 b9 e8 T' A& |
unsigned char fontData[] = {
[3 L9 U+ A2 L' f
// 字形数据的字节表示
5 `6 h4 c' \' b7 |& r
// 例如,这里可以包含字母、数字和符号的字形数据
3 g+ v' J: t# B, a6 l& R& l
};
# v: T( |* v+ C: Q* J7 G8 {7 }% J& U& \
6 Z) e$ W* U2 b6 x) |. L
FT_Library library;
' i j8 I$ j$ [( V" W
FT_Face face;
5 d! n4 s- ?1 o9 v% t, R
GLuint fontTexture;
0 k9 K7 D0 v+ a9 F
: J! P2 o3 p5 I9 Y+ O
// 初始化FreeType库和OpenGL
; ^+ B6 q' d5 M; `
void initialize() {
0 P& c- ?) h) I! O* b3 o
if (FT_Init_FreeType(&library)) {
: Q) F; ` h0 @! w2 G
fprintf(stderr, "Failed to initialize FreeType\n");
* P9 d6 b' g; o" d4 W
exit(EXIT_FAILURE);
2 h, b* a4 h e |. b! V7 w
}
) k+ P" N, y. n+ Y
( R0 `2 B5 W7 c
if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
5 r& x) s, D8 j4 [% k
fprintf(stderr, "Failed to create a FreeType font face\n");
) L; J/ m- m g
exit(EXIT_FAILURE);
h8 I @! l; V
}
@0 Q* [. Q" E: Z
& B! U% k& ]' Z6 Y
if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
$ S. a6 Y% a( K
fprintf(stderr, "Failed to set font size\n");
! t, H+ N( H" C2 a j( H
exit(EXIT_FAILURE);
# ?: }( V( |# M% x( d$ P; a- }7 m
}
e3 L& a$ r0 x, D" b
4 w) K) d" M5 k2 m! G( _9 l8 @& l: e
glGenTextures(1, &fontTexture);
9 L2 C; }4 a5 x w$ `) q0 t
glBindTexture(GL_TEXTURE_2D, fontTexture);
3 B* `4 h# `2 F2 R5 P' V+ n/ N
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
% M, y5 _; ?: B2 F
/ F: R8 _& f4 {0 u
// 将字形数据传递给OpenGL纹理
) Q4 w6 x! W$ P5 H& b6 d
for (int i = 0; i < 128; i++) {
! K$ B4 J! k) b9 x, U% x: y5 M# O
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
- N4 S7 ?2 v3 B4 K
fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
' u; U* ?- n! X3 e: P. Z4 X H I$ w
continue;
- [ @* W9 r U
}
" I0 B; b" Q# l: P
* m* X. v) p/ B$ c, g, g
glTexImage2D(
, q% X" g3 |7 l u4 D
GL_TEXTURE_2D,
- k1 B- X2 D/ s6 H+ U$ t
0,
( A# ]& ^; F: @( f
GL_RED,
/ G2 u! K( T$ P+ G2 i; }4 w
face->glyph->bitmap.width,
- ~, V: d0 P. _. K6 o
face->glyph->bitmap.rows,
: U2 q8 X" {+ x A5 E
0,
$ v) F* R6 t# M) W1 B& a
GL_RED,
3 P) p& J ]7 ]) \
GL_UNSIGNED_BYTE,
3 o( ~0 \8 v/ ?! X& T
face->glyph->bitmap.buffer
+ U, f: a$ X* o
);
* s. i; W1 V4 f" m3 m
: J( M$ @; k2 l, E" Q
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
0 H# t3 {: |( w4 T
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
0 e: G ~/ P8 r, `5 ^, D
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
y: l$ X0 ~- F G6 Y
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2 W( t7 n$ H7 `4 r
}
; u. i4 m2 P. g4 g
}
% I8 c' K) i# f% H* i
# X3 C; |, O* P: W( K
// 渲染字符串
' }" C, s* x$ {! [6 v
void renderString(const char* text, float x, float y) {
( @- s1 x: q3 _. h
glBindTexture(GL_TEXTURE_2D, fontTexture);
: t. N9 Q: i2 M0 s
! b7 ~, D! V( c+ r, F/ R$ {
glEnable(GL_BLEND);
- n- R' i4 ~7 ^* B
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
7 m$ I: q, B+ Y/ I
0 p+ H- F# S4 k7 ]8 T3 B& P2 a# c
glBegin(GL_QUADS);
" k; w% f; g% q0 H V
for (const char* p = text; *p; p++) {
8 g" A+ N' N% F0 e
FT_Load_Char(face, *p, FT_LOAD_RENDER);
5 q! w0 d( i) ^) N m/ R7 m- F- N, A3 [
2 l ~& o% s1 `- p2 V; V( E
glTexImage2D(
( X, h. i% k' u1 B. E8 [7 c( w
GL_TEXTURE_2D,
: k% h* l. }+ w8 n7 A: W8 I7 k
0,
# k7 b; ]' @7 f
GL_RED,
& N$ ?" r4 {" y9 b
face->glyph->bitmap.width,
: g2 Z$ T- ], ^3 r2 `- C
face->glyph->bitmap.rows,
' ]. T- ~1 d3 p2 i$ l0 N! x
0,
# x9 ^4 ], P% X' s8 ~
GL_RED,
# p: ^7 F: S1 |* M7 x0 f" F
GL_UNSIGNED_BYTE,
( F! w5 X0 f: [& `+ A! G. H/ s( K
face->glyph->bitmap.buffer
! c! k0 g7 S5 I# O: l
);
0 U/ N/ L- \/ j0 r H8 P! s' V
- A- m! P7 L- g$ a. Y& U1 K* S
float xpos = x + face->glyph->bitmap_left;
2 A# ] o6 U& t1 ~. ?+ \
float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
9 x. h+ B# z* z+ h, y1 i; e
6 i" }' h/ y7 b7 L7 q
float w = face->glyph->bitmap.width;
4 u# V, f' d8 b( S
float h = face->glyph->bitmap.rows;
, K( V$ Y- A9 O1 E! p' l
& [3 W& h0 X/ S: S) v, i: M
glTexCoord2f(0, 0);
7 k7 x: x7 e! J0 M8 I
glVertex2f(xpos, ypos);
* ?9 v/ n7 n, Q3 S( Z( f
, R8 q) k& P+ d
glTexCoord2f(0, 1);
( S3 J& F; m( b! u( M _& W
glVertex2f(xpos, ypos + h);
: U* y% ?- S& {5 q; F5 g
8 Z: {3 p$ ^* f5 V
glTexCoord2f(1, 1);
) H1 R, p& K( p" r
glVertex2f(xpos + w, ypos + h);
+ u \! f1 T+ V- F
: v1 K. p: g8 g
glTexCoord2f(1, 0);
% ~5 j% N$ L* y5 Z4 U+ P' [1 B* l
glVertex2f(xpos + w, ypos);
& h- N% A' Y8 H
5 {2 L* q6 @4 |& L$ P% ~
x += (face->glyph->advance.x >> 6); // 字符之间的间距
/ \- {+ @ [# G" s B+ z
}
9 Y' A% U9 a8 e- C. ^7 j: U
glEnd();
- r9 M$ u6 l# p) [' H* }8 c
7 Q( P9 I8 [% `2 c. a
glDisable(GL_BLEND);
. v# O$ H) c5 M
}
6 p& T- X. _. A; F
# m1 K! R& M" b
int main() {
, i8 X$ J f$ O' f$ I
if (!glfwInit()) {
! |7 U& w2 K7 e V5 k
fprintf(stderr, "Failed to initialize GLFW\n");
( h& }" h$ W3 `4 J6 ^
return -1;
! H% J0 L8 d. i3 X! Z4 l
}
1 w( t8 U: J; R+ ^2 c7 w4 e
1 b! g5 H* G# g, O* ^) D& B
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
) E6 r- h1 J' e9 a2 S
if (!window) {
1 M- X9 h7 g5 I& |! |4 T; v
fprintf(stderr, "Failed to create GLFW window\n");
$ u( ]/ [5 T9 S5 f& Y B: u
glfwTerminate();
6 B/ ?% B' k4 V! @1 v2 ]! ?6 v
return -1;
5 T2 B1 Q; e! a( s; n
}
: o+ J' I- }/ G3 q' [$ d
: d I/ w" F. ]9 l% [8 d3 l
glfwMakeContextCurrent(window);
' P {. D, y. l( }; A
glewInit();
1 K I! T$ B& M9 B, K4 c1 p! q
. `' ]% y7 e5 Y# p h& N
initialize();
V0 o8 @$ x$ p9 c0 M/ o
7 u; w. p4 U6 f# m
while (!glfwWindowShouldClose(window)) {
% u) u/ a3 q3 j! r" Z5 F
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
3 b1 J( B' y2 X1 G
glClear(GL_COLOR_BUFFER_BIT);
' ^6 E; T" M2 z/ _
, o+ ^5 V0 w# g2 X
glColor3f(1.0f, 1.0f, 1.0f);
1 k9 A u) N' j
renderString("Hello, OpenGL!", 100.0f, 100.0f);
# \% ]2 B% C+ }. H7 D2 ~
- r% m7 [6 w( F M, \
glfwSwapBuffers(window);
% @" s4 E& T( O2 [% s% i* \' j6 ~
glfwPollEvents();
; Y& U$ K3 M3 [. y; v1 m" f, b! H* s
}
6 u0 n' s8 o* N4 ]
9 H9 R# c. L% @4 ~# w q; O
FT_Done_Face(face);
: T. q" ?% R" c; L& r& S; K
FT_Done_FreeType(library);
: _7 {4 ?4 J& W. b Q& T
$ A. w1 t% a$ ], [) m9 K
glfwTerminate();
9 i: f u5 y' B8 Z3 G# \
; A! ^! G i( W) {' W+ {
return 0;
8 \# f+ ?8 f0 t' ], }8 M9 k
}
& h' ]6 }2 c; E) D% Y
复制代码
" `" r4 y+ F; C
' j9 h5 [ Z* ~% Q$ g5 l! e
欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/)
Powered by Discuz! X3.2