本帖最后由 shane007 于 2023-9-6 15:32 编辑
# u; M+ k2 h/ \7 Q
& h% n0 U- H! w* f9 E0 I以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
$ {1 t3 n* T: [0 ~2 K1 [6 I本代码经过分析以及改写之后,将取代游戏原有的显示函数。
) P% o7 J8 ~$ p, ]% k w5 T- [! }) @' t
代码详细说明如下# m- A+ g% ]8 G
3 O/ u6 t l7 V* S. W
- 在上述 renderString 函数中,我们有以下关键部分的解释:
Q8 B3 {: @; e4 K( }- \ - 8 ^7 ?7 @9 N7 H! ~0 h7 S% x
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。7 w! } k4 O7 L% w ?8 T
' b' M+ f( ~ e- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
/ x. t+ n' f i% D4 a
I; G1 W f! [/ s- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。( M* ?9 ^$ x" `* q9 M* ]' @- X* N& O
0 @2 ^. Q }" o: o$ @+ g B z- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
& l+ b/ ^& P" @. |' X; S
$ v! v2 {8 P! I* j- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。/ W" A! k/ s, e0 }
' ~; r9 n: X! k0 q) O$ w- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
L* ?7 I4 R6 o2 b% [5 Q
1 r& A: V% g+ @( C' m# g& z6 i( K- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
% ]; [! @; Q8 \& ]# v
/ l7 ?- y. N2 d8 o+ P! H- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。0 S7 q3 |: W2 V1 b" S/ s' Y; \
- 2 O) i; F# W1 G$ S: h
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
$ P! R& ~3 L9 F5 f6 a6 n- z5 F - 0 t# g P' B [7 e5 a$ o9 C4 R
- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。; W4 Z' h% S; u* ?0 K3 ~
复制代码
6 n& `' ]7 |/ X
5 B. }" \9 n% S- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:, d2 L2 I9 U1 O \; {
3 k a y! J2 W' m9 \8 }, e3 L6 u. ]- 参数:/ x2 ?9 z! o, s Q
8 s: ?& R9 X, K# f/ U- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。$ Y, V" [9 k4 c+ O5 x( L
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。4 b, P" L( E. t' f7 T( x9 T
- load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
9 a/ v( j! G" Y8 ] - 功能:- X; ^' \0 e# U1 W$ {
% r9 ~, M- N) U6 b- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。0 E- `, M# B2 T% S& L/ o9 R
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。1 k6 O/ k) Z6 c0 Y" C
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。# Y3 Q; A" z1 b6 z. ~9 Q; f9 Q
- 使用示例:
a4 l% k- I- T" e! i, F! g - + e* D" z3 X( t2 l: t6 p
- c/ e) Q' n% s* f
- Copy code
7 U0 g+ B$ p+ W0 P0 l' Y0 v% [ - FT_Load_Char(face, 'A', FT_LOAD_RENDER);
* ]: S( z, ^3 z+ ^* [5 J/ h - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
. r4 L7 F5 B4 Y. x. R2 z- s
. q! ?! X) C0 @( }0 w- 错误处理:
4 H6 s' L# G/ v& W( |( z4 v, R2 p
+ M2 A2 e, K6 C/ g& x& z- o3 q- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。0 a% G$ ]4 J# t
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 + a5 X& b& C2 F* E
6 o: p: D9 b# ^5 ^; J: ]
代码! V1 s: ^4 M0 c6 x) R: L
) @! A7 n9 N8 D9 V' g. A6 l- 9 @# D" n# @; F7 b" N
- , g/ T& v- B; L( J t, C1 N
- ' O I3 s' G* K
- #include <stdio.h>. R9 X3 p1 I, ^
- #include <stdlib.h>
9 n2 X0 c1 f+ y) n& r - #include <GL/glew.h>
& ?% h2 |7 ]9 w - #include <GLFW/glfw3.h>; I5 p {3 M6 |) D1 N. m' g
- #include <ft2build.h>* y" j) H" M7 b. u* h) P1 Q! K
- #include FT_FREETYPE_H
9 H9 s+ A0 |2 f' q/ O - 4 }. \! ?2 d: S( s
- // 定义字形数据的字节数组1 ^- s' g1 [6 {; ~2 F3 Q
- unsigned char fontData[] = {2 z5 A6 @1 \" D* U7 H# I
- // 字形数据的字节表示
8 v8 q* b J) \ - // 例如,这里可以包含字母、数字和符号的字形数据
, r" Y! h: M# K% q" X - };
) ?. Y }0 T" q+ A% ]) S
8 b9 ?' ~$ p" D8 c; o0 Y# X- FT_Library library;
U* M. k X9 u7 M0 p5 O$ f# Z - FT_Face face;1 f' t% W( i1 c! y, U; t/ b
- GLuint fontTexture;/ n1 {( N* w: h& H1 k; K, a
- . f& L5 h; y' r; D) q
- // 初始化FreeType库和OpenGL
8 j. ]3 t& ?0 H& g - void initialize() {6 [4 [& }& M0 v) f0 |! j
- if (FT_Init_FreeType(&library)) {
. h$ e2 Z$ g/ v- e; n; b - fprintf(stderr, "Failed to initialize FreeType\n");& P. G8 w: f$ a' h+ Q
- exit(EXIT_FAILURE);
9 B) g( @3 D8 F% }& F6 K) s - }$ H. o# f- P0 r/ a7 V* U2 S4 B# b
- 5 e5 y7 n: F0 V
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {) _2 a) x# V. a2 m; C
- fprintf(stderr, "Failed to create a FreeType font face\n");
+ F! h, `4 \- z; h1 j- o - exit(EXIT_FAILURE);/ K4 Y/ D3 p# `2 E, x5 n* w. A& _/ s
- }4 R8 z8 Z: O( }/ i5 U) w& R6 A
- . }3 O$ w5 _; w6 X7 i$ B$ h: E. Y, w0 g
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
2 {, k* e8 V' K) q& ^. n/ H( G - fprintf(stderr, "Failed to set font size\n");
- _7 d2 R) N0 A j) Z7 ~ - exit(EXIT_FAILURE);
0 n3 C+ ~2 t% S1 `) X5 B3 {- a - }( S2 f1 |3 G/ s
. q1 D; G" C X0 Y3 N Z7 U2 S- glGenTextures(1, &fontTexture);' I& p; S5 @( v" ` R3 t4 m7 J# a
- glBindTexture(GL_TEXTURE_2D, fontTexture);
) u1 o9 Z e# G9 g n, O, ] - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);8 i( S: ? y- ]% v) N+ b
3 q4 {) m! M3 @+ u. b$ K- // 将字形数据传递给OpenGL纹理
/ @. D0 ~. |8 H% z$ p - for (int i = 0; i < 128; i++) { N) N! G7 N+ U' ~) L P3 z
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
; o' o" v+ q2 s - fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
2 L1 K4 @9 F' e7 Q( z8 ^ - continue;
& y6 d! l* A. \4 l - }& F/ `- b/ C F) [. H$ t& T# D5 I$ D
- ; \4 Y/ j- T W, H4 x
- glTexImage2D(
/ h' [2 ]5 [- Q& R( t8 ?9 g - GL_TEXTURE_2D,+ l* q. V. u4 U; r
- 0,2 {8 R n7 }! _8 l' _, g' c
- GL_RED,+ Q8 Q& V" e U" ^
- face->glyph->bitmap.width,
) _- |1 }+ \) d/ l. S0 |6 O - face->glyph->bitmap.rows,: o0 n# U1 o: `& Q
- 0,
2 D# C3 t% m* { - GL_RED,
9 o0 j+ y/ _' U1 u8 ], t1 f - GL_UNSIGNED_BYTE," Y7 d* S* \0 @ n( V! B4 Q6 e
- face->glyph->bitmap.buffer0 I! d4 c& v E k4 k6 o
- );
* X4 }' n0 x% ^8 G - 5 p! [1 p: B( w( B8 ?
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
# t. x& I1 a$ n' [0 P - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
Z5 H/ o3 i V5 b' j! | - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);! y3 `& V% t3 G; |
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
: L4 i* z0 ~" p4 @ j2 p - }
4 h* |) d* {2 o7 h- a - }: F, G! k( {; [5 a; X& @+ ?8 v
- 3 _8 n; L) F, F0 i* G2 F
- // 渲染字符串
% N/ K) q/ ~* p2 r5 T3 U z - void renderString(const char* text, float x, float y) {4 J8 J1 d Z/ f2 t* l
- glBindTexture(GL_TEXTURE_2D, fontTexture);' _* a- }! ~ C r4 W1 {
- 4 t- k" ~( ^9 Y
- glEnable(GL_BLEND);
" C- a. c! t* ?! p7 F1 |) m* i e - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);; _# ^+ C; Y. V; z' o' I+ h
/ {( H% Q, a2 X+ P7 [; @3 f1 D- glBegin(GL_QUADS);
" z7 T. z, o6 @8 z: e/ l; ?0 R! w - for (const char* p = text; *p; p++) {* P0 j; j# X1 D5 c
- FT_Load_Char(face, *p, FT_LOAD_RENDER);
3 _. ^6 ]5 d1 P" I" Q" b5 |
Y* V; D, `2 \" q( i. D9 V' F- glTexImage2D(
5 t/ ^. a, t% X" t- i! K2 D2 U; m - GL_TEXTURE_2D," F" Y1 W! ?0 \
- 0,. {; L& i& F7 ~3 {5 m- L W
- GL_RED,
: c/ H! M# X N- X" z - face->glyph->bitmap.width,
2 F3 R' N) r: D - face->glyph->bitmap.rows,
, O& r* u/ V! _ - 0,
2 {3 O+ \9 u, K0 z - GL_RED,. F9 d' C+ S1 \% |) C* i
- GL_UNSIGNED_BYTE,+ W( B4 {/ N8 U, W5 N
- face->glyph->bitmap.buffer S$ d2 R! K8 D
- );5 A5 O( Q5 Q3 [% m* N4 y. V
/ o# |( d2 f. {, y- float xpos = x + face->glyph->bitmap_left;
/ v4 w, V" L& ~. r9 |' u - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);+ p, C2 E- O# W# n5 `& q9 W: o
- . h3 ^( C" b a" o2 R% V, @
- float w = face->glyph->bitmap.width;
$ Z1 P- |1 W) \9 [1 D - float h = face->glyph->bitmap.rows;) _+ d+ z6 b" Y. R. ~
& p5 K/ Y+ g( l! O9 D- glTexCoord2f(0, 0);2 b( F5 _3 H. M, a
- glVertex2f(xpos, ypos);
1 q1 o8 U% v1 F& b# Z - 0 F+ B/ e9 S5 Y h- i& t
- glTexCoord2f(0, 1);
8 B2 E! z: w$ ]% ^0 q: N' f2 q - glVertex2f(xpos, ypos + h);
- g# Q1 v; P) k$ s! C
! L& M1 e# m; f& V% l7 v: S- glTexCoord2f(1, 1);
* g# J7 v! m; ~ q7 G/ A - glVertex2f(xpos + w, ypos + h);0 e$ j5 X0 e) i: J
- I, C' v& M( D2 M5 H
- glTexCoord2f(1, 0);
3 \ e( {5 Q6 g% }, j - glVertex2f(xpos + w, ypos);0 [1 a! N. ~+ N" `3 k# W o% j
2 [$ a% ^2 ]/ c) }- x += (face->glyph->advance.x >> 6); // 字符之间的间距6 D) C5 ~8 u N
- }" {/ t; s) K7 V1 V; p3 v' P' u* r
- glEnd();
# a$ ^6 Q7 D4 T5 S7 Y" h8 p3 Y
5 h9 V0 B# s+ Y! q! |* J- glDisable(GL_BLEND);
8 Q( `4 @" c/ j; S& f - }
4 [' n8 B7 r2 s- ^
( s0 `) }( s$ I- int main() {
8 d" F% y) N3 |( Y7 _- e% X - if (!glfwInit()) {2 ?+ j/ K9 e/ ]: U. N' M$ C4 h/ k! s, n
- fprintf(stderr, "Failed to initialize GLFW\n");) m8 g3 x8 k q
- return -1;5 b k, w+ k" i
- }; [3 L! B9 n# g; p
- 5 B+ j" c2 T1 W9 H, Q u
- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
- [1 ~/ m7 @# r0 J - if (!window) {" R9 T% C( d2 D2 }" @: E6 g
- fprintf(stderr, "Failed to create GLFW window\n");' r5 |! ~- l4 ]$ Y
- glfwTerminate();
! A0 U$ Q& ?4 L* o, S2 @% p - return -1;
, K4 u* `% s, D h5 U - }2 [' J2 u% a: _( \ q* S
( O9 ^" i3 Q) J. Y2 V- glfwMakeContextCurrent(window);
0 C2 x1 B- y; l6 S+ U - glewInit();+ m" A7 i# d) a2 ^+ V. b# D& F9 ?
- 0 t/ c2 ]* z8 ?: Y
- initialize();
. z9 h/ d+ e: Y - 3 V1 L' y7 M8 C. h" D) s
- while (!glfwWindowShouldClose(window)) {
6 |. A9 r% r" h, C9 ] - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
* u% W( t4 }4 s: M8 B5 z - glClear(GL_COLOR_BUFFER_BIT);1 B( O& O2 E& h- o2 _
$ F1 H/ j! M: q/ @0 |" g3 L- glColor3f(1.0f, 1.0f, 1.0f);( z8 x& \. ?' a% ^* n9 e
- renderString("Hello, OpenGL!", 100.0f, 100.0f);
0 F2 `( m# {. M1 Z
g, N/ q7 {* [2 x/ T) t' u- glfwSwapBuffers(window);
7 R" r% X, X4 ]; W, Q: H - glfwPollEvents();' Q D; h- V% z
- }0 g& x9 m, C, c+ `
- 5 N \. b1 Y+ ~: q3 x
- FT_Done_Face(face);
! s, M( K. A4 L4 y- C5 A - FT_Done_FreeType(library);
* o. `4 o! Y& E3 N5 X- |) C! X
( W4 P2 w6 \$ O0 p! ^/ i. h- glfwTerminate();+ X; M( n! g( R! z9 r
& @! D1 U3 L- s0 t7 q y- return 0;% `: s( ~. z) |
- }
7 U6 g) Q$ g2 b& s1 R4 w5 X8 d6 R
复制代码
0 }/ o( g1 Q" [" s
7 _8 z+ L! p' [: Q |