本帖最后由 shane007 于 2023-9-6 15:32 编辑 ' c( i" B F+ e3 G x
; X+ s% p9 Y" m+ T6 [1 E2 ]( A" k
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。: r1 F% p0 t# k" _
本代码经过分析以及改写之后,将取代游戏原有的显示函数。$ y/ b. w% i" o5 t% ?$ b/ R
; t7 D- M0 x- V, Q3 }代码详细说明如下6 r: n1 ]$ c5 M' S& V
5 G$ J& |0 w9 @3 \) i! Z' |: j% w- 在上述 renderString 函数中,我们有以下关键部分的解释:
1 x/ N; R0 l% x& V1 P - ) t5 |$ I! ^& J3 [ `
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。- _( K) l/ l- Y0 {
+ v( j- X2 ]) ]* U- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。9 w5 r: Z' {3 N3 y
- 7 ]" n- W4 v2 s' G$ S
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。) O+ Y, J. B9 j6 Z& `9 ^
- : p/ o6 x" ?) g; l8 p& r; D( T, L
- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:2 M4 J* s' j3 c$ [& C
- Q- i5 H! n3 Q0 Q* F
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
+ L6 ^! h0 t% b5 V - % }) B' M& l( k/ x1 B+ U
- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
6 z" o) G: h; S1 P. {+ Y) j# r6 ]. ~ - 3 U0 \: |' Z8 U
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
; p7 C1 d G( |2 E4 \1 ~% K - 0 p7 U; Q' V, \8 x( Z# d
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。5 {. u% u; ?- v7 z3 r6 Y; l, g
1 `! o) i6 @' V8 ~- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。( ]$ N, S; f6 e, ]; c5 {
- ; i. A5 S2 A1 K; O9 X/ q
- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
' _3 I* l! q2 H9 D X; O7 E- r
复制代码
6 o. H1 ~. ]5 F/ L! d3 x! m
2 o7 G- {% ?$ J0 v2 X* t1 Y5 A; o- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:5 J. D, o/ N4 q w
- ! y+ h o* }9 R+ F3 m
- 参数:
, A# V% s4 l W' U3 P+ N/ w - ! z L8 E8 W+ f3 [" d, q
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
/ v& \6 G. q x8 `2 i. f0 W - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。' g" S; ~8 }1 Y" L/ X4 v& S5 o( B
- load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
6 o3 f% h, b. b - 功能:
( f& h( F2 s" S
3 D& U8 c. o* ]7 ?1 @9 I1 l- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
- x7 X H& w1 R1 `* P7 ? - 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
9 O' |& H) O+ { b/ t - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
8 Y d# L c7 h! P, `* r- P0 D1 N- y* z - 使用示例:# y2 o7 a2 _! ~
- % \% D+ i5 U) }# ?" A# B! T
- c
1 `6 |- T. B+ j K1 T7 v8 A$ T' ? - Copy code( X) U% e& H! y- j$ r7 x1 X0 i
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);
' j+ s( W8 }# ~ - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。( z2 t2 B7 W; I8 g+ @
5 I$ O+ n1 l. q$ R- s. P- 错误处理:1 F3 `5 n7 Z* w* X7 ?5 \* [5 R: X% z
- 4 F* x! D4 f9 r4 ^" f
- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
+ B9 R/ D% d6 w, M/ I - 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
1 ^) G% @. O; a2 n e4 r( h6 P ]3 Y, k2 Y2 }1 S# Q
代码9 d) E8 w- o/ @( |
& e5 v3 a# J3 ^8 V
; o# `5 }0 q6 W8 {7 G+ W- ' n9 ?0 s1 ?; ~/ B+ K
% E( v, g! L9 @( @% l- #include <stdio.h>, Q: j! T$ V8 @3 o) b8 Q8 ^7 M& I( D) p
- #include <stdlib.h>) I9 F+ u' s$ w
- #include <GL/glew.h>
3 z2 L; x! E- H# y4 a8 D - #include <GLFW/glfw3.h>
: |4 z6 P) _# w3 N3 U" k/ I - #include <ft2build.h>
8 A& ~. s. n9 y3 \$ d - #include FT_FREETYPE_H6 [' [: Z$ q- J# T) a6 ~- e* [
, B4 {! d5 k8 b; E* g& r- // 定义字形数据的字节数组
) O7 m7 \* ?2 U! e$ I3 \ - unsigned char fontData[] = {
3 |. w% g' |% d' q - // 字形数据的字节表示, g7 L$ V% \' B+ W2 }/ \) g
- // 例如,这里可以包含字母、数字和符号的字形数据- G. T% }0 t- d) }2 h6 z
- };
/ l$ J2 v" B) w+ z8 D9 g7 O
4 z6 M$ o! ^7 g6 w7 m9 F- FT_Library library;+ K4 I& x B) A0 B; |" N5 o
- FT_Face face;+ r# f0 Y& r; R9 l9 R. e% K
- GLuint fontTexture;
: v1 \$ c8 F: q8 ]6 L- `
T6 v5 k) |# B3 N; x( R- // 初始化FreeType库和OpenGL4 \ U: q1 E5 Z2 U7 _3 B8 r( V' |; p
- void initialize() {
5 G# b- E% {5 ]: q+ M/ X, \ - if (FT_Init_FreeType(&library)) {
0 J( d7 t+ W: @7 G- G$ j - fprintf(stderr, "Failed to initialize FreeType\n");
2 a1 _. q4 I3 u% Q - exit(EXIT_FAILURE);: m! f' x/ _# u1 t r
- }
6 y) S6 |( C, o
$ O0 K' F- Z2 }% }6 e* C4 V3 y- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
$ \7 \; i* n* m6 b! U& s! W; o - fprintf(stderr, "Failed to create a FreeType font face\n");
! o" {5 }+ Z8 h$ U! u2 | - exit(EXIT_FAILURE);* x! E% }; `3 t
- }
. j4 i! G, _. n& z- C. O( b4 L: u# o
; W" e& v9 A I8 ]4 C) d- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
: p& \, F* J! R# t- t% E2 C! X - fprintf(stderr, "Failed to set font size\n");1 N6 Y( e- L4 X9 M% v
- exit(EXIT_FAILURE);
! o. Y' |/ u0 l6 s* }3 i- N3 S - }4 E) p. m8 |( C4 [2 D7 c( b$ k, I: P
8 X( f* H( Z2 I2 n& V6 ^, g- glGenTextures(1, &fontTexture);
" {$ r7 L5 i. {( _- O4 _1 N+ f5 X - glBindTexture(GL_TEXTURE_2D, fontTexture);
. Y+ L4 `1 `/ Q0 w: C - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
9 a; M6 ~; f2 U/ b2 ? - , |- m: p6 U* R7 v& `" K$ i
- // 将字形数据传递给OpenGL纹理: ?! s. L A( c- @, a
- for (int i = 0; i < 128; i++) {
* J% [& n$ K* E* p' @- `" j( B - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {! F. Q3 w/ L$ O; ]9 v
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);1 N& o5 ^0 i" B. T. {
- continue;
3 \$ q8 H- a Z7 {- w. n - }; `2 R% i7 r+ v7 F7 v: h. ?, x
4 ]% {8 |. j- c; i: D5 _) b- glTexImage2D(
0 M- ~( L* `, Z' j" |3 j! z - GL_TEXTURE_2D,8 q) {' Z a1 a, n, c
- 0,
& b( E5 K% T. G! m' b/ s. F - GL_RED,
9 C0 K, n$ w- x) y0 Q4 i5 r1 @ - face->glyph->bitmap.width,
/ D2 a5 U: h% j$ Z - face->glyph->bitmap.rows,
; _( R5 A2 q9 }% V2 l8 i - 0,
, K8 f& l# d8 D, F \4 u - GL_RED,6 b6 i: c7 {3 b# ?1 a/ ?$ L, g) Z
- GL_UNSIGNED_BYTE,) ^0 B8 ^& c& y
- face->glyph->bitmap.buffer& V+ a. h* D: t9 ?5 x# z
- );( m, i1 P: d7 L9 E7 f
1 l- f5 w# z; U$ N, E) y- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
) A8 u' n) B$ E; ~) ?1 w" T - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);; v; D% Z7 N( a" w3 L% Y- S9 ~
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);' b/ y0 `8 L. r8 O ^/ c
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
9 N E* o7 X6 B' X v" `9 Z' k - }' V% V# M8 S5 `0 P3 z' b; D/ v
- }) b" ?1 Q9 y0 y/ i" u+ B8 d+ D z
1 s0 a4 z2 [( s( f* |- // 渲染字符串# i* {/ e/ W* g# ]" b0 h! ?+ l
- void renderString(const char* text, float x, float y) {" z# M& i P8 b& K4 H2 C3 I
- glBindTexture(GL_TEXTURE_2D, fontTexture);
/ g7 ]4 W; A- T- I4 u; t1 g% U
) B0 D4 a& N& h$ I- glEnable(GL_BLEND);" Q0 C' s2 }# V# x# w- s% W
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);: N( W8 k0 u/ S9 G+ i+ [
# }$ q7 {7 Y5 Q( H% I8 U- glBegin(GL_QUADS); T3 W+ ], P9 u1 s& ^/ \/ B- ^- b
- for (const char* p = text; *p; p++) {
/ m" O5 f M; m, B6 I8 u3 s: b# P' { - FT_Load_Char(face, *p, FT_LOAD_RENDER);6 A6 R% S% {' R6 E. F8 j, G3 W* X
0 p' @4 W4 ?7 c9 M9 ^: F; N- glTexImage2D(' o1 H, L* H3 s( q) T4 \9 B2 H
- GL_TEXTURE_2D,
[8 h& d5 \: F3 t$ @* F: R - 0,6 _* I9 c& Z) I _$ A* J
- GL_RED,- d0 u) p# U' w' K5 g! y5 I
- face->glyph->bitmap.width,
) e; n: _4 Q: ~- Y2 y - face->glyph->bitmap.rows, z2 V W0 d4 o5 }8 k( {
- 0,
5 Y7 J7 D8 Y* P3 O9 m. Q - GL_RED,- M2 @! C2 }- [
- GL_UNSIGNED_BYTE,) U$ x8 S6 R5 o% N( X" M6 g5 \! n
- face->glyph->bitmap.buffer
- w! r! b1 r4 o4 V/ p3 a5 @ - );
9 J: z0 E. V7 |
Z: T. U" F) \. I- k9 h- float xpos = x + face->glyph->bitmap_left;1 w% i9 v' B9 Q# `1 D7 f
- float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
$ }1 [. w$ ~" u3 b2 Z8 C9 I$ a, f7 \1 {
" m# _$ b" o% R- ~# z3 G- float w = face->glyph->bitmap.width;4 x$ x9 i9 q! q# F& h9 L3 o0 J' Z
- float h = face->glyph->bitmap.rows;) J: c# I3 t' O. }
7 `$ E v5 r5 m1 Z9 R- glTexCoord2f(0, 0);. e, A% S8 h: K. f/ Y
- glVertex2f(xpos, ypos);8 v: W( W! z$ W7 {
- . U2 W! u$ T" G% F+ v0 ^5 _+ j5 A
- glTexCoord2f(0, 1);
- m$ z3 {0 S: W1 x - glVertex2f(xpos, ypos + h);6 s6 a, C6 w _* r1 r
- ! S0 ^/ r# e8 k. p; u
- glTexCoord2f(1, 1);
& V* k; y$ w. h2 [7 h6 Z - glVertex2f(xpos + w, ypos + h);3 A; d% N& C/ r6 g; l% u
5 }( R5 y4 T$ A2 ?( z& `- glTexCoord2f(1, 0);" U6 f) y! j$ i8 g+ O
- glVertex2f(xpos + w, ypos);' w2 [# d, S/ b! _. ?+ J; _7 {5 ]% m
- 2 I9 }$ ]5 V+ P0 H, l# w
- x += (face->glyph->advance.x >> 6); // 字符之间的间距
+ e s4 l4 i7 o+ A: ]* U - }
4 T1 ^: h; | ?% C+ { - glEnd();1 r0 t: W: T) y u% u! l& \# o
7 ^, s0 N* ~$ t) O; ]- glDisable(GL_BLEND);
0 T3 i& p$ {$ n( w: \ - }) |2 T& }% H6 T$ S% ?! G4 e
* {) l6 j& ~' P6 X; U- int main() {# ^2 q$ _. G# C: q% W: i
- if (!glfwInit()) {
, F" K2 D0 {' d9 G# Z" A" B0 C+ N. Z - fprintf(stderr, "Failed to initialize GLFW\n");
3 ^# Q! r# ]# o2 c# q6 Q8 ` - return -1;" ]* q* \7 ^8 n1 s5 h ]$ ]! A" ~
- }. I$ b7 j- h$ J
& H/ U; d6 J; P w( H5 P+ w- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);3 d. Y7 ^2 V7 \
- if (!window) {
6 Y& q3 {) }' i% U) e/ p6 r# `1 _ - fprintf(stderr, "Failed to create GLFW window\n");
: Z9 U! h+ T, O( h5 v - glfwTerminate();
' J% T1 w. \7 c0 Z3 u/ `" [$ B/ z" V; z - return -1;6 B/ t) c- d, F% w. {& C
- }2 [9 X3 n @1 @( ~
; N W8 B! W- j9 ^ i9 D4 a2 t2 j- glfwMakeContextCurrent(window);: T- h6 \( x7 o5 U
- glewInit();) H# r+ ?$ x' e: W
- 5 H5 T& m! p/ y7 g: e
- initialize();
% l9 l( G6 {% ]7 N9 ^# f( g" V; C
' e. {. W4 U8 Q* |- while (!glfwWindowShouldClose(window)) {
: ^0 Z) ]! u$ G) {- X+ H7 D - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); }$ X+ r/ j6 ^" x3 G# ~7 {8 \
- glClear(GL_COLOR_BUFFER_BIT);
& x B& o( u, N - ( f' q5 u8 X/ [% ~
- glColor3f(1.0f, 1.0f, 1.0f);2 d( E# M% P2 U! j
- renderString("Hello, OpenGL!", 100.0f, 100.0f); w' L9 n5 r( X* A& m# D& X l
5 U: F& W X, h- glfwSwapBuffers(window);4 J/ z; a1 ]0 S
- glfwPollEvents();4 P* x: y+ n6 X$ R
- }$ m# b& A' S2 |: T" t
& h1 u( X9 \: e& f& w4 }! e- FT_Done_Face(face);
: Y9 t% B% C5 ^% P# u- w1 ^2 m, Y - FT_Done_FreeType(library);+ j2 Q* h: C5 Q9 `+ J) R
1 S5 _9 U& M0 m- glfwTerminate();; r& E. R2 O6 p8 V& J5 j
* ^% E4 k+ q+ [- return 0;" X' o. N& F3 Y$ B
- }
/ P. D+ I' X, N! w
复制代码 * A3 F0 |0 r5 n7 q) T( F B4 c/ j
0 c6 x% d2 f* d& X; q1 T |