本帖最后由 shane007 于 2023-9-6 15:32 编辑 0 N8 b, f3 ~( Z2 n& h$ y2 u7 @
5 Z' p# N2 T, k! B! u3 ]
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
6 [" R* k3 N7 L b本代码经过分析以及改写之后,将取代游戏原有的显示函数。
' v% p$ F& G( N# f/ {/ ?; o3 U. l" X# j% @; U
代码详细说明如下
5 f- \& h' k# K! ]! e# ^' D$ T. |% |" O/ p9 [ m8 E& x% q
- 在上述 renderString 函数中,我们有以下关键部分的解释:
5 I* J$ t' X0 N6 F2 m - ; b! s1 b( P8 D% z' e% H
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。% \6 h( h4 J7 d% s' k5 T
- . Z7 e6 M3 L; E6 g9 ~. t! m7 {; ]
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
: h* O1 z2 v) s- g8 i; k- ^ - % t' D' v1 Q/ [* p# H! E/ V
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
1 {- A4 F8 V% F. _, e0 m
: u, e/ }: o" e# Z: e, l# F- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:+ a2 A9 t" ?: x$ `6 `
# G" {$ o9 a4 Q$ ^8 l) X! I- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。: K8 v' j c( w) Y6 z8 U
- + B3 P* Z+ d8 i! g g
- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
/ y" W# F5 \' D S! @7 n: f$ O
! b. X! n& w+ t9 T- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
4 ?$ H7 K7 E/ H1 P: l- j
1 o* v( X" x' H% A; ~, Y- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
) F, H. U8 M3 a% _4 E
* v( o# g, R6 a- N3 z- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
, p- C! \ R4 h% o9 b: y" H: V - 7 K* d! Z: [" C0 D4 b, ? P
- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。5 x: ]1 U2 @$ a C
复制代码
7 J; ~/ a2 X2 a: ?1 k& X
( N5 G( l% T p4 S F- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:6 R6 q. Z3 g. L( r% R9 \: F
* j7 `5 g% d- }) u. P1 E g0 i3 U6 J% ?2 |- 参数:+ A* z6 B( n5 q
- ) E7 W9 s4 j( |0 N
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。/ G9 s! A) p# ]: O/ c
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
. m/ P0 s5 Q* a h/ {0 E" k - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。6 w6 `; n$ @" h0 }
- 功能:
5 ?+ ], D& k# W% b1 f - & u% e W+ b7 r% q) F& T4 Y0 |3 Q
- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。; v: w, x" a2 {- P. L
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。- }4 k; ~0 j5 N9 u1 x
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。7 k& X' o5 y+ g- x8 ?7 v5 R1 M) A
- 使用示例:0 q! p9 [4 G" }
" \+ `7 X# a1 O$ a2 O& j- c
: C0 |: u- O, H# ` - Copy code
5 Y, Q8 L# {% N- B+ P; R - FT_Load_Char(face, 'A', FT_LOAD_RENDER);
* r$ C- _! k- q$ |; U$ e/ z& I8 [ - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。" u9 u9 v" }4 }8 u% s6 G: X
, b$ Q) V* f7 B8 Z- f# w1 X. _- 错误处理:
/ C Y4 D6 H; V- H
' c1 W+ q+ X9 j* B- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。* [ E0 v6 h4 c9 m `+ ?
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
# _4 t1 b3 X" C( e8 D9 K) _: g& d$ [( {7 W9 r
代码
- l- n" Q) U0 {8 y8 A% T$ v2 @ M, ?5 U+ C
- 5 O# [4 D$ n6 V2 s
* j6 j( V; ~* P G$ H- ' Q3 M( g2 V6 T' |9 I
- #include <stdio.h>1 G6 N; { Q5 u2 n$ u
- #include <stdlib.h>
' O9 N% `( K; _0 f - #include <GL/glew.h>' g ~4 T' \/ g) P+ O+ L
- #include <GLFW/glfw3.h>
! L- n; ]! ~; m - #include <ft2build.h>1 J$ _( S* Q- q! `- L9 @6 P: p& C
- #include FT_FREETYPE_H' Q) {* {* a: r% C
- F$ ~7 ~: g: S8 n, p# ^3 I2 a
- // 定义字形数据的字节数组7 P" H2 h( h# c d
- unsigned char fontData[] = {
5 c/ E& E( k X. Y: n - // 字形数据的字节表示
! }' `& W+ A7 O* X2 J1 ] - // 例如,这里可以包含字母、数字和符号的字形数据
' h T' i* _! Y/ j9 Q3 r. d - };9 w# e$ o2 W/ C! F
- / |" s+ x2 b* D0 w' j
- FT_Library library;
; M6 l, ?$ ^# h - FT_Face face;
) Y" a( N6 z( }7 c! l! @ - GLuint fontTexture;
7 V! \, U4 ]6 G - ; b" ^& N: T+ n" o# H+ I3 P
- // 初始化FreeType库和OpenGL1 j, @& T7 t$ i$ a* I( H0 O
- void initialize() {; r6 f: Z+ r3 S
- if (FT_Init_FreeType(&library)) {1 D3 A5 |# b) @
- fprintf(stderr, "Failed to initialize FreeType\n");
. x& s9 O' F8 n- F& o. ?) i - exit(EXIT_FAILURE);
" F" p8 Y1 v" O$ M! M. E* [ b - }
1 I; l/ V4 B( g" b n9 A0 Z% O - 1 A/ G; }# {4 p2 V7 B+ x
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {# Y; ^; `( j, D0 B
- fprintf(stderr, "Failed to create a FreeType font face\n");
% t# h' F3 R( Y# k4 Y - exit(EXIT_FAILURE);4 ^# z" E/ z; o* t+ f
- }7 ^# A) e, D3 h# c
# G5 M2 a: T/ o0 A- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
; H# u- {5 \; g+ l0 K. Q: R# u6 N - fprintf(stderr, "Failed to set font size\n");
. A' R W6 _5 e$ R4 w - exit(EXIT_FAILURE);8 H/ u% v' g( N
- }( ` l8 @( P6 K: F+ t' Q
- , [ e, T" F8 D; G
- glGenTextures(1, &fontTexture);' ]4 \. f: b( Y8 P: r
- glBindTexture(GL_TEXTURE_2D, fontTexture);
# i8 a3 s9 L. w3 Y( ]! W0 p - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2 a/ O- B0 S" }9 ~: e( z+ G
% ]: R# |, \) ]! m/ o3 V) v- // 将字形数据传递给OpenGL纹理' [9 N% r( P4 N* M; D6 C% L) W, k; @$ {
- for (int i = 0; i < 128; i++) {
1 |2 ~: @5 ]. W7 F/ N6 ? - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {8 \8 H F# G& ~8 k
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);, ^6 _$ r4 P9 R8 ?: t, j+ k5 @
- continue;
' s' ?! S' S8 C* e6 r9 o; V8 O - }
1 u' F( F# T. [8 V7 `6 z
" R$ r. e) j/ K- glTexImage2D(
( l. O9 t4 _: M( j; C - GL_TEXTURE_2D,
: L. s" C! k) a& {' W7 {: Z( M - 0,
$ L! {4 D! q: w8 f$ h; q - GL_RED,
$ F& ?/ A' {7 Q - face->glyph->bitmap.width, T6 z* t) s* \* Y% P
- face->glyph->bitmap.rows,1 u _$ P9 T& c5 l6 |: s8 S6 s
- 0,1 W! v6 r1 e4 j2 J% X a0 i
- GL_RED,
$ X+ i0 A5 z7 w2 D* U - GL_UNSIGNED_BYTE,0 B9 t# H% V7 t5 L
- face->glyph->bitmap.buffer
# F7 e* Q" g- r. s9 ^! _ - );
# i9 J+ c# S# k! } - : ^- t7 H! G! g1 Q' I2 x& z8 S
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
9 ^1 t9 ~6 i, |$ ^2 J- ?9 m0 G - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);0 J, w8 s+ W) V1 |
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
! E. @) e' }3 C7 S/ c: D - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);0 m$ ~$ {3 c. W2 R* n: Y( N
- }2 k9 P( B* h0 p% B
- }# K! P, d) h3 j* N
- 4 V1 s% s* C. s: Q& }) f
- // 渲染字符串
9 }2 |6 v4 _: y# P6 M3 ?9 l - void renderString(const char* text, float x, float y) {3 c1 a3 w+ a' U) x7 I; {2 l
- glBindTexture(GL_TEXTURE_2D, fontTexture);2 W& r! N, h+ z$ ?) L
- 1 R" i$ f; o. e
- glEnable(GL_BLEND);
0 t: v: l9 q4 y2 F0 o9 _- F - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);) }0 `( Y- Q0 d! p
3 E) V; o: P% J# e6 b- glBegin(GL_QUADS);# m8 M3 [$ q% O6 a6 d! K/ L& M+ D
- for (const char* p = text; *p; p++) {8 F" H3 N4 x6 h q2 R
- FT_Load_Char(face, *p, FT_LOAD_RENDER);
# i* x" X6 D( c - ) d1 @ W3 l! k1 w: x
- glTexImage2D(
- c6 X( i4 d4 v, {( |( a+ X - GL_TEXTURE_2D,
% ?4 v1 @7 G2 ]2 K - 0,2 [( M) X3 p$ @; y; B# x
- GL_RED,& J6 B! d- }! G4 E; I0 M
- face->glyph->bitmap.width,
% X8 R i7 \ p" k3 P - face->glyph->bitmap.rows,* D4 m; o/ a; | a
- 0,+ f! s G$ y$ }9 h$ U# ?! M6 M
- GL_RED,
1 V6 X* {0 N. [1 G u - GL_UNSIGNED_BYTE,2 T! x2 x; B5 X* x
- face->glyph->bitmap.buffer
/ O# y; ~9 G- I - );0 { ~% t& _/ D6 x# {3 \
) o& V: I; X. ]- float xpos = x + face->glyph->bitmap_left;
) u* j5 j. F% X$ A ~# n7 B - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);6 {7 P& j3 \0 l9 g
& G2 D6 {) _# U, b- float w = face->glyph->bitmap.width;. W% a+ n# T3 V- @7 }" L& C8 ?- f
- float h = face->glyph->bitmap.rows;) ~' u+ k! K2 S% ^9 `8 c3 h
- * u/ G9 w7 a0 }5 J2 N: j- F0 I
- glTexCoord2f(0, 0);
; i2 K U1 N" ^( y% N3 n - glVertex2f(xpos, ypos);) \) R ?! \: I- ]
- 1 K: |. {! e5 {! f$ `7 t9 U
- glTexCoord2f(0, 1);* `0 M4 y: Z. _6 \# z2 ~ g
- glVertex2f(xpos, ypos + h);
& j) f- A& g5 d; k3 \ - 5 g4 n2 m) q: V2 n7 w' x3 U
- glTexCoord2f(1, 1);8 B0 W; J: e1 ?" }" p
- glVertex2f(xpos + w, ypos + h);
( m/ d6 ?% M0 @& U4 x6 r; b& Q - : N* S! T; p) C$ m. V
- glTexCoord2f(1, 0);
# A5 M6 N1 U# [0 I - glVertex2f(xpos + w, ypos);1 ?1 R- C( Y9 f
7 c3 v5 n4 t D4 E$ H. @- x += (face->glyph->advance.x >> 6); // 字符之间的间距- H7 W9 N1 ]7 O Q8 r. ~- c
- }; r' }3 W- d7 g# @) M
- glEnd();
$ W+ Y5 |, A6 a8 r
# }9 `# _9 S( c4 t- |- D; p. e1 U2 g- glDisable(GL_BLEND);
/ ?' x/ R9 X5 l7 ^* N f& j% a; Y - }
0 e2 l4 O. s: g1 H - * @7 T, w7 e* U4 {& I6 g8 a
- int main() {: E4 a6 t1 z- G' Y
- if (!glfwInit()) {0 R5 H1 a; l$ S3 k. ?
- fprintf(stderr, "Failed to initialize GLFW\n");- K- @, I% i2 m: k' t1 v# b- A$ ]
- return -1;
- h {$ a% k( c8 J6 f9 z - }$ C+ H! ] Y, p" }- @# ?. I
- 5 `! c M5 `- q4 d0 z6 p2 {: L3 i
- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
8 `4 X$ I: M/ n0 Y r0 l- L - if (!window) {. I* v* K0 I$ R: W
- fprintf(stderr, "Failed to create GLFW window\n");
4 v, o# @, P: w6 X2 ?& H - glfwTerminate(); Q' X+ G# J$ A: b+ V* q3 c, J
- return -1;
3 ~4 J! @9 E, \/ b7 | - }
1 d( O: }: C, f( {3 W% H: E
. ]0 j! w6 O& |- glfwMakeContextCurrent(window);3 _1 u* m& W, a9 j1 v. ?
- glewInit();# |2 }' N. _. f& x7 L- H8 e9 h# \
: w+ w' U" u' \3 {& c$ v* p- initialize();8 ?! o' `6 E4 w: A! A' [/ m4 p
7 e& S3 k; G: c- while (!glfwWindowShouldClose(window)) {
& D1 q1 n- O) t: ~; T' w2 Q; R - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);) d9 j( E; k( X/ d& a
- glClear(GL_COLOR_BUFFER_BIT);
]+ p3 r* [9 n) J/ f8 g
7 _( f/ I8 U8 N, x o/ q" H- _6 y- glColor3f(1.0f, 1.0f, 1.0f);
( V. N6 x; l. Q/ v - renderString("Hello, OpenGL!", 100.0f, 100.0f);
' u4 b- |$ \0 X. m/ Y D - ' v* L; h4 E- l s4 x! I
- glfwSwapBuffers(window);
( |" S+ K s3 j3 k - glfwPollEvents();
) ^8 X( ~/ u& ?( N# D% O - }
+ A- q G/ d, b% x) Y - ' N7 V4 Z- N* C0 u" O6 ~
- FT_Done_Face(face);7 l7 z7 f) D9 H2 Q( X4 {
- FT_Done_FreeType(library);
0 d' B/ i* C& _. y
+ Q8 ~+ u! g2 L- M/ C" H! ?' y- glfwTerminate();
2 \) z" Q8 @+ K9 g1 u' o - + v2 \8 }9 S( q2 R# W
- return 0;; Y$ _0 n* Q6 E! `+ S1 S3 \; C6 O
- }
- J- e2 |4 K$ ~& Y8 U' t' S9 j
复制代码 8 b8 i5 I, `" }( A+ q
$ i2 x: i3 g6 B1 J! N- b
|