本帖最后由 shane007 于 2023-9-6 15:32 编辑
7 i5 ]- t* E( j9 k6 [. ^# c, h2 F1 o/ ]; D% F/ u: G
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。* U/ O( R( Q- X; w! W2 i3 ^
本代码经过分析以及改写之后,将取代游戏原有的显示函数。
4 [. e; h. n+ S: t# R! m" w* e. m ?2 a% v/ G/ ]! N
代码详细说明如下
" {$ e1 i# t2 D# M$ U2 J+ G
, e( O- T. K, m4 k' U- 在上述 renderString 函数中,我们有以下关键部分的解释:
. x8 m" \! M" A7 ^ - . L% [. m: R( I0 _9 B0 q: x
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
5 U+ E0 h' }+ \# P8 K
5 x5 I7 i2 s. \- ^- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
9 R' R" U4 O) u# r w Z - # f2 e; o, ~$ L
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
7 x7 t) V1 x; f. s* i; Q
; e8 u# Q) ]! T: l6 r. M- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:( c! x- V; e G1 S4 @! P
- ; Z0 C1 i' l' ^4 q
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。% i) A: d Q- j0 ~3 E# ?9 P
1 R5 ^( q/ j, g( h3 u5 D" ?- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
# |; i; o+ X8 r$ K
, a! f7 Q' ?" V/ Y' Y+ Q. _7 i0 |- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
5 d4 d0 e) ~1 {) Y - . S( t1 t+ M# I6 j
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。( J) S" ^; a( A/ J; t* E
& g* C3 [" I2 ?- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
$ t' ~2 i! p& O6 O
: l# j0 i/ x' o+ V$ e. \3 G" q1 G- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。8 b& b4 X& ]2 H; Y
复制代码 9 }+ j( F% u& b
$ |' Z( f0 ]8 E( n% w; U5 `8 U- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:1 n6 X& n4 t4 b p; b9 O- Q: R( y' j2 }
& r" J4 |1 @2 j' R; |. _3 ~& K- 参数:
1 n$ U$ V0 C0 J: _. W
* I. _* V9 ^/ u+ x7 i4 Z' M- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。' ]: x6 r( k- e/ t4 B/ D" p
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
! I \0 a# w7 H! K3 G5 P - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。' r) C0 a$ M- S5 X$ x5 Q% v
- 功能:: [7 m2 L* J" H8 ~- h3 \
- 9 [$ A& |; v+ y, G4 I% j3 I
- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。3 a7 p/ ]$ |! X. R
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。5 K+ B: v, @8 o- D' I1 B- e$ X
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。9 n; t Z$ d1 M9 O
- 使用示例:
7 L6 {, d3 n1 _9 V3 _
/ c5 P# T2 L0 e8 m+ H- c+ V' t q7 K) ?4 o. R
- Copy code1 W2 }+ D- j+ P; Q% R
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);. r6 [- g% ^' I6 W ]; |
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。0 I, N, S0 F, a* ?0 ~+ B
- : _1 E4 W4 [' T3 L
- 错误处理:7 J! K* P4 P4 Y Z
1 S9 s' e% k% J& P+ B4 r- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
2 L: U# K1 T; l6 i3 i3 R - 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 5 E& D$ A+ V9 ^) N
% }* F/ n6 P) ^$ J# J
代码4 D- o; c( \0 B( {
# B, S; v6 S D% u/ r( x2 a
: V1 i/ D7 ~, s, d8 V: L+ d \
- W6 J9 K- E, s- 9 S R8 u! }, }
- #include <stdio.h>
+ {, G% z1 K0 q/ j+ u; z4 y - #include <stdlib.h>
# b2 h$ }0 ~* v" j1 v! D - #include <GL/glew.h>
! `8 C! t! p8 H. j; N - #include <GLFW/glfw3.h>+ H* \# |4 E m0 a, j% N
- #include <ft2build.h>
+ P: ?6 a/ C5 a4 Z0 K - #include FT_FREETYPE_H
8 _& v) m u/ H7 Y9 b4 V$ @( {7 P
6 v j2 u" F" p1 F3 e- // 定义字形数据的字节数组- q N: s' ~. d& |
- unsigned char fontData[] = {
' @8 H) c* i8 L5 q# H. d6 p' E - // 字形数据的字节表示; _: R# L2 u/ }; ]6 k2 T1 ^# O
- // 例如,这里可以包含字母、数字和符号的字形数据; u0 q& `! ^, F8 ?. c$ I) y4 Z
- };8 ~+ Q5 }, J' z# Z+ e/ C
% H w3 |' H- \5 b1 d- FT_Library library;; V4 R6 E% i* E: p0 ]$ t# n: G3 `
- FT_Face face;6 X4 _# `$ X8 e1 Q5 b& ^( m5 o
- GLuint fontTexture;
0 w$ o7 C; [- M1 \% @5 z - , R$ D, n5 U+ U: \$ f: U/ \
- // 初始化FreeType库和OpenGL
7 P/ C- t. I6 p+ o2 M: k5 | - void initialize() {
* S* R( S( F' J3 C; C# l0 z - if (FT_Init_FreeType(&library)) {
; a7 Q% z. Z0 n - fprintf(stderr, "Failed to initialize FreeType\n");: U$ `# _, u& q8 `3 B9 L$ G& G8 O
- exit(EXIT_FAILURE);. o$ Z0 ]( m) h M
- }
: b/ R. D5 H$ r6 K" Z
1 \; L& m6 B0 k- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
" G3 z2 W) z: _/ o& _ - fprintf(stderr, "Failed to create a FreeType font face\n");1 t$ ^; [+ L7 s& y/ Q5 L
- exit(EXIT_FAILURE);
. Z( d; o N& o, @ - }9 Z9 l \$ A4 I7 T
- , X) w2 u8 h+ j0 S$ q
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小( P9 L$ L1 J+ a; f% h( K
- fprintf(stderr, "Failed to set font size\n");
5 _! O0 E7 V! \ W& f6 M3 z - exit(EXIT_FAILURE);
) x! e6 f5 @( b' @! k - }$ k) i, ], e! q/ P3 p/ H) [( }+ l! M
- ~/ H& T! d1 e8 T5 U
- glGenTextures(1, &fontTexture);
' f) `4 `4 f! Z4 I3 v$ B% M+ C - glBindTexture(GL_TEXTURE_2D, fontTexture);; C# m. m( C& q/ ?& T$ s& F
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
9 |! I( k: a/ p( s% a3 r - ( K3 ]* D% S8 Q+ P! c* O* a
- // 将字形数据传递给OpenGL纹理, S6 H; V% [1 ~
- for (int i = 0; i < 128; i++) {/ D4 H w0 S8 g+ ?! e9 O
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {6 O6 q2 p- S0 w* s
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
: j5 W A! `* D: @7 y" m - continue;9 K( v7 }5 O/ H s, a+ y ^
- }8 T+ _* ?( h- \) }$ P
- ) w4 L7 q( h9 t/ O- G7 \. V
- glTexImage2D(
! a/ Y" F1 G# W5 C, y( S( {5 } - GL_TEXTURE_2D,
; x4 t. C9 u: B- |* \ - 0, }4 k0 s0 b9 W" i9 x& ^- k
- GL_RED,
( Z3 o: R+ j& _0 u5 A# M( U$ G$ l - face->glyph->bitmap.width,; U! W, W `4 B. y& q
- face->glyph->bitmap.rows,, z3 W9 O6 P9 f( V4 e
- 0,1 \; G+ o2 u8 N% {
- GL_RED,- w: L4 Q3 S ?0 K
- GL_UNSIGNED_BYTE,. |; h- N+ z* P$ k9 K/ a: {
- face->glyph->bitmap.buffer
0 ]1 j6 g" k( ^% c- B% W, {6 t - );" [1 k2 \3 n# U3 z
- ' ^( h$ B& b9 h4 ^
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
0 R9 \) X- R" P1 B8 z; t8 o G7 ?& ]& K - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);7 T. k6 `- f0 }2 {4 h6 g- ^5 v5 C
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);4 T3 E3 q& p: F: J
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2 D' Z% U- u- Q) c - }: l7 M q/ h$ B$ g+ u5 J( F
- }; }0 n' S2 m, `# k8 u
6 N: s* J8 t0 J- // 渲染字符串
" P6 ~' {) A$ _8 w) v5 P6 I0 u) e3 G - void renderString(const char* text, float x, float y) {% L9 ?5 {3 ~! p- D, A
- glBindTexture(GL_TEXTURE_2D, fontTexture);
, \- b8 m5 ]( y - 0 |0 q# U7 M a6 [3 W6 ?! z; R5 ^# B
- glEnable(GL_BLEND);' E$ Q$ x) ]4 M7 H
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
* c: ]4 Z0 L: x2 ^& l
* K% m% m B! W! L* N3 Q2 a- glBegin(GL_QUADS);# P5 v' s H. L5 \" c1 u! V
- for (const char* p = text; *p; p++) {
. c! H9 D( l) m: C; s; R8 P9 l - FT_Load_Char(face, *p, FT_LOAD_RENDER);2 a8 b7 g* |. |& M
- % H L: |* \# {2 {* e! D# y. }
- glTexImage2D(7 h" t- y0 q1 T8 \
- GL_TEXTURE_2D,# G! P8 F) h0 z1 E! l
- 0,
* t+ e% A( k" Y* k% b - GL_RED,
$ o) h+ k$ \* Z! N V: V - face->glyph->bitmap.width,
. _" V! s* M9 R4 j" f+ R8 c - face->glyph->bitmap.rows,
0 P6 X5 @1 k& |/ @6 L5 V - 0,
, M* [0 K* q z; D, s4 | - GL_RED,! T: v" `6 O& u' C
- GL_UNSIGNED_BYTE,
0 N7 ]- U) @' E4 i q k# ` - face->glyph->bitmap.buffer
0 d( s3 Z7 k A0 K8 ` - );) C B$ M' C. K4 @- x4 @
- 0 U; V% A" [3 {4 p: z' {
- float xpos = x + face->glyph->bitmap_left;
/ K3 i# U/ V- c( `( E - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);9 j! m2 o1 F. j- g1 z
! I% {. j, X! N- float w = face->glyph->bitmap.width;
) `/ ~5 z, Y$ f - float h = face->glyph->bitmap.rows;
$ N7 z+ T6 i+ O1 \) V
& t1 ?5 ~0 Y3 i* |( k' t$ z: j9 V- glTexCoord2f(0, 0);4 {+ X6 j8 Q- K% R
- glVertex2f(xpos, ypos);" y8 x1 r- }; g; D' Z8 a
0 F4 R2 m1 @2 V/ d8 L- glTexCoord2f(0, 1);
' L& A$ e/ N" E& Y2 A0 ^# j6 F - glVertex2f(xpos, ypos + h);$ b. C6 v: H: A. a; U8 @0 H$ h
- - X, L D, n4 A" U
- glTexCoord2f(1, 1);; w# y+ {( _& i+ J7 O3 D% h
- glVertex2f(xpos + w, ypos + h);; ^) S+ L+ y' B' v G
- # Y, T. g5 c' f- O' u
- glTexCoord2f(1, 0);& v3 r7 l6 A4 y" i' {
- glVertex2f(xpos + w, ypos);; ]7 v5 `1 G; W8 O. _4 f1 `3 t+ n
- & n# q7 }9 R# T/ W$ \3 n/ N4 K
- x += (face->glyph->advance.x >> 6); // 字符之间的间距
2 M( M! {6 M% o/ p) P: e1 z; ` - }8 Y8 M3 Z( K: W0 }" |* k7 C2 }
- glEnd();8 Q, t, h# j: f& h) b' A# H
- % x, P% K( w/ C8 w9 s7 M
- glDisable(GL_BLEND);' E: o) ]' o! j4 J0 A
- }
" t0 B, e# F; Y8 L, ^5 I
; n, `( h/ _% y- `) I- int main() {
6 e9 j% M& a% M: {5 Q( C& t/ X - if (!glfwInit()) {) e+ f( s7 O K) q: i7 |* d
- fprintf(stderr, "Failed to initialize GLFW\n");
1 Q- P, B: y+ i$ @$ e& X% ~ - return -1;, x) @0 c0 D4 @! M ^2 {# R- D+ I
- }
' {: ]* f; C0 c - , u" K& g& M! p! M# O* [0 \6 F
- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
* T3 U1 B3 K, T- d7 ` - if (!window) {
* Q8 T9 Q p0 t8 N1 z: G& \ - fprintf(stderr, "Failed to create GLFW window\n");- _% y& }1 R+ ~* V2 q$ D; l
- glfwTerminate();, e q+ p1 f' H5 X. b
- return -1;
/ s+ c& R5 g8 f3 h0 D. i - }
: L1 `) {- |, `- ]$ c2 Q, b1 S
4 J k) G/ m, |# x$ c9 Z( y8 Y( O0 _- glfwMakeContextCurrent(window);' ^8 [$ `& Q5 }! I9 N, R$ a
- glewInit();
$ w9 S E3 H2 t, t( K. C( I3 @& q
" i4 ~4 J1 W, J0 y+ c7 C- initialize();0 ~3 L0 b0 I, V/ ^. k+ C% C9 F
5 c: k7 \5 g( l6 Q* X& Y! h- while (!glfwWindowShouldClose(window)) {/ Z( v2 M4 s) H' o$ }- q/ }
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);% x5 Q4 \; o$ w( @6 Y
- glClear(GL_COLOR_BUFFER_BIT);
3 |9 K5 F. X: I7 M% ` - ) D8 h& V/ i, a4 T$ H% ?& U' ~, m0 i' B
- glColor3f(1.0f, 1.0f, 1.0f);
" Q& b6 H. [4 F! a8 K2 g- @ - renderString("Hello, OpenGL!", 100.0f, 100.0f);+ _! H2 x- X4 g- E: n* ?8 B& k
& m% a; G- [+ Z. q0 _' `- glfwSwapBuffers(window);
0 y3 Y/ l5 y+ X+ E7 T5 M E4 \. D! F - glfwPollEvents();9 l& N! m; y1 j6 u! ~5 e
- }
- {7 {$ f9 g9 T3 ?1 z! Z! B( j
' B m3 `! d% H* H; W- {3 \- FT_Done_Face(face);2 n* l0 A( G! _* k
- FT_Done_FreeType(library);3 L! [/ O! P$ e4 A$ m- [
~# F2 g: b4 S5 ^- glfwTerminate();
& ]( \8 R. g2 S: W* J/ R - R, w/ R0 T2 G1 ]; K) U
- return 0;0 Z) i* ]& ]3 H3 ~5 C. {
- }
+ D2 _/ y E A
复制代码 ~8 Z8 d- I2 ~) R; F+ }
8 i5 H$ ^. ?9 J$ K( j |