本帖最后由 shane007 于 2023-9-6 15:32 编辑
8 q$ Q3 B- K9 S K$ }) Q
( n# h8 r3 S# I6 E0 [以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
- A+ S, x R0 u) }本代码经过分析以及改写之后,将取代游戏原有的显示函数。; O+ o9 l! p! N0 s2 k
- |! \ g/ x! L* Q: p9 n代码详细说明如下3 V2 s& d1 {* k4 O0 {( b
' @: P% s' f6 ]* ?, a
- 在上述 renderString 函数中,我们有以下关键部分的解释:
0 a/ d9 A& [* Z# | - 1 W4 M- Z, v, o! t! N1 |; v I2 N
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。3 q0 `' N8 d. b0 \9 N
9 p0 A% D( Y- F( [: E( m- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
& c3 R0 w( y$ @, \ - 8 f$ _! L+ v& W M' }
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。: N0 o. m+ q1 p* f) k8 m
- 5 R6 d0 I- K* F" L6 b" ]
- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
8 @7 d7 ]# z9 M - 8 C+ Z# O6 e: J5 J3 z* r( h' Y3 u
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
$ @+ e# @. |4 ?" Z' J# t4 R5 ^2 n+ s' j
% u# O! H4 F* }, R- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。2 M% X* y) t& Z/ r- m8 {9 r
- & ?/ r% } A L5 O
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
) m) N' C/ k ?$ e! B( w7 r
) D7 |8 ^1 i9 o' a9 Z- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
$ |" ^) D4 r1 F$ }; W - 5 E! U7 w0 r5 j, b
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
: u' L2 }; Q+ B& `& Q* P
9 D/ S: m, w7 {9 X. Z( m- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。! D2 D1 c3 ]# {. Y' N/ ]" \' P
复制代码
# k$ {& ]6 Z n5 e8 B7 }( ?1 r* T# B' p1 ?3 O2 j
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:
8 Z( h0 w; m7 H; D
/ L0 ~! @3 i2 l7 D9 V5 w- 参数:8 j% Z$ y2 K9 J( d5 D) u
- ! L+ [. a: }5 V
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
. J5 q: y- F7 D. Y - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
7 o# q) i: v- g( c& T3 ?6 h - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。4 C0 `; u% O" d; l
- 功能:0 ^% Y% o1 A% `" h- n1 W
# l. B7 i, h5 _' X+ b! a' i. p9 r- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
" ^) w8 X: B, l7 d2 _ - 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
6 ^4 x% B- T" Q* f. }0 F - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
5 w5 b* l3 G( I O - 使用示例:
: }9 f& {2 N* q' k - ' A8 U! ^, z: _' X% _
- c# j! C- D; T. d, O" }; x0 O
- Copy code0 ]4 d( E3 @, c o# v1 Q, O- o5 ?/ s
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);% v% ~. g6 |1 b4 g! q3 f
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
0 I# ?6 c7 |4 C8 K3 c4 O, r1 [; X - % S" [. W+ ]; i8 f! g
- 错误处理:" I! N. [4 P7 Y M
! l. q! A( J7 `9 G! o5 ?" L- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
& v) o/ S+ I5 S - 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
3 K# O! Y% ~$ X4 Z/ p) s2 v3 M& d* m! J- B
代码' k4 ^& N/ Y2 o4 @7 t; O
0 i# k8 _/ P% P! Q3 Y
7 @0 v! y! a3 p5 Z- ' P8 C' D* |, L" \
- ; F$ S$ I2 ]8 V* Q- [7 m- ]+ o7 Z, l
- #include <stdio.h>) `0 w- f1 G t" s9 {8 R, `
- #include <stdlib.h>* \1 X7 Y# R& m4 ~
- #include <GL/glew.h>
& f, K' W3 K: U/ [0 c - #include <GLFW/glfw3.h>
1 s; V0 i+ {6 V4 }- ?. h - #include <ft2build.h>
/ l9 ~' [ m9 X/ y$ H+ M3 n - #include FT_FREETYPE_H
2 ]5 f9 a1 b |
* ` w# z" m/ W; }2 Q- // 定义字形数据的字节数组) w* `9 i m( F# }$ j0 H$ M! \
- unsigned char fontData[] = {+ }: R6 _; { m1 F4 _. Y1 p' g
- // 字形数据的字节表示
" s. O; e9 y% d3 ~4 Q - // 例如,这里可以包含字母、数字和符号的字形数据
5 D7 Y E0 ~1 t6 E) d - };
1 A: [5 T6 t6 v+ n q+ } - $ L! }8 ?8 K3 F8 I _# o
- FT_Library library;1 D' l4 l* k" F( n; A/ q
- FT_Face face;
& @5 n, c0 S8 g8 y% r" F - GLuint fontTexture;
0 Y u9 m+ v) c3 D+ M/ _9 c
( v; u9 R/ w, E) i% ?2 A9 L' N: [( ~- // 初始化FreeType库和OpenGL! E3 `% U4 q$ k& X4 L( x) @
- void initialize() {: E+ E9 c0 [! |9 f: a, {7 f5 @1 F
- if (FT_Init_FreeType(&library)) {$ @ W) I0 Y; `" {0 ^4 V6 A
- fprintf(stderr, "Failed to initialize FreeType\n");0 @3 w2 n2 P+ I
- exit(EXIT_FAILURE);; B: S$ ?5 G" g1 Q( s# L% }; @
- }7 r$ V Q0 l. ?$ l
- / W6 K$ z& c6 `' N$ u/ D; p
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
- h: b B9 z8 I1 B! }; a - fprintf(stderr, "Failed to create a FreeType font face\n");# C/ Q( V# w: |$ T/ T% q5 `, t: ~ ^
- exit(EXIT_FAILURE);
& ^# |: a5 p1 J" n - }
* v5 a6 ^3 z' ?; I( R - * ~; l+ @* H1 M1 I3 U+ R
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
, Y7 V: J6 b& b, U& R - fprintf(stderr, "Failed to set font size\n");6 e* Q [- q+ c" J' |3 @
- exit(EXIT_FAILURE);
6 M% g& x, z9 a& v E - }
$ V4 `, s; M" n9 ^7 S p
( }9 ]9 f- u, ]* F. B. i- glGenTextures(1, &fontTexture);- X5 I, |# \7 u% ~6 V2 L+ G
- glBindTexture(GL_TEXTURE_2D, fontTexture);( j0 b. p2 N/ P: p, o6 q
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);( A/ A: U `& s3 L; K
- 9 u0 p& F& A' G: M) y
- // 将字形数据传递给OpenGL纹理0 P+ J4 q3 ]- e5 @3 t. K! H
- for (int i = 0; i < 128; i++) {
8 I8 |0 U |6 g: T! B. e4 A - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
0 n1 o2 k5 y) S9 Q1 _, j! n" O0 n - fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
3 ]9 e3 e) r7 h+ o# y - continue;7 d, H0 P+ |! a0 j5 m& M: A: `3 A
- }% j6 D# k6 J- ~& z" K3 _
- 4 q; |' d% w! _; I) T
- glTexImage2D(/ y. k2 v9 s. i
- GL_TEXTURE_2D,2 z! r; Y0 U+ a
- 0,
4 x) z5 q' f% e - GL_RED,# m, H$ {8 @' a/ Z3 {
- face->glyph->bitmap.width,
2 i: P( w& a- [5 c - face->glyph->bitmap.rows," D. q% q9 r4 h5 t* f, p, ~ p
- 0,% z; ^! ^( x4 {. _4 T
- GL_RED,
' Q" E6 `- I" p6 V# w- [ - GL_UNSIGNED_BYTE,! A' L" g; d. N
- face->glyph->bitmap.buffer/ e2 |3 k/ r% ], ^- Z% X8 [
- );! |! Q8 y6 W! C+ y# N
- 6 T9 y2 R2 \( V4 X+ N
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
# D# N# b, `# T; q - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);/ Z; m0 K; W8 J4 \; O$ c
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);& N' o- N/ T% ^* W9 g& v2 b
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);- J- J1 y9 M+ q( T6 g% P+ I8 `
- }) e6 P" A8 F2 N7 O' y
- }
6 [' o* O6 \# B; p7 b! D# a( x
8 u4 ]9 r) ^, d- k( W% I. O% V, D- // 渲染字符串, e' f2 _6 m7 s2 y. i
- void renderString(const char* text, float x, float y) {
0 v7 A6 @) ~2 W - glBindTexture(GL_TEXTURE_2D, fontTexture);
% p3 f& x7 L+ u! H! a i* P E - ! S8 W4 x/ r( I$ z5 Y/ m$ B2 A
- glEnable(GL_BLEND);
) L; f( m: B5 K) ?, H% a8 k - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);8 J+ f& O6 z$ S; \1 ~
- 1 a$ H( r; d& O7 G. I
- glBegin(GL_QUADS);; {0 H- B9 _9 v8 {; C& n6 [
- for (const char* p = text; *p; p++) {
5 q- r% F* ~7 u - FT_Load_Char(face, *p, FT_LOAD_RENDER);
* E& g% [/ X, _4 b - . @. ?: i8 g3 A# e' x4 I/ q
- glTexImage2D(
) V) t( l) T2 \: I' o( p f - GL_TEXTURE_2D,. w+ u K( Z2 z! c9 o. N, h
- 0,
0 F) P; {3 k& t - GL_RED,
- z2 b# A) [ ^- o8 O" f - face->glyph->bitmap.width,2 {0 `* d: D# [# T
- face->glyph->bitmap.rows,
# ]: k' c( I1 @' m! p) g/ B) M9 \ - 0,0 A. ?" D: n1 [
- GL_RED,/ f4 {) N" b- ]: V' t
- GL_UNSIGNED_BYTE,5 j" ^$ g9 O9 L4 v L& N
- face->glyph->bitmap.buffer
/ _8 P8 ]% \- \* _! d8 v - );
3 d7 }3 x6 M) E: o3 |: P! Z - ! _ Y! g' ?% P1 Q2 y l& i
- float xpos = x + face->glyph->bitmap_left;+ \' W. O. f5 p, M+ q; R* @; ]- ?
- float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
/ R; G; G8 p7 F/ N- P - 7 @6 e( v4 P- L+ ]
- float w = face->glyph->bitmap.width;
9 {) r( t8 {- L _: N - float h = face->glyph->bitmap.rows;8 u8 i: |* a- M9 {
- / I& O) w7 y( U7 A, v
- glTexCoord2f(0, 0);
3 r. q9 D" A8 h4 u8 F1 d - glVertex2f(xpos, ypos); }$ t% D* c6 B6 m6 I7 \; C9 C
- 6 J1 N; U3 }8 m" g: M8 p
- glTexCoord2f(0, 1);; x! C% t0 H$ K! x, V( i0 S
- glVertex2f(xpos, ypos + h);+ A% v! x' J7 w% X: Z
, z: o) E% u0 u2 w! \' s" r- glTexCoord2f(1, 1);
3 U1 q5 R1 Q6 \9 a2 k, j9 f - glVertex2f(xpos + w, ypos + h);
; _8 b" n" Z3 ?$ @- C* ?( O3 [7 T - / n' r5 z5 d5 W
- glTexCoord2f(1, 0);% P( u! P% ?, z' K4 g. B5 J' |
- glVertex2f(xpos + w, ypos);
: k- }) ^* S; {8 n
7 ?0 f p; S9 |5 j, q& f- x += (face->glyph->advance.x >> 6); // 字符之间的间距
: }+ i% ]* C2 L& G - }7 {9 d0 s6 w7 A2 y' E" C$ a p
- glEnd();7 l+ q: x/ L3 V6 a" y$ U
3 K2 z5 I' p) e- glDisable(GL_BLEND);" F5 D" L1 Z; }) J
- }
2 r, f. {+ O. v, o5 H7 g
( Y9 U. f$ X. X# L. G' A! D- int main() {! h4 R% c( @( ~% Q
- if (!glfwInit()) {- A* Y: F/ \* R5 s
- fprintf(stderr, "Failed to initialize GLFW\n");; C5 c) D c, W0 U
- return -1;
% l) X% r/ _6 y; H# {% f$ K - }
, p. N; V; x: {( M! [ - ' N# }/ A% n7 v( V8 N" E6 \; s
- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
+ ^# A" J6 _7 X) @8 P, ^6 } - if (!window) {
. j# N8 L h/ y+ Q. p2 a - fprintf(stderr, "Failed to create GLFW window\n");. ?# J% M/ ?, n' O7 \+ s/ o2 D) r
- glfwTerminate();- [# c( W) x; h
- return -1;: t( x; G# U2 D! a% r
- }
+ k* x0 c' b% ~( J3 v* u! K: @
+ T. r4 e' s- H4 U8 \5 x- glfwMakeContextCurrent(window);3 L$ s& {2 F' r7 D
- glewInit();
1 t2 n$ F5 }. ]" B' w: G- f
: C- ~3 F1 t/ [- initialize();
2 {7 ~/ A& {2 { @, Y% L - & s$ K! _5 v+ m: J K
- while (!glfwWindowShouldClose(window)) {- `# w5 E4 F8 z5 A% i7 ?
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);9 n0 F* c: u1 a. t
- glClear(GL_COLOR_BUFFER_BIT);4 `4 u8 H1 G! A1 l* j' N7 n& W
- 8 w! e! S! V6 R @* I, j: S
- glColor3f(1.0f, 1.0f, 1.0f);
" f& T7 z8 {$ D( Y8 @6 i - renderString("Hello, OpenGL!", 100.0f, 100.0f);3 v, k, X/ D# B6 e
+ ^) k, D S& o/ b3 {- glfwSwapBuffers(window);# Y* b3 E6 C$ W y5 e
- glfwPollEvents();2 d- @, b' ~# Q% b! G
- }8 y( X1 _' ^4 q3 {* a
- V# K y! e& Q% W3 i% P
- FT_Done_Face(face);
! }1 i5 b; |' B8 N8 N - FT_Done_FreeType(library);
) y% d; \9 t: r- m4 `( p
6 s0 t8 i: v4 l6 s; f8 W+ V8 W/ @- glfwTerminate();5 p6 F" K( x# d) {) f. c
5 a" [9 u) e% T, }2 O8 Z, t5 m- return 0;
% u" }2 ]9 P4 r/ V - } k! M% H. U4 w
复制代码
6 S1 [* a3 u( z' _0 K9 x% T/ m4 M% n& d
|