本帖最后由 shane007 于 2023-9-6 15:32 编辑 5 A9 z9 B/ b! j9 l! M0 S
& ]2 d6 _) U9 @$ S: D以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。+ p* L( o9 i5 }
本代码经过分析以及改写之后,将取代游戏原有的显示函数。
1 N& n- f6 Z+ N
) s" i! @% _* u: B8 p: i代码详细说明如下
- b; p8 B. i9 h8 ^0 M/ J
$ D, ?/ P2 H; u2 a6 p( |. ]- 在上述 renderString 函数中,我们有以下关键部分的解释:- n# V0 w) D: @
0 K J$ L. j$ b$ s' m/ s- `- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
9 _: G1 Y! ~/ |. {1 o - * q1 V8 ]% }( F9 v. y. C
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。( N9 |/ w$ M3 Z2 F& I
4 l4 ?: a+ J; A" G1 @1 T% ^- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
, W. d C; g0 R- G
& B4 T6 j# U6 ^* a- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:& U# x" s! \7 Q% N/ @ Y {
. w% v; T1 q v. e8 z5 B- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
9 \+ Q* h( Z* h6 U+ d
0 G/ |' F% k% P9 h4 H+ }2 A$ U, n- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
' ]7 y$ D) }; D1 u& A) }2 Y4 g* P - 5 F% ]! b! h' y+ i. l% J" M0 L
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。6 f; t" B- b0 g; Y
- & \8 c* O* i3 O4 J# o
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。# l0 ?) ^+ k8 L+ `! r
- # g, a$ Z* L) a! Z7 q& w
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
- A/ [$ U$ L8 ~" A - $ x, D! ^8 ^! g$ t% J
- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
( i( g1 I/ Y* o/ U4 K
复制代码
7 ?4 x6 b# O8 Z7 K- |8 x# J! l: Y7 R/ O2 [; ^
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:0 ~) A+ t2 p# K8 v, r
- ( I8 _9 c' r' `
- 参数:5 u' m& o- n# S: D4 F7 m, B
- 2 |4 X6 ]! t2 q! M( P
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。3 z, m; G$ ^7 ?& b8 L
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
. G" U, _- J" Z( y" ]: ?0 d - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
: d3 o2 x5 Q4 i8 _! t2 l- W6 r. ^ - 功能:) b1 b+ i4 g4 H3 g
% U# Z, X) R$ l3 W* G4 Z- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。) ~; s% J" H+ D8 t6 Q6 f% m
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。3 n9 F5 ?. R5 |* M% S
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
% y0 J2 I/ i$ r! u5 D - 使用示例:1 j/ z; ?: Z0 d0 E+ P
; a7 V6 H. {$ G4 h) q2 q! [% _. m- c6 h, f. {2 M% X# W; K
- Copy code
9 \" x) w" B, y1 Q X$ ^: x/ x* [/ R - FT_Load_Char(face, 'A', FT_LOAD_RENDER);
+ X& \* o/ s. N - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。7 Y* {' ?# e! g9 H" C$ v
% a0 `4 J4 v- S5 L( ?; ^5 r- 错误处理:# e5 s( q, a8 Y8 _
- 5 h2 f' H! D' H" W
- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。, k" P+ T' j8 ^6 j# y# w, i
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 " e2 w3 \% D; n5 Z1 o
+ Z* i; z4 B: T& V( C
代码
" s- j0 I0 h. N B6 {
5 o b2 u9 K3 }* z# R
9 V( Q$ e2 H& Z: T9 z2 z
) M% u* ?3 R" ^/ h
+ m' G: M1 Z% P& f1 y- #include <stdio.h>5 u' v' J; ~0 Z! u# r4 d
- #include <stdlib.h>+ S! R: j& n4 z( u5 n/ }) n1 W
- #include <GL/glew.h>
* Q! q% `' z6 C, V% l) \- Y - #include <GLFW/glfw3.h>4 @+ n7 u& e* O0 j7 ^$ j
- #include <ft2build.h>
) M8 ]3 o% I5 z5 k' W2 l+ l - #include FT_FREETYPE_H% C9 J8 A! E+ z5 a
- 8 _8 m, M! `3 G( R
- // 定义字形数据的字节数组
% V9 i+ N, S+ d( [ - unsigned char fontData[] = {
+ ^& y1 Q! z* K7 \) y - // 字形数据的字节表示
2 x6 A) R( R- u$ ]3 r# `5 [ - // 例如,这里可以包含字母、数字和符号的字形数据
' Y0 A7 N: r. T) |( B - }; ?2 b/ r; ?! N* V0 r2 x1 s
9 _7 s2 P; `! V8 I) [& j- FT_Library library;
& ~2 y6 C, p0 z9 G S( z) ^+ o' b - FT_Face face;! k* ^; ~0 `! `8 z8 T1 G* v
- GLuint fontTexture;
7 y% y6 `# T% `- w; \7 Q - ) C) a2 R) A2 E; n
- // 初始化FreeType库和OpenGL& l' H" w/ `/ d% K9 I
- void initialize() {) @7 d- d: f E ?
- if (FT_Init_FreeType(&library)) {! O+ P0 p4 c6 ?, [& N
- fprintf(stderr, "Failed to initialize FreeType\n");* J5 ?- P4 }6 _
- exit(EXIT_FAILURE);4 a- [4 K+ S5 ~, a
- }
6 v5 Y# q9 ~* v2 b- l - & T [( K& k7 z! C4 Z |
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
; V9 k0 ?( U4 s, c$ p% d - fprintf(stderr, "Failed to create a FreeType font face\n");
{+ Z" B5 T$ D - exit(EXIT_FAILURE);
- W$ B' [8 _+ Q- {! V5 } {( q - }. z6 o+ e H( g: s
9 n2 ]# R* t: p% E8 N/ w- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小+ h. O( |9 ~6 w2 h4 L2 o
- fprintf(stderr, "Failed to set font size\n");. f" O: w1 j% F( Z9 ~
- exit(EXIT_FAILURE);
0 D; [9 P6 g& ~" y: U6 O7 U+ s - }- z: J: D: w* j; p% T8 e6 E
- 9 g4 t: c7 E- i' @
- glGenTextures(1, &fontTexture);) o* w8 u1 L* f
- glBindTexture(GL_TEXTURE_2D, fontTexture);
+ q. F- j& X! u- M) y' W - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/ H, n; J: ] s/ c; X' b# ~# A - 7 A8 l; m$ Z' Y9 o% V
- // 将字形数据传递给OpenGL纹理2 @( e( `' O2 X$ Q# F1 I. `
- for (int i = 0; i < 128; i++) {1 s3 O* e- w" m- n' c
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
: _% |7 r$ H/ `6 G - fprintf(stderr, "Failed to load glyph for character '%c'\n", i);1 u& I* n: t8 `0 N, s
- continue;- n6 U6 Y! T" `- w
- }
/ u7 S& A$ d8 }( ~* I o9 \ - $ Z+ r1 F0 N. n6 _5 Q$ Q/ @
- glTexImage2D(
( M7 x2 l1 d- p1 b4 S - GL_TEXTURE_2D,
0 H7 v2 r7 d6 s - 0,* a9 W' M m2 p
- GL_RED,
" ` ]# ]2 i( Q5 ^: a - face->glyph->bitmap.width,( O! y' b6 h' y0 }0 C8 g
- face->glyph->bitmap.rows,
8 ^- [) N, l* h* J* n" z - 0,
4 u7 ^, {( E8 b0 T - GL_RED,
; D3 B: ?5 N% G0 O+ `$ u - GL_UNSIGNED_BYTE,
- d* L& l! _! V, Z. n - face->glyph->bitmap.buffer2 B n7 p x3 @$ ]9 f4 N' ^
- );
: F$ [( d: j$ X* W [1 w" W - / `* ?8 s# o, f4 n! W8 J
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
j, j# E8 e6 X" b+ w: d3 O - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3 r$ {& R0 C. {4 I8 E% M - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);) P2 g/ E `# F m* y8 Z
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); j: V* M) M8 Z. A. c5 N
- }
# N: Q0 b0 H. S, f - }# c) |! V' U" I- N
4 r/ U Y2 T) i. u, T9 W- // 渲染字符串
+ H9 N9 c' y7 L% I. z - void renderString(const char* text, float x, float y) {- s* Q- i; S- f$ `2 |; T+ i
- glBindTexture(GL_TEXTURE_2D, fontTexture);, ^. ]: {1 X( | w
- ( `$ P# s9 C: ` v
- glEnable(GL_BLEND);
# ?! f$ X9 N- y) R/ a0 b: L! K - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);6 ~' A+ N/ S9 _( q" n0 p
' R P2 q; }, f B3 r1 x$ H- glBegin(GL_QUADS);* K1 R j0 q9 E: }5 V
- for (const char* p = text; *p; p++) {- M0 |# ^! m; w& c+ C
- FT_Load_Char(face, *p, FT_LOAD_RENDER);, A* s: V M8 g: g) F
- 5 Q: ^) _! S# m3 |+ p
- glTexImage2D(
2 I& V1 r/ F- a& p( N - GL_TEXTURE_2D,. w5 I* k0 P! }( C
- 0,
9 a4 g: N- O1 b$ R y$ q - GL_RED,
' {- E4 v/ R. ?8 r! D4 {5 \9 E8 L - face->glyph->bitmap.width,% w7 s& w4 h) h% {% s
- face->glyph->bitmap.rows,' U: W& `! z$ L; S, z; ?4 B
- 0,$ Q: S, Z) p# x" [
- GL_RED,
; _) T; u/ m' s: i* v - GL_UNSIGNED_BYTE,
0 v* p. ~1 o$ y" g$ f5 n0 u* k - face->glyph->bitmap.buffer
+ M( n( a& X# m0 l - );
5 m2 I2 u$ x' Q7 G, J - % j% Z! U: S5 V* k3 D' p4 @) V
- float xpos = x + face->glyph->bitmap_left;
& J* ?9 V. n0 v* z8 o. L - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);3 ^* [( w& b% A, O$ s
+ h8 y0 b- D4 D7 I7 K- float w = face->glyph->bitmap.width;' N+ K. X, t0 W- Q
- float h = face->glyph->bitmap.rows; x p- c, _4 C1 e& x
$ R: W5 S T7 V% v- B" y- glTexCoord2f(0, 0);
# j2 M5 B7 t2 z) i - glVertex2f(xpos, ypos);; _. Q; E4 b' `% C2 G/ N; x$ F
- ' l; q! @1 f3 B' C( f/ C& W
- glTexCoord2f(0, 1);
" Q3 m( P& F9 ^- w: M6 `1 f' K" V+ e; [ - glVertex2f(xpos, ypos + h);
9 V" u4 I' w% p; N) ]
; ?% \; J9 d q, }6 S- glTexCoord2f(1, 1);% S+ N/ q, W$ V, f0 e" k8 k
- glVertex2f(xpos + w, ypos + h);: Q8 @# J7 u ]$ ^# Z
- 0 T8 D/ N3 I! q1 T/ f5 }& L
- glTexCoord2f(1, 0);& q5 z. H5 u- ?9 o+ K4 K
- glVertex2f(xpos + w, ypos);
0 I4 A+ E' D$ M
" j$ K" F9 Q5 D3 e& L8 }- x += (face->glyph->advance.x >> 6); // 字符之间的间距" j a' O- i+ A( ?8 u
- }
0 L4 d0 {% n }& p0 E1 }( L i2 O - glEnd();
3 V e3 I( z* R* }- a5 H. C - + f6 H8 W2 \3 m. [) |* J, k
- glDisable(GL_BLEND);
7 g( b/ N8 P! U( ^+ y* L: j4 \ - }; y# b1 C* Z: `
- 2 ?. Z7 \2 n. d) k) Q j5 J
- int main() { u3 T, p5 t2 ~1 ~ c& w4 C
- if (!glfwInit()) {
& o6 l( v/ Q+ \) W/ t - fprintf(stderr, "Failed to initialize GLFW\n");: E1 h! u8 r2 ~" Z( h( p
- return -1;/ M' M' V% k1 x+ f0 H1 x/ K
- }
8 s" B t3 A( A' [6 g
9 S7 A2 f3 g% j. f) {. o# N% U- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);. e8 B) g% m6 z/ J8 W- W4 ?# H" p
- if (!window) {
0 y" \+ d# @; b+ p9 F, h6 ^ - fprintf(stderr, "Failed to create GLFW window\n");
a5 _) J0 u7 H - glfwTerminate();
0 @% L" l* z* N" [ - return -1;9 s* U) U" e) f( R M8 u
- }
# @+ H+ K" p2 y
0 z7 u0 n: }- n3 {$ n9 K3 c- glfwMakeContextCurrent(window);4 q% |. a% B% p, z
- glewInit();$ U9 }, o5 d1 z y
- 4 j7 [9 g; X) X( x4 ~7 O
- initialize();- k8 R% T/ @" B2 I
0 B) ]* E7 c" F/ \" E0 h1 M, o' K- while (!glfwWindowShouldClose(window)) {' T5 c2 L5 w r; @! R
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
' a+ M( e/ R I7 Y$ `9 J - glClear(GL_COLOR_BUFFER_BIT); m% C4 K3 |+ d, Z% L
- 5 f/ [- W- E# {& j
- glColor3f(1.0f, 1.0f, 1.0f);
/ G( `* I/ ~$ R6 d% t6 O y - renderString("Hello, OpenGL!", 100.0f, 100.0f);% d0 p+ n3 W% u, W) f
; P8 W1 E3 w& f% I+ T- glfwSwapBuffers(window);$ b" n3 x7 t8 G7 Q, E, l3 H- Z1 d
- glfwPollEvents();" X7 U7 S+ s# D' |/ I( @9 k
- }! [2 }$ Y9 _2 R
- ! e. b; [: f& H1 C- X0 ?. W
- FT_Done_Face(face);
$ s# v7 j9 E4 N - FT_Done_FreeType(library);
5 }) H; @* x f1 q: [5 Q/ F - ) n2 O. R9 I8 E) o; q2 S. D& G
- glfwTerminate();
1 f& f( w2 D0 X3 v - 9 c# m& B) t+ Z; d
- return 0;
2 b+ C& ^1 |& ?: T9 H! a8 } - }
+ U% w) _: x( c" g
复制代码
+ E! t2 Q1 X2 \! N% c' J* d" @; Q# Z0 ?" |) o
|