本帖最后由 shane007 于 2023-9-6 15:32 编辑
) t" X& o6 D' U9 [* j0 b. @* q+ a! q5 j7 X! d% f/ H3 `" m
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
5 ? h2 M3 z: U# M' T本代码经过分析以及改写之后,将取代游戏原有的显示函数。. a7 Q- e! e }. g* g& t
' J( q/ k- I/ s" C8 ]0 m5 B代码详细说明如下/ ] [& _, I- \; O% L, C
/ P1 \' M: ^7 U+ A( P- 在上述 renderString 函数中,我们有以下关键部分的解释:
, q; V9 T! L; f8 g" E3 A
, y1 a8 T8 v; R- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。$ M8 y3 W' H" v: y: @+ Q J$ {
) d: ~4 ^0 G1 b+ k8 u- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。8 s+ D8 Y! M8 O) e [% j
- r2 R' A5 A$ R& V3 U2 H& F
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
% _2 O' t! P9 D# B, w$ ]# c
: I) k2 r# O. S- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:( I& `6 i# G* ]- c. {
2 d2 M+ Q2 P) H0 N- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。/ v& w* @6 u# Z" k" B; O
& u; V* X' E/ D( G, a; b+ I- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。: B( T# l/ P* T
- 4 F4 C' ?2 `3 _: d. Q( |# g" c
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。0 d! k5 d% \+ [; ^0 @% T
- - B$ N/ D7 Q, i- V3 G5 @3 @
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
; U! B0 A" G/ R9 I2 F
! o: H% r( a4 x- p/ Q- ]7 w- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。! Q _4 t& Y2 C
) D/ k+ {9 L- t- B$ j" ^- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。. N" G' |9 v- C9 \$ x$ n& m
复制代码 - m' G, j9 ~, h, w/ q% Q9 D3 B
' L2 r2 L2 ~! w8 D; b
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:$ O- [6 p i- _8 n: \
4 E7 z4 a9 d) Q$ M/ O; `- 参数:
& G' A* v% Y* R ^ d' n0 A' }
1 u; W: a! q% y8 d$ R6 P- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
% \0 s5 g9 c) N d6 z - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
. E6 I4 w, g |5 {4 o1 C5 Z - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。' J3 _7 X1 Q% ]. N
- 功能:: \) i. ]# q9 t9 o- @! n& D
- * Q+ s( I/ l6 Z# B$ n+ h% O, l
- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。! i# Z/ W9 r* \7 O$ W+ a
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
# Q3 W5 g: T- X$ ~% b - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。8 @- w- y H% k" G. B
- 使用示例:
! c u1 N. b+ c& P$ M - : E. ?3 W) r3 _6 E% C/ w. i( V
- c
9 Y1 ]( Z$ m& l' i1 P - Copy code8 ^& H6 q; t- A% l8 \9 M
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);
" ]' ]- x' q: r! | - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。* M! {) |% v) d9 a. n( W7 d2 [; l- ?6 B
9 S% L. V5 ^5 i& `- 错误处理:
4 a5 C2 @+ q7 X
" ^: T8 T# A& w) b! ]- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
7 }" v3 k$ h4 m4 _2 O& Z! W% W - 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
8 M5 R2 B7 j+ a& [5 q
2 h8 W2 @; ?% w6 S" W) W3 }代码
- ?; w, g$ a, U- O, X3 _# |
4 W) U1 [) u* E' r# r6 S- k) B- $ ?+ F6 G% x. j, r/ \+ [# O
- 6 n3 r8 I4 B) M7 h! `" ^% p
- ( l3 l3 C; Z! [! n5 v
- #include <stdio.h>
- {: H& m/ A" l# J: R) ?& } - #include <stdlib.h>5 i8 }6 g6 `5 e2 e4 G( a
- #include <GL/glew.h>
8 T' _" K/ \4 y1 s - #include <GLFW/glfw3.h>
- R0 R1 _( S* U4 P% s - #include <ft2build.h> f5 Y1 R+ b' _9 g
- #include FT_FREETYPE_H h9 `. | F/ b* x6 Q1 W7 L
- : e/ A h7 \$ D, B/ c5 F
- // 定义字形数据的字节数组
+ v! _1 u3 D* N8 l: K - unsigned char fontData[] = {
! ]4 }* E+ I( q - // 字形数据的字节表示& P6 {1 k- N! g. T' |
- // 例如,这里可以包含字母、数字和符号的字形数据0 d) t4 T. M: Q
- };2 N, N) D$ f8 n4 z& J
9 I& ^! c2 K2 X+ s1 e5 m' r* D- FT_Library library;! g+ E6 f2 m3 A! ~/ q5 a
- FT_Face face;8 p' F. l# `. @" K$ h0 n7 t2 I
- GLuint fontTexture;
5 F& K2 d+ p- U' n) S* e% j+ B/ L
: \' b. O* }+ E$ \- // 初始化FreeType库和OpenGL- o& K( w+ @! S8 I
- void initialize() {( U7 v" z9 ?7 y/ }. ]# Y
- if (FT_Init_FreeType(&library)) {
4 ~1 B" y' e: Z2 a3 x' T - fprintf(stderr, "Failed to initialize FreeType\n");
" G3 S0 w" p3 z6 Q- t+ b- p8 o$ m - exit(EXIT_FAILURE);
' x3 j4 _9 y& E1 i - }6 @. H' q& e0 S Z: o
- ( C5 F6 F0 c9 g
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {0 J1 k! a9 _) T6 s' g3 T6 [& N
- fprintf(stderr, "Failed to create a FreeType font face\n");
: C' H: P. B+ H - exit(EXIT_FAILURE);
3 S# m* {: d' O( k - }
i+ h6 i2 I' |/ k0 b. p" i! ` - ; _, ^" X. s9 G4 O: S
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
$ C1 a# x7 W3 J8 @/ P' s3 P - fprintf(stderr, "Failed to set font size\n");4 Y, c( Y7 ?# i) r
- exit(EXIT_FAILURE);
& }* [* }! ~9 M - } `+ Q2 M* y6 N
- * d4 C3 ?6 F# {4 i6 ]
- glGenTextures(1, &fontTexture);% h! P0 V; C8 z% @4 E" k
- glBindTexture(GL_TEXTURE_2D, fontTexture);8 t: _. E7 Z) d* V
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);: z2 |9 a6 A# R. G- W" M4 O. X
# A& [7 q: T9 }$ S& n h- // 将字形数据传递给OpenGL纹理4 l) ]% }& k; T! {3 e
- for (int i = 0; i < 128; i++) {' a. f7 t% a) o2 K
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {. r& _/ w1 ~6 O( E) K
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);$ g% A) U' z( | j& P X
- continue;
( ?' s+ x% T. o7 S1 l - }
3 c% w( t4 P8 [& D
7 T; ~- W2 a( \3 z% M; o! X0 K$ B6 u- glTexImage2D(9 V( X' ?: Y- D) }) ?) X! t
- GL_TEXTURE_2D,. E5 o6 u; N. U' e1 q0 |# }
- 0,
7 Y7 j0 T# |8 t) A; H - GL_RED,
# ]8 |( D" m e3 r, U - face->glyph->bitmap.width,' ]5 t, M6 B# S( i V' `/ [
- face->glyph->bitmap.rows,
1 j+ |7 _+ {( Y4 V$ j7 E8 d - 0,
* ~. u4 b6 c( P/ |+ C - GL_RED,
" Z. d: Q; h: L4 D8 v. v6 o - GL_UNSIGNED_BYTE,
! }& d6 e/ q: ~( A# ?9 B- _' l - face->glyph->bitmap.buffer
% i8 T4 i w/ J" A9 b - );- B$ x2 q; V0 J% T, v: q3 j
- - q8 {+ ~+ O3 e" q
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);- u- u+ `$ u* @, {' Q$ X/ {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
) y4 j; o3 q$ ^8 e z - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);2 @; o* z( }7 j3 p* L, q
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);# P- Z3 \8 U! A; J; {: ~
- }' R! N1 R3 v) H4 e6 B
- }
/ Q# A& `. y& ?3 n3 c7 f7 K( A% b - * |5 u; D* M% J8 c: S! h
- // 渲染字符串3 \) a& y" g+ X
- void renderString(const char* text, float x, float y) {
6 R* h* F; E( B% J3 O# f; ~1 g - glBindTexture(GL_TEXTURE_2D, fontTexture);
, v% ]' Y" y" z/ X* {" Y$ c1 V6 x
& x, k: ]4 l5 d' h! N7 Q- glEnable(GL_BLEND);
5 I" P4 T5 `0 y7 l7 A3 n# L& n( M - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);. i1 Y2 t6 w! z6 {3 S
- * w) H" a7 _ k" l7 t5 h! u
- glBegin(GL_QUADS);! x* [/ ]0 Y6 S( n/ H% C' V
- for (const char* p = text; *p; p++) {/ |2 H) E! @) h: M* K' E; J
- FT_Load_Char(face, *p, FT_LOAD_RENDER);
5 L# K$ P: D5 U6 { \( f$ I - ' N) | }1 j3 M1 m6 _; c
- glTexImage2D(
. |& G* r/ j/ s" O: j - GL_TEXTURE_2D,
f9 @ P: [! U' G% m, K - 0,9 T' X/ H/ h! ~0 ?1 f
- GL_RED,
& F4 p: v: p |' ^+ ?- W! E - face->glyph->bitmap.width,
7 x f$ n& V C9 G( I6 E - face->glyph->bitmap.rows,
9 \4 g6 }- T! h& f$ ~ - 0,
0 N: M F' E( a# _ - GL_RED,
# H7 A1 L* w9 o) A - GL_UNSIGNED_BYTE,- M" S1 l# d) N% f! p2 B
- face->glyph->bitmap.buffer) ^ Q! x5 W) o7 L5 Z& v
- );
' ]# ]3 @. e1 x. a$ l: r! a2 k - d8 J& k5 @/ ` g
- float xpos = x + face->glyph->bitmap_left;/ [/ L6 U& X: ^. g
- float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
- ], x5 |- d9 N) Z& H4 ] i - % ]2 b: t5 @% Z7 M
- float w = face->glyph->bitmap.width;
/ s/ h5 v: b2 j* @' h! [ - float h = face->glyph->bitmap.rows;! \2 q/ P/ O0 D, M. W
$ U2 A4 k$ y% H5 f- glTexCoord2f(0, 0);
7 i3 s3 |& x# A" X0 S( X - glVertex2f(xpos, ypos);
3 ^- @# c3 O$ H+ }; e: l } - 5 E( B; D3 ~* A8 d1 c
- glTexCoord2f(0, 1);5 @$ _9 A* ` I6 ~5 V6 x( r
- glVertex2f(xpos, ypos + h);9 B3 j' V0 ~7 L O
- 5 m* A# [) w& k$ A1 d
- glTexCoord2f(1, 1);
- m- c0 p9 @. f9 O+ C - glVertex2f(xpos + w, ypos + h);
! u' H: O5 C, I7 Y s2 E - 7 a4 Q+ ~* _' `+ t* p
- glTexCoord2f(1, 0);0 ]9 Y8 m# |& Z
- glVertex2f(xpos + w, ypos);, @7 G9 R# t7 i) [
+ s( U9 ?9 Q& b. Q3 ]! q- x += (face->glyph->advance.x >> 6); // 字符之间的间距. o1 F3 I" r) \8 O8 a0 R& r
- }
, [1 I& T6 A) o1 i, {7 U0 W - glEnd();: c- Z q" x) X, ^
- # r. @0 b! k* o( t# h1 c
- glDisable(GL_BLEND);
& g) x) @) E, @; F - }
$ x9 v6 C+ A- S) B+ d1 \2 W5 J - . b! t) B# G; x# W3 n
- int main() {
5 |8 e8 F" r$ { - if (!glfwInit()) {! x4 @" q( t5 C# T6 _5 U
- fprintf(stderr, "Failed to initialize GLFW\n");
. X V0 M4 w |8 p$ |" b2 ~ - return -1;
) k) K3 X7 F7 h - }
% `3 q( u) Z& k. p
; N+ @) n# G- c! n7 G- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
1 k* ^' ^8 y4 a6 Z" I - if (!window) {
# G" W% ^4 M9 o1 ]# c/ x9 e3 K' p - fprintf(stderr, "Failed to create GLFW window\n");( L. V3 b/ b p) k7 ]9 Z5 U
- glfwTerminate();! l! o9 d/ s8 A: f
- return -1;
7 g" [8 o2 P5 B% T4 l! M$ Y+ j8 f - }
6 v9 ]9 O, }8 J7 r/ n& I9 m
+ ^" x" b$ G( h! V2 ^- glfwMakeContextCurrent(window);
8 T" @1 r1 _( L3 l+ z; P- g - glewInit();
. U8 L8 }+ U$ G, q
8 V1 W9 e* {; ]6 b- initialize();" o0 u3 c4 G! D) j* j4 i
+ t+ h- T( b3 ]" ?) U- while (!glfwWindowShouldClose(window)) {
5 e& N9 D2 u6 ~2 S3 C% |* ] - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
4 q& N, r: Q' J: [ D/ C - glClear(GL_COLOR_BUFFER_BIT);
9 Z7 M% s8 j/ {- a3 j2 x0 J
* d9 I5 J6 s8 E0 J: }7 E; l- glColor3f(1.0f, 1.0f, 1.0f);4 k8 w, F! M2 i" a
- renderString("Hello, OpenGL!", 100.0f, 100.0f);# F7 s' S. y9 K. W3 h- u
8 n2 o% f8 ~& ^- glfwSwapBuffers(window);
( V ~4 |, C2 e! n' P; ]# U( D - glfwPollEvents();
6 z, M. d& J: [0 g. ~ @ - }
0 f$ H& z$ c0 f w$ O6 q" `8 J
( r6 i/ ?- E+ c3 L3 t) {3 s- FT_Done_Face(face);
. X1 D3 _: V& K/ K7 [3 L - FT_Done_FreeType(library);6 f0 W7 G$ s9 y, w* B. R5 K
- 8 J2 I1 X% j, g/ w
- glfwTerminate();
; k' U1 c( w1 I3 {6 W+ c; \ - , O2 t3 H, n G! a
- return 0;
! \5 D7 R8 H- F - }
7 }9 S ?+ y. {) h6 v. R6 G
复制代码
4 T6 P% o- O! r$ S& M8 w& \5 P" _3 k( G
|