本帖最后由 shane007 于 2023-9-6 15:32 编辑 + A; u+ ^1 p: H( A. B+ V- V, d
2 G% Y# i8 h% w4 G以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
; b) Y- i! W% R+ r$ C本代码经过分析以及改写之后,将取代游戏原有的显示函数。# H E6 \4 b+ ]; v$ P6 t( R5 t x
1 E2 o) i5 d: s- o5 c代码详细说明如下( ~$ A1 h$ O# n! R
; w \' F7 k/ c+ u' n: T+ Q* m- 在上述 renderString 函数中,我们有以下关键部分的解释:
; {3 a! s3 h' j; d" `+ K- c2 m - ( i# y) x- O" a& r2 ~4 h7 I
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。3 C. y, O3 y* K2 M
- # b& b! B" h/ |# F. x8 a, Z: i, k& q
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。: Z* u) o% v0 d0 p, t8 N
c% S, m. U1 H9 w- A& W# j- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。 V D' Z+ O9 }2 E7 f" q
; x( f& Y8 A3 r" V- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
4 q y5 f& ?; @$ s% ]4 v$ o8 h - d& ^# I4 X; D
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
( `0 h8 D& s" ~" B' O5 S9 {
) {& V' G: o. V- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。, y3 \# t6 p8 y' B/ ^
- 8 Y! |5 s* o9 b$ @
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
8 d6 p8 q5 n' s' `1 N6 y& }1 f6 K( z
. z# [' ~3 @8 M9 C8 z1 `( w5 n- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。; y4 c$ b1 Z: x K
- / @8 Y, q+ C- U+ H- N/ u5 f: u! G
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
6 b; g' `. U" G6 `# n1 n" b
" C7 c+ F2 i ~& p; Q# F- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。4 e. t3 s7 K0 X& ^7 g9 O: n( Y1 K
复制代码 2 r2 _! p8 h+ ?8 l
: E! J: m. ^- s; f5 z
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:8 X& B" F( h6 ?7 V* f% ^2 U% f
; U. B# D7 P* z- 参数:
) ]9 z9 E2 z& t" V9 B+ `4 Y - 8 q: }/ b' u% p# T) U2 v
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
% x P3 i O0 U7 f8 w - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
# T/ h# V/ {) K - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。& w. m1 u' q# r8 c
- 功能:% J# _9 L; l7 p) w' t
- " q6 M& h- ~ t' e: }( e4 V8 Y
- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。# I4 h( C# h/ `9 e: e
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。( i: [% Z4 c/ M" b5 z. t4 L
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。 |: k7 h0 U. F
- 使用示例:' |3 E4 P5 m2 n! @4 g% L
7 P- T- r; O H- k W" q; [- c- B1 s: o/ f. A2 {
- Copy code8 A( i. d+ h c7 n
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);# i3 q) ?: K# Q0 ~
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
$ g7 }2 `' d+ E) \' W/ }, q/ Z# [) `
' Y+ b. `5 m3 W) M6 J3 ?- 错误处理:
7 `3 P9 C; t* B# L4 f# I, V5 p
' y) b, x6 U0 d8 d5 Y5 W- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。. [ T6 w1 [7 \$ ?8 J4 o
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 * C% w# d0 H8 f. c( o8 V0 N9 {+ j
- l4 l. I3 U8 |$ B) _
代码* L4 ^5 S" j' y. \
* U0 V* L5 R) o- F5 d" d6 y4 C- $ O) X. b$ P1 e/ b, _
( X; |7 L/ r( K- 5 J0 U; i4 Z3 H! R+ g
- #include <stdio.h>
# _; ^; @/ R( H& o - #include <stdlib.h>& U3 B( t3 L8 w Z
- #include <GL/glew.h>
4 H/ O& m$ d2 E5 y" Z - #include <GLFW/glfw3.h>% j' Y2 b, u' ~! I9 }/ Q
- #include <ft2build.h>
3 V+ l, y& t% ~2 u+ C - #include FT_FREETYPE_H+ }( J v r4 ~
- 3 c0 I2 Y$ Q9 A: C# s1 w
- // 定义字形数据的字节数组+ G4 V1 x3 K+ ~( l' ?$ V' L
- unsigned char fontData[] = {
( h/ k6 _( Q T+ P - // 字形数据的字节表示
: q7 W) O% J0 R8 }8 t! `. w$ g - // 例如,这里可以包含字母、数字和符号的字形数据) }$ p; u4 x3 S9 I0 @5 \# ~
- };7 f9 W$ _4 s2 @$ w- [
- 3 Q. r7 b/ l% k& }3 h6 N; @
- FT_Library library;; v: P, a/ Y- @5 V
- FT_Face face;
$ o% x! A! v# s0 v; C* }2 s - GLuint fontTexture;7 U8 P0 E- B+ \8 J" R
- ) u+ P) L; ^7 n9 E: X% x
- // 初始化FreeType库和OpenGL! l$ ` c* M3 }0 S
- void initialize() {3 y9 D# d6 R. _8 k2 G
- if (FT_Init_FreeType(&library)) {5 f- m% y" c2 b' S% v$ K' U3 z
- fprintf(stderr, "Failed to initialize FreeType\n");# Q( u: k, |. F( \! M
- exit(EXIT_FAILURE);
, M7 e" q) c5 i) c6 i/ | - }
: [6 Y2 E% T. X
- i3 ?' i9 }+ z K* r# A" e$ G- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
0 p9 ]5 A* }3 F; j/ Z) [7 r - fprintf(stderr, "Failed to create a FreeType font face\n");
* r# v; K' h$ p/ v8 Y; ~. ] - exit(EXIT_FAILURE);. W6 k% K3 i- {! k6 }, H
- }0 h3 p, k: [; N/ O' k$ c0 @
! J& [# G \; ^1 K5 M4 J. }- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小2 }5 w5 s. Y' D
- fprintf(stderr, "Failed to set font size\n");
' X4 [: |: u3 N# }* Z+ f - exit(EXIT_FAILURE);
: l2 M! k1 ?6 Y' ~# D* Q2 r/ Z - }4 z, q S/ h9 j) ]0 Q+ {* x8 @2 G
- ) A8 o& c; T5 l
- glGenTextures(1, &fontTexture);
- F; R! d5 T. R- Q+ h' ~) S0 [ - glBindTexture(GL_TEXTURE_2D, fontTexture);
5 i$ F0 x. s) x# E6 m2 k; e - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);4 m2 ?; A% ^, U$ n- l& ^4 |4 Y
; H/ \& E6 ?9 i- [& W/ u2 C! j- // 将字形数据传递给OpenGL纹理
U6 Z( u4 G7 a0 O% { - for (int i = 0; i < 128; i++) {
' I& s/ [2 ^/ H' J- F/ Z - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {$ p) Q: S# m- H9 ~; }# L
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
+ q7 f+ k4 O2 S - continue;
0 r( k* z: N+ s4 n/ d7 { - }; A9 ~% C) v. A' Y$ z7 m
- - \$ z1 @9 ?6 q: S1 z3 ]
- glTexImage2D(: U }4 |, b9 h7 n( ^& b
- GL_TEXTURE_2D,2 {& q: Y( [9 Z$ \9 K
- 0,
) X* t2 i! Y& z, @ - GL_RED,
! ^" P' y- }$ S+ u' F6 E5 l - face->glyph->bitmap.width,. G- x& G4 z5 i+ y5 J0 J$ X
- face->glyph->bitmap.rows,# [/ n# }2 B4 b( P6 K
- 0,, B( o0 J4 {/ k& H
- GL_RED,
( O* \" K- A0 H) d' n7 l/ d - GL_UNSIGNED_BYTE,4 \+ r8 x' @3 ]% D, @# T
- face->glyph->bitmap.buffer
8 j) J+ w4 P1 {2 u4 ?) Y - );' A$ C9 N3 D7 a6 l0 a
; b; u6 |" ^$ x- Y% }2 s- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);; Q( V5 D; L, P( Z. _" u, J
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); h: r; S, E, W L) y; `& ]
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
% L7 @! `# j! Q3 Q/ ^: t8 { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);' Q7 |! H* O1 u+ O
- } F! Y- l" P. k, I, l/ q! z2 z
- }) C y5 r5 f' s% ~; Z" K0 o
- 7 B, f% d" y) n9 q
- // 渲染字符串
$ W0 M7 N& F0 G% O( V9 Q+ Q - void renderString(const char* text, float x, float y) {
, V( S; i/ r0 S4 s2 |& c- b6 R- y$ j - glBindTexture(GL_TEXTURE_2D, fontTexture);
& T) c; }# |( g) E5 B" `( p - + s N' C- K8 X% i
- glEnable(GL_BLEND);9 H1 a" t9 I! R* i
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);0 W: N+ u( B8 F
7 }, |6 @+ a, v+ c- glBegin(GL_QUADS);
7 y( t! d! l. e& `! l- v1 D - for (const char* p = text; *p; p++) {4 W- j+ z( J' f3 ~
- FT_Load_Char(face, *p, FT_LOAD_RENDER);
2 Q0 T% Z2 U7 |, \
4 m' m, W. n6 D- glTexImage2D(& @# z# h; t) _
- GL_TEXTURE_2D,& H" k7 A. \* w+ Q! t: U' R
- 0,' R% [! E( K+ U, j$ H! }4 R G
- GL_RED,
% t1 [9 @6 }" |0 w - face->glyph->bitmap.width,2 {5 Z @- a% J* [
- face->glyph->bitmap.rows,
7 i0 A6 g9 p. g m, _' s - 0,3 l% i k) ?: l( G: R+ B& B
- GL_RED,- F" J# z% i# N+ {0 X/ D2 F- A( z
- GL_UNSIGNED_BYTE,1 Y- a+ z; z, d c( Q
- face->glyph->bitmap.buffer
1 O" j2 s0 c. e) |" _0 c: Z - );6 d) Z$ Q& K. l& M
3 }& R9 K5 P# h& O0 d8 @- float xpos = x + face->glyph->bitmap_left;, ]* _9 S" a2 _* L- Y3 _" X
- float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);( [. T# e- `9 c$ i5 F
0 N: e/ e' a* }+ E; p- float w = face->glyph->bitmap.width;1 y: m) S, C. R, V. i/ U
- float h = face->glyph->bitmap.rows;
" t Y6 B4 a% B' R: t- `: v& K
/ s2 }& U" [6 J- q$ P, c8 W% E- glTexCoord2f(0, 0);8 b% O; y M3 `$ M$ D
- glVertex2f(xpos, ypos);) c6 T& D7 k7 H9 d# v8 w
, O' t' u7 I" \ U0 c. p* g- glTexCoord2f(0, 1);
% ^, e' P1 {+ |; X {( U7 X - glVertex2f(xpos, ypos + h);
% L* G2 M' ~/ M$ b: \0 ` - / f2 r D# o7 \* k$ ?2 l/ `
- glTexCoord2f(1, 1);
' r& \5 q! L7 @1 l1 G) e+ s - glVertex2f(xpos + w, ypos + h);
0 _4 S b, h; }5 @" z - 0 Z S. Y! r! g6 [- j* r7 d: {
- glTexCoord2f(1, 0);
& O8 V4 @6 {& {9 M - glVertex2f(xpos + w, ypos);! h- |6 F: C* b% m
& [& V; L j+ M- g" Y+ \0 |- x += (face->glyph->advance.x >> 6); // 字符之间的间距
$ h$ l* S" F0 c - }. v" {. @5 \! h% f
- glEnd();/ a, o; ?& ]5 O. H9 ~. Q, Z7 w
) _, M8 `* d. K3 I, [: O( A- glDisable(GL_BLEND);
( @7 s3 \: B% S! u5 ? - }0 B2 s( i4 b8 S3 e
- # O8 ~7 b# f8 [/ b2 D( Y; n
- int main() {: ]* H1 {! B+ N' D& B
- if (!glfwInit()) {
' o9 |( f {; G. L" g - fprintf(stderr, "Failed to initialize GLFW\n");
! }& C' K. v4 u8 ]6 j - return -1;9 X+ `! d, }3 K4 A5 m3 ^* \
- }
3 `5 U! B5 h" z* e+ J( W7 R# n. b; | - 0 i& q6 O; j& q+ V2 t
- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
5 X& l; u' v. W" R - if (!window) { |1 c; w. Q' r: G! E
- fprintf(stderr, "Failed to create GLFW window\n");; ~% C. R0 _& I$ |* P3 Q( X
- glfwTerminate();% e$ q2 U* X9 J) P0 n
- return -1;
6 J3 ^ Z0 O3 ?/ a - }2 m5 A* ^: a+ y6 `6 t) G
- . K3 d( q$ M' a' X' p, I
- glfwMakeContextCurrent(window);
. o' A. ~. I1 A. K, v) t+ L$ { - glewInit();/ Q# H7 m3 |7 V2 _- _0 `
. R$ K1 m1 W/ j( {% i, A/ S- initialize();
, g! {) V* y) T# o
7 Y% F( z. c) A3 f( T6 p1 t- while (!glfwWindowShouldClose(window)) {
2 f( j: v' a' \# c' m- D% I- a - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|$ r# y2 ?7 D- l7 Y - glClear(GL_COLOR_BUFFER_BIT);" T: I4 e' j! `: e$ I7 Q
- 4 s+ {/ Y* q$ n% m
- glColor3f(1.0f, 1.0f, 1.0f);
! r! n- Q9 m& o3 n# V) L - renderString("Hello, OpenGL!", 100.0f, 100.0f);2 F& P1 [2 ~8 {& }
- 4 K5 X1 Q0 n* b' C2 ]" y- f
- glfwSwapBuffers(window);
. J9 e. N( ^" x& A - glfwPollEvents();" D z/ g+ O2 H) f
- }
2 Q/ i' }4 s$ i# ? h3 Y8 l4 _
X% t: S/ R6 X- FT_Done_Face(face);
H- r& n2 X6 @. r - FT_Done_FreeType(library);; e' U$ P2 M6 n: e) X
3 @' Z+ Y2 y5 `+ {: \& ?- glfwTerminate();
1 |# e$ d7 n! T* W1 }! Z+ t6 ? - ' i6 g+ O/ G8 |+ O v* ^# B M$ C
- return 0;
B0 Z9 L5 x$ B- a W - }
6 n3 ~! H5 _! ~/ C6 n
复制代码
) t' ~& X" e& o8 W7 ~' D8 F6 S$ f4 u
6 R1 T+ L: K8 |+ X$ R7 i% m! Y |