本帖最后由 shane007 于 2023-9-6 15:32 编辑 " ~4 Y3 }, J6 l& P7 v
# ~2 M+ Q& U( L以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
) z6 M5 j2 t2 r, {本代码经过分析以及改写之后,将取代游戏原有的显示函数。
1 m# N# _% w5 j6 R1 Z2 m* _
( V& u( A( J0 x! ~! T* x9 C9 N5 x5 ~代码详细说明如下
6 Z0 S. ?4 p8 @7 f% |+ D# [5 j- @# h" O
- 在上述 renderString 函数中,我们有以下关键部分的解释:
3 W/ r5 s+ A2 K" k+ I" `
7 \% t6 N- P2 S" `3 _- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。0 B$ M$ q& K0 j; l$ a
$ v6 f; U! x/ E# @- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
2 |% s( h X8 [5 s$ B
2 G& d* [/ B9 R v5 d- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。9 ?4 ~9 i5 y6 E
- % G. y. z# W& @, b& T
- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:) K8 ^! ?0 X3 x0 @! a
( }; {' b, O. ^$ G- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
0 i y/ X7 F& v. X' D8 h
* E5 w) I! p' q$ H" i* k/ E- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。* X2 P3 ~+ X; B; N9 Z# Y7 _7 n
- * j$ W$ F! z# r: u# P) y
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
! u7 M0 s8 L# w7 X& i2 p - 1 ]1 p; @6 B+ u' \9 B7 ?, J0 z
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。7 F8 x* `# ]/ a1 G! V- D
- - E9 \1 Q) {9 K2 @' c
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
( d4 W2 Z; S4 h' p) V2 B - z6 A" c8 x8 m, J; E
- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
g. D3 R/ {; G5 O
复制代码
- M) M& m: O J E- {; Y& U; u( W& }
' @! S0 b/ g X$ x4 q6 `- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:
2 E8 c* N. d! A- J4 s* Y
4 s5 E( }2 g# L- s0 C* j5 ?- 参数:4 T% N! W _0 u' u- R4 D: Y
- 4 ]0 H$ l" i: v4 ^
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
- ^& Q5 D3 j6 |. ^ - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
$ G" x) A: c6 L1 A& n9 H# E& r - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
$ L) G- v E) N" | - 功能:3 q9 l' H. x4 Z0 T
k/ _2 E5 G) q6 a- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。3 j2 F/ T, t `% g: [0 T
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
D0 C) Y: t0 z; v+ u$ E3 x - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
/ M4 y0 e1 ^5 J4 E K - 使用示例:1 U. W! R3 w4 |! \; t& R0 w( ~( a, a
- 3 ?4 X7 {8 n) v
- c
F, ^, z; N; \, ? - Copy code6 h+ Z% [- h6 b2 [' q$ L
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);
) q$ G( x+ O0 V8 E - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。4 X% ?. J; L0 Q8 V
- 2 u( _6 ~! B" I4 S) I! a p
- 错误处理:8 i1 E5 j( I! c! B% S: a
- : Q' @6 E, [, X
- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
2 w) @, [7 B" v4 z% J1 u1 n - 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 6 h b/ e1 P& U5 z
$ m" e: M# |. o8 B代码( Z& _0 x" `5 e ^7 _0 z" g6 a
1 X1 U- \7 s U
! j! f9 l' V, j- ' S) k* [1 w7 g+ l: K
- 3 n, S/ e$ a7 E7 _0 c8 b' k" e
- #include <stdio.h>
8 J( r+ R' ?0 V/ B! x7 w - #include <stdlib.h>: E% X, p" h0 ]2 U2 [7 S% c; A
- #include <GL/glew.h>
' P/ L- O# q+ l& a, P - #include <GLFW/glfw3.h>
( A& \! D2 K' f7 e7 N! g - #include <ft2build.h>
1 D4 v4 E$ `, ^" O- w - #include FT_FREETYPE_H
: }" I( I8 A. ^
; N, n- |4 V. `9 i- // 定义字形数据的字节数组3 z& T- L- y* M% Z7 c0 W: D
- unsigned char fontData[] = { s/ E4 I1 j/ y+ o
- // 字形数据的字节表示4 |3 U- D" y9 I$ e V
- // 例如,这里可以包含字母、数字和符号的字形数据- i) D: k" `% T3 l- u4 s7 Z& U
- };7 W8 P; f# k9 v w. B6 O6 L
- $ P- e( [4 {- _+ i
- FT_Library library;0 o/ }0 ^, W5 L
- FT_Face face;
& M% O# Z7 Q2 k7 P$ G - GLuint fontTexture;
% Z1 ]* W7 L9 c7 C0 w# V
2 q4 U7 \7 T$ \# O# p. ~% c' @- // 初始化FreeType库和OpenGL
# K( e5 k! E( v1 n1 |+ @" t - void initialize() {# F3 N9 W y, J4 Y8 B
- if (FT_Init_FreeType(&library)) {9 v( x! R+ @$ `; j; \) W
- fprintf(stderr, "Failed to initialize FreeType\n");7 s- l$ a) F& L
- exit(EXIT_FAILURE);
0 O( D2 A" u/ M% Y2 d - }
7 g4 d. g- ~" |, C
6 ]& A$ n2 V) b* \/ h$ h+ v- P! k- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
1 V) B9 R; ?' a( I, O" W - fprintf(stderr, "Failed to create a FreeType font face\n");
3 N( e. L6 ?( r# i* J% I; _0 O - exit(EXIT_FAILURE);
8 D2 |3 w' j: E) D - }
' r; P U/ }, }; }4 y1 d - . @$ E& N) u+ o
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
3 | q8 X- g, p3 Z: j - fprintf(stderr, "Failed to set font size\n");
: r' ^4 [2 B* B" x7 e4 b' g; E( i8 _ - exit(EXIT_FAILURE);8 ~- U, i. n* a1 C+ O
- }
3 y e. Y$ @2 N+ j! A - . ?' I5 m3 Z( E( F% f
- glGenTextures(1, &fontTexture);) m4 O7 R+ e# \6 `1 E
- glBindTexture(GL_TEXTURE_2D, fontTexture);) U* F! F6 U+ o3 Q# \9 I( L4 {- L
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);# W/ z, `" Y9 h
7 ~+ h# R+ [6 r, `8 H- // 将字形数据传递给OpenGL纹理
" X% j' X8 h4 e, y* ^( c5 s3 n - for (int i = 0; i < 128; i++) {
1 |# C1 ^$ c8 b. P - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {6 j- @$ ?3 O3 D' m
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);; J" f6 G {8 E
- continue;3 \* G# y& _; Y% H0 Z; }* D4 u
- }, a. S7 d3 C, u! I6 o) |: r
0 w# Y2 C P6 s$ c- S8 @- glTexImage2D(
, L8 l8 C3 B9 J4 b - GL_TEXTURE_2D,
% Q! g V# l( w) U - 0,* Y+ Q! S6 a! j& P( ]. w
- GL_RED,) M: R0 l& [- f, e' t: i* ^7 l
- face->glyph->bitmap.width,* V X5 z# |* I, }
- face->glyph->bitmap.rows,
9 ]8 ?' y; N6 G6 c6 z - 0,
- j& E% B& m# w - GL_RED,' |# Q6 E9 m- f# \4 k5 O
- GL_UNSIGNED_BYTE,- j0 r: ^. u3 {8 X6 e5 y
- face->glyph->bitmap.buffer. k$ c3 J( B, x2 u8 q
- );. q# c! c+ K; J0 g4 u! Z: D
J$ P: C; B! S- N% M- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);) J! k* y E# r: u6 A
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);- o9 _8 U/ ?+ P5 v4 P! m6 I
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);6 ^$ J- b7 @. k' }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
0 H# n8 ? u4 } - }
# j& W+ ^" \8 {$ l/ ` z& C - }* s+ D; d# l, U* M
- : }8 P$ Y8 n- B0 A
- // 渲染字符串' G, G+ v0 n/ v+ G1 v
- void renderString(const char* text, float x, float y) {
' s+ f7 Q" V, j - glBindTexture(GL_TEXTURE_2D, fontTexture);, N: a: Z$ J# G3 v
, Q. t6 l: m' D$ P- glEnable(GL_BLEND);9 ?, b# j2 h+ L% Z1 ^
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9 F% k. M7 \5 t& ~; a9 q
% A$ Q8 @' C: o1 m' X- glBegin(GL_QUADS);
& b) R# t5 T# A9 C- \4 F" G, H$ | - for (const char* p = text; *p; p++) {
8 Y& c' o# ]7 p- y1 ]# Y - FT_Load_Char(face, *p, FT_LOAD_RENDER);
, @4 x" n! d$ b7 S2 G: A
I% ]- j* i; m- glTexImage2D(
1 w2 i, \; i2 M, g0 o+ _ - GL_TEXTURE_2D,
0 q: Z9 n: P4 f' T; ]6 U# ^" `$ k3 j - 0,
. {* T, J& k- n2 @4 u- S! Y1 { - GL_RED,7 `0 A0 B4 O# F! x# t6 t: [* L% P
- face->glyph->bitmap.width,
* m$ O2 V7 D/ t" Z: x7 ^) ^% \ - face->glyph->bitmap.rows," Q2 F! G. m9 F* A7 r
- 0,% H: B/ u+ p# D2 N& j4 X% T
- GL_RED,* _% B o" F9 g) O; p
- GL_UNSIGNED_BYTE,
0 X7 }" l" E3 h1 P& ~" ~ - face->glyph->bitmap.buffer
5 _$ Q8 _6 S5 c8 W& v( c - );: I( t9 b" x" h
& x# A- e& r8 a! p. |1 K J6 ^- float xpos = x + face->glyph->bitmap_left;
0 N; @4 R3 t6 g7 T @ - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);* D$ A: x1 \& o% K: f1 |
- ; p. S( z* c: ]! \, l1 T+ @7 ^
- float w = face->glyph->bitmap.width;
4 A& h: I6 w' _6 N - float h = face->glyph->bitmap.rows;" T: L8 T* |3 [" N
4 b# u- s6 U ^) E2 Y1 y- glTexCoord2f(0, 0);
7 D+ D: A+ B0 J# `: R3 ^ - glVertex2f(xpos, ypos);' F3 G7 y# A5 d/ U ^
" b7 Q2 O8 x0 R+ ^, I* K# P8 A. L1 f- glTexCoord2f(0, 1);
, Q% x* C% L% i5 V0 m. F& w4 I8 t - glVertex2f(xpos, ypos + h);
2 B" B! ~3 _) I) @1 d n! _
5 p5 {8 {! Q* Z5 C- glTexCoord2f(1, 1);
/ a% {8 k7 W# G D - glVertex2f(xpos + w, ypos + h);
3 a( G5 K* c/ q. u
% Y0 n# b* D7 ]6 k- glTexCoord2f(1, 0);
% y8 u& A$ Z2 L. z& p - glVertex2f(xpos + w, ypos);
7 P D- M; V' E0 D, H. ^/ g - 9 ]0 F! E1 U2 E3 e. K5 F; N
- x += (face->glyph->advance.x >> 6); // 字符之间的间距
& d/ P/ V4 \2 G* g5 A. o4 f - }
+ x% c+ v/ v5 |" ?2 H0 |' `6 i/ D' A$ m0 I - glEnd();: t( U2 X4 \; B# O! _) ?" I
8 l% x- G6 W4 n; o, w4 {: i9 w- glDisable(GL_BLEND);1 r- C# }4 Z9 t: P. L
- }5 X* l' \' ^& H( P1 V
- 0 u2 C! o. R; J0 `: k
- int main() {
% D( \+ G, u$ S8 N/ s) [ - if (!glfwInit()) {
$ v7 n+ X( t7 o$ F- ` - fprintf(stderr, "Failed to initialize GLFW\n");' W V7 e `& ^3 }; n7 U# W
- return -1;6 d1 C& X G, W/ f. W+ L* c9 Z
- }! z0 Y: V1 U/ B
h, s B2 u8 T1 b/ @- M- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);7 A8 @- E, v0 Y
- if (!window) {4 z9 \/ Y' K! B' ?% F& H9 [; M
- fprintf(stderr, "Failed to create GLFW window\n");8 e2 T) i" R9 M
- glfwTerminate();
4 l3 z& E+ t) S6 p - return -1;
; h) y6 |- I6 K9 v: E - }& c; a! K# D8 v4 ]
- 0 q0 J( A+ b0 s. m
- glfwMakeContextCurrent(window);1 t: S5 Y9 O$ \8 _ A7 p3 l. `$ |0 N
- glewInit();5 ^# Q" ]$ q$ ^' | B
- 3 o( Z( v! _8 u' K" V
- initialize();* o2 R7 t' e5 M; f' G
- ) _) I; f U( r/ R$ |: D4 z' b
- while (!glfwWindowShouldClose(window)) {1 e6 L( _- d6 v
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/ V/ f: N9 I- ] B1 c - glClear(GL_COLOR_BUFFER_BIT);+ m$ J% S& d( f9 L: U
9 J; q1 ^6 V- d- glColor3f(1.0f, 1.0f, 1.0f);0 x# H2 o \( s1 \' }
- renderString("Hello, OpenGL!", 100.0f, 100.0f);7 B1 _1 O5 r( K8 `: g) s( T
- : \$ `! Z* y# ?! O
- glfwSwapBuffers(window);0 s( n8 T; f" h$ L8 i
- glfwPollEvents();* }+ U7 V A i, w
- }
# F; D; i, K5 o% H% p/ O
@5 N0 l7 [6 e) g+ N* s; ^- FT_Done_Face(face);) S6 e+ w. z6 S- F; k6 ]1 t1 ]
- FT_Done_FreeType(library);
; i! b: w! x) F
( ]! ]" n( |6 a% y- glfwTerminate();
9 ]2 N% W% C+ K$ [; y6 X
2 b+ u, l* U% u/ Z2 T- J' l1 K- return 0;
, k5 \4 z' R" C( B4 V - }
|# N( a/ I; I+ t m
复制代码 # r6 S2 u" M, |4 s! ^& _
1 V8 @) X" C& I( ^
|