本帖最后由 shane007 于 2023-9-6 15:32 编辑
/ \& V0 U/ Y+ h% L. `, ~8 |$ d8 t& I( I6 R
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
; ?( g" s$ ]# i9 ]2 g' g5 v. s本代码经过分析以及改写之后,将取代游戏原有的显示函数。
4 P% H/ @# |$ |( K3 A- R, ~' K8 H, M
代码详细说明如下
& u+ j* X2 S0 U; [0 X- {/ O# K. Q @6 }4 ?9 n; @& k
- 在上述 renderString 函数中,我们有以下关键部分的解释:, t s0 }5 I: |7 e; {! Q
; C; y2 k. C: L, y0 q+ v- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。3 e" o: I; [! G/ @4 F- }
$ r: G* f3 ~. b* }) `% O; u$ Q* T/ y- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。2 U" U, F0 u2 l+ w" {: P
! t) T$ K; P; K$ D- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
U5 Q& m- l4 ?! a
5 Y6 L a7 K$ [- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:* R! B p$ h6 ~( J$ y$ Y d2 l
( H. @ [1 ]- Z7 ]- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
' w) E2 N0 f; X& I( Z4 T4 k7 }
$ J# J. _$ l$ i9 w# ~9 {- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。% w3 k& B( v( Q+ ]4 i% v) b% a4 q
0 b+ _. l4 L" D% p9 u- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。; M- [$ ~: n: T: X# c5 o* _4 x
) B5 Z! P7 f) b8 D- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。$ W4 ?9 q* n; D: h
- 4 Q2 Q$ V# W: D! |7 i7 P
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
. e5 y( K% P3 u4 n' g( k
# u6 m4 j8 [' {3 k/ e: g0 ~7 M0 F- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
% Y' |* d5 `% S$ z, L, Z# {3 w/ \
复制代码
$ T/ l8 v5 R" I* O0 j; T- ?5 ~3 x0 L: B- L4 l; P3 f
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:
' o, y9 K5 V0 J/ m P6 f( }
- A# H9 f/ z b, m5 Z0 X0 q8 X- 参数:+ i: a/ S4 D" b' W' R
- & _+ `% K/ Y3 Z
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。8 E' V8 \ K; c( T$ q w
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
0 E: g2 ]6 p2 U' b. ~( f, ]; X: G! m - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。% S" [: m+ o, g8 Q% f
- 功能:
; R! I2 J. F1 l$ b2 o/ r2 f+ K
3 S+ U3 {& W/ u# ^; [2 w% C3 J- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
& X$ a# H! w. ?* j3 J! | - 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。. \: W) Q9 T. I! w% {( c7 x
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。: v, v2 i2 e3 J2 s% u2 P7 o) F
- 使用示例:
: t6 t7 u/ I% n - - u D3 o( L7 M! q
- c
. Y+ D0 V/ C. t - Copy code" b+ x+ S; m+ p1 |: D0 v" B# b
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);& y' w1 u3 |0 `/ [
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
/ I6 B& m6 q% H, _! ^+ H" \
9 f- C5 k; L l. v1 ~- V q- 错误处理: ~' f) a" R; J7 ?
Q" I" P* x; ^; X; n# c- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。, }: \) t" i7 s& ~% ~
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
3 g( B/ W2 I3 S8 x' [% H- [& C6 p8 I1 K# J9 X7 Q- J! x1 [
代码
" O; _" h4 l+ p1 d# @! {* s5 x1 O$ n
- , q7 O. \* r6 F6 [' n- z
: {- {% Q+ C f. Q8 g( B
Y* U% |$ R, T0 f- #include <stdio.h>
% @4 |0 h$ u \, a - #include <stdlib.h>
1 D5 `" {' h# ` - #include <GL/glew.h>
) |; C; O% s1 V. U/ u - #include <GLFW/glfw3.h>1 L, z p" r( }& g- ?, v& _
- #include <ft2build.h>
3 K! c# y D! e) W7 r, ^& U - #include FT_FREETYPE_H
8 h! K, k: e' k+ k
! D6 i% m7 N4 r9 `- // 定义字形数据的字节数组, n1 K2 \2 ~5 A# R$ F
- unsigned char fontData[] = {
! G L7 c& E0 J8 S/ S0 q - // 字形数据的字节表示, D/ h# p' l$ Q0 H D( d: N7 A2 {5 r* ~
- // 例如,这里可以包含字母、数字和符号的字形数据
0 m5 s7 M( E3 A) q B' R - };0 @: i, b* K5 t+ {
- 0 e+ P6 Y; |" W7 Y8 a' k* u
- FT_Library library;
5 T( d4 d5 S, |7 p - FT_Face face;9 x% g( h7 S& b* n) n/ _
- GLuint fontTexture;' U" T; z( d! v: ]! H" b
- & E& F8 [% j* E* ?2 f# d. `
- // 初始化FreeType库和OpenGL
% _, s( W' v- m7 R$ V5 x - void initialize() {; O2 ]+ W- B0 k! R" \
- if (FT_Init_FreeType(&library)) {
+ Z, r" j' q. U3 M/ N( g - fprintf(stderr, "Failed to initialize FreeType\n");
4 X) F6 d) V2 L8 m! E6 @ - exit(EXIT_FAILURE);
3 k: J0 b/ c! {0 [* Y - }
4 @% T6 s: `$ q& y - p1 V% C4 O9 S
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
* x# y2 D+ |* H - fprintf(stderr, "Failed to create a FreeType font face\n");4 |1 c5 o. H) p' n5 k
- exit(EXIT_FAILURE);# b5 S! t* Y6 g5 a* Q
- }
9 y$ m' W6 _, r9 G* }" T! m) O: c - ( ]3 U$ ~! o1 w- ~7 r1 {7 _, D
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
& c$ b8 e; w! N2 P - fprintf(stderr, "Failed to set font size\n"); i# v+ z8 `6 m/ z& E j# W
- exit(EXIT_FAILURE);
6 O J/ R9 k' q: _1 }; X8 N - }; t0 }6 }* W1 J. u$ h F
7 L; B) C& b* N2 }8 i7 {- glGenTextures(1, &fontTexture);
! d! b' w' X" L) j0 r - glBindTexture(GL_TEXTURE_2D, fontTexture);- w! t5 _- t" ?( {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
# \0 _/ F4 g1 H, T7 P; i7 o( ]
/ Q! A) S2 z$ Z- // 将字形数据传递给OpenGL纹理
. i3 H/ D8 P7 g/ b+ \ - for (int i = 0; i < 128; i++) { k# K3 h3 J( E( x6 D
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {3 d" K6 H0 i! |, _ X& }% \2 ]
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);! I: Z8 F4 r: W8 u$ Q
- continue;
* R% ?* B& F) [4 I - }2 d' ~% n8 e1 I+ l/ I$ p4 ~8 c* x
- + [* Q* I0 }0 V% T$ B
- glTexImage2D($ j' ~$ h+ O; k
- GL_TEXTURE_2D,% a. p8 O. }( a- i8 ?+ l
- 0,
* @% W) S& v, s$ m* t, n+ x; E - GL_RED,5 d7 T3 K3 m5 w( S
- face->glyph->bitmap.width,
. L0 q% ~0 Y+ f2 q9 h7 D - face->glyph->bitmap.rows,
: b9 j7 W% W% f/ j' Y - 0,6 h. F$ E. Q& j X, X. `% M
- GL_RED,
9 A7 d# j. q7 Y$ v/ A0 h - GL_UNSIGNED_BYTE,; \) p2 b. P1 \( U. h& f
- face->glyph->bitmap.buffer, l$ B$ F; m+ `: v& X6 ~$ ?
- );
0 B1 R8 X$ `' x; C; u
t' i$ C I5 N7 N, \5 X- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);& C4 r K$ H+ _, a( T3 e) H
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
& @! m' m3 V3 i2 p5 y - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
* y/ w& @7 a" X- h, J9 | - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);: v6 i- ?' | G2 _3 o/ ^# S* X* g
- }
: i2 q* i: ]; W- n p7 I - }
+ }( z6 N, o0 C* u3 p0 ? ]& W - $ M. n2 E& z/ g- Y! p# h
- // 渲染字符串' z# x5 B, ^% f9 i; ]- z4 f
- void renderString(const char* text, float x, float y) {
d& P9 o8 F% o0 o) P0 l; z - glBindTexture(GL_TEXTURE_2D, fontTexture);! C; e2 q$ r9 g0 [: m
8 a! e3 a% z4 C5 I- glEnable(GL_BLEND);6 z" |. b+ \1 D! H
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
& c# V) S7 E: ~- R! w: k3 T7 f
E; {' Z: F- n# d; w- glBegin(GL_QUADS);
3 I- A# k8 L0 w; F+ p" d0 ] - for (const char* p = text; *p; p++) {: O" }+ `; r9 T- i: F! L/ }
- FT_Load_Char(face, *p, FT_LOAD_RENDER); r- \9 M4 z8 V+ d( h
& T! A4 `0 R- S$ X% U7 o- glTexImage2D(
: ?9 T/ E8 M1 l7 K - GL_TEXTURE_2D,
7 g0 {# L3 e1 w& r( `/ E9 P - 0,- O2 P6 `2 ~* e, Q: q8 ]1 f& k
- GL_RED,
% H. T) u, q5 t0 h& w3 z* C' Y) h - face->glyph->bitmap.width,
3 e1 o# X2 n" c/ e - face->glyph->bitmap.rows,
, Y: X7 B, q% i7 d - 0,
& c& _7 a- N2 P2 J. w! S - GL_RED,2 K0 @. i0 w) Q) v! Q
- GL_UNSIGNED_BYTE,; D& U! W5 z# Z5 }2 A
- face->glyph->bitmap.buffer
% \( A6 g+ t b- J6 c" l5 c - );
3 S* S! i% q3 i( a( U6 ~
- J9 w: O( G( T L) k/ m+ I- G- float xpos = x + face->glyph->bitmap_left;# O p0 n& o' |) x Q0 E
- float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);0 E/ l! r. N$ C6 F9 J
- / U" v6 Z9 w0 D
- float w = face->glyph->bitmap.width;
3 O7 |9 N- K3 `8 t0 E t# j - float h = face->glyph->bitmap.rows;( m# @ ?2 J- M" ^! z
; G: ]+ {0 x, [7 m- ^" Y- glTexCoord2f(0, 0);3 K# k% z+ k) I1 m. l. i
- glVertex2f(xpos, ypos);' n' i) Q) c: |7 P5 z0 R; E
- + n( U9 b0 O% F# P4 @ m/ p3 d
- glTexCoord2f(0, 1);* v+ |8 W$ c. q9 V" X
- glVertex2f(xpos, ypos + h);( Z! }& @ S( B7 |0 `* Y" R) u
- e! W5 R2 A3 {: f$ P* u) e- glTexCoord2f(1, 1);% A% k2 [+ Q, {2 J6 [* y( c
- glVertex2f(xpos + w, ypos + h);/ w& ]8 o4 F: t
- 9 _, @# E2 K: g3 O, K
- glTexCoord2f(1, 0);
0 G$ N o! `9 V1 L3 } - glVertex2f(xpos + w, ypos);
+ ~1 m9 h) f8 c* d
# v& p G0 n" s$ l8 V' h+ A' S( k- x += (face->glyph->advance.x >> 6); // 字符之间的间距
2 \! u* t9 V9 p V# S - }- j# ~, U" _/ d4 U
- glEnd();3 k3 [, s1 m$ h* f0 p% n& h) W
- 1 L3 G5 ~* m% `" Q8 d
- glDisable(GL_BLEND);8 I- c+ Z9 i7 e, ]
- }: z+ f1 g% H M5 p0 t) y
- % @/ E: n2 K N, u2 A1 _
- int main() {
' r" z; i& C1 L. O h! K/ ` k - if (!glfwInit()) {
6 E& n \+ K& q' F# Z+ x - fprintf(stderr, "Failed to initialize GLFW\n");
. }# M" t$ W% [2 o& {; G+ K/ U - return -1;" T' H/ P9 z+ q
- }% X; y3 l- ?4 O8 r. h, s9 T
* [& R5 E( |$ }0 l- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);' V7 K$ H0 o! ~- J* a, B4 E) z
- if (!window) {, f! X- l9 m0 v4 X
- fprintf(stderr, "Failed to create GLFW window\n");3 R# |" p! N: g! X9 ?2 Z
- glfwTerminate();
0 C* k0 \1 H- Z* E# d2 V; K @ - return -1;* p6 d5 T) ~, ?' F( C7 ~; Y3 {8 g2 }
- }. F0 W$ t: n6 \/ I; Z: u
7 I) Y7 R, z ~2 k# m1 I5 T- glfwMakeContextCurrent(window);
; D/ E5 i: n' _9 S; E2 ^ - glewInit();; d) P' U; y2 n: D; f/ T
- ; S8 t; ` o% r4 x
- initialize(); V8 [8 ?6 k n. ?4 q
- $ V& b1 v: K+ q0 P8 r# G2 u; O4 v
- while (!glfwWindowShouldClose(window)) {
; k/ m3 F( L# N; q - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
9 e8 u6 a8 D/ ?" i* I7 } - glClear(GL_COLOR_BUFFER_BIT);' r) J' f2 V0 Z# I# f' f
' i' R8 k; c% W0 |) U0 N! X; \* z! w- glColor3f(1.0f, 1.0f, 1.0f);
E4 E( q4 N2 Q0 P& H5 u - renderString("Hello, OpenGL!", 100.0f, 100.0f);9 Q. a* r! g' }# j' F( ]+ l' w
: S! p6 \/ ~: B) S- glfwSwapBuffers(window);
, l. x. U0 ^ W* K& x o3 A - glfwPollEvents();
4 t1 A8 B2 e+ B9 {# X - }. T; X( J0 M; t }" a
+ X( P& X+ g( w4 M- FT_Done_Face(face);7 f: h8 f- x# G9 W% X! F) Q
- FT_Done_FreeType(library);' [+ E0 r; G2 @) E% J8 H) Z; x
4 \* T' K6 G8 n# ]; d/ ]- glfwTerminate();$ F& S8 y: I H' Q: X1 ~
- 4 C/ Q% R) D6 Z( Z& q5 {, F( B
- return 0;5 T' R: n+ U( |& `
- }
: Q/ [1 z0 I* v4 J
复制代码
, Q. i! u) u8 U1 X& a6 Y. w
D: X s& v$ k% K3 i |