本帖最后由 shane007 于 2023-9-6 15:32 编辑 # f* [3 b5 g' K* E
& p) j' L! M. Z# h5 T以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。& l( R2 V6 @' x9 Z; Q1 }4 v
本代码经过分析以及改写之后,将取代游戏原有的显示函数。
- m" ?; o m7 f5 W; d) x
" x1 e3 R; R* c* s* k8 }' j& r, {5 F代码详细说明如下+ v. [4 t. ]* e! s# q
' h2 L G9 p. j+ \
- 在上述 renderString 函数中,我们有以下关键部分的解释:: \9 j3 ~7 ?) o) T
2 F O' m! y1 ]0 T3 G- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
; |( |! M7 L$ k - : x, m4 u0 e8 L( B7 _1 G
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
$ @" }4 j4 Z% U8 h: m - 2 l; N" [& T% R: ?
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
1 m- S7 j- {2 \! D5 Z" @* Z - 7 ?) k T" J' t( k
- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
! j7 q4 K( r1 X% A: ?3 y7 i2 M @ - $ V$ F' p. p: T, C2 d* L# F2 G" [ k/ q
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。1 g0 ]- K4 ^0 z1 T4 J
4 y- U# z7 Y0 U- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
/ p5 F# r7 L0 r: _5 t, G - ~4 B8 L. T% i
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。9 U* M* Q& c0 D, Q g# t
- 6 m" Y/ V" q4 H( E$ `- a9 Z
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。$ T6 O+ B$ _) K
- , I' P* v* B2 \2 z4 a& Y2 Y
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。3 y/ w W3 J( \% K$ D% w
- / e: W4 x: `; S$ j
- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
/ g8 t. z3 O" ~. e
复制代码 " Y; m) W' A4 C4 p) @9 \+ S- A
# G6 _- e1 g- m. q# B( i- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:( |; N/ |: C) |( H; d2 }5 S
1 N! ]6 R4 e$ S1 B. X8 L& @: U- 参数:( j* n& t# R2 w# U& o; K5 M" t+ V
- ; m& Z$ p% G4 ]2 `
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
% n8 x2 N* d+ K9 x - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。' p* ~- K+ m- C" V0 x# `8 T0 U
- load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
9 I# J; O6 v1 S' o. N - 功能:
8 G1 m& _6 G+ s/ ^. d - 1 ]& u! K( L8 x4 n, V/ b
- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。, f2 G; ^2 f" t' W5 c+ y
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
' K7 S7 p5 z0 S1 V: d! D, y; v" b - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
" ~5 j I3 S& U, C+ f3 } - 使用示例:$ b$ }; u8 W9 }' d. Y& T) X2 W
- 3 D9 y: Q3 q. O9 k2 L) v0 b
- c/ a7 |3 k: H1 ^: s! J! S
- Copy code
& h6 q. N. |" x - FT_Load_Char(face, 'A', FT_LOAD_RENDER);
* u& b' |) i+ j0 n - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
8 q' J$ C$ C, V" s4 K5 o* E7 R+ B - ) H2 h; y, W/ |4 P* G: a- @
- 错误处理:
/ ?5 j* S8 J/ Z0 G! f* S& O - / j, ^& N% i" N S2 m
- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。/ q2 j# m( T1 o+ v; k9 ~
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 * }4 r1 Z, Q+ H2 T8 f' X( c' f
6 Z. [8 [) F6 D8 r代码
4 U! Y- k1 z9 S
( l6 H0 S) F N0 ?$ w
& R' Z% \ Y4 _3 a N& Z9 i6 F& b. }9 B- ; w) ~$ _# o: V- `0 N8 i
, l- l ~! H# p: V' p# H; s4 L- #include <stdio.h>
8 ^. U' l5 C$ r. G8 O - #include <stdlib.h>7 M4 P9 U+ L( j& A# M
- #include <GL/glew.h>) `! C6 Q/ z. P" a/ Z
- #include <GLFW/glfw3.h>2 o2 h4 {+ B$ x6 U1 g: ~
- #include <ft2build.h>/ a# V: W/ B( i# H
- #include FT_FREETYPE_H7 b9 f. j+ {& }9 m9 F, y
- ; D2 a* Q: _2 o) N; J# i7 N
- // 定义字形数据的字节数组' ?( Q8 I; D6 z. Q5 C
- unsigned char fontData[] = {
. z# q6 V1 i. ]3 D* k8 L8 A; k - // 字形数据的字节表示
' g& p$ P; B/ g. m8 a - // 例如,这里可以包含字母、数字和符号的字形数据
1 Z6 N; q* N0 g+ b, Y7 Z - };
/ z: A% T$ {- G5 b- T% s0 K+ V! q" G - ' N$ H: o( }! u/ P* P9 |2 v
- FT_Library library;
k- l& D7 W4 m - FT_Face face;
2 ~9 r2 Y0 [, k& x/ k$ W! n* H - GLuint fontTexture;7 a9 a& C- n' c! b0 P7 Y
- 4 d; g; N0 i6 J% U
- // 初始化FreeType库和OpenGL
7 T6 G% N9 U3 G3 C9 g+ i" @* ]9 L) }5 a - void initialize() {
. M S- h8 r" c2 g, K( _ - if (FT_Init_FreeType(&library)) { {/ _3 y7 h6 V
- fprintf(stderr, "Failed to initialize FreeType\n");
" F U3 G0 \, z - exit(EXIT_FAILURE);
K( s- }# k+ ]' J5 k - }
. g4 ]( W! {* x, w9 ^ l - 7 A; h3 H) g1 z# y$ ]
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {# y( L3 X3 w# d
- fprintf(stderr, "Failed to create a FreeType font face\n");7 y! B2 ?: I {, ? j8 ~% [
- exit(EXIT_FAILURE);
! a& r, W* U/ u! ^ - }
. d' @% N! \1 V% m0 q) v" j
C: e, ]# U9 Z! a- g. V2 i- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
; f( `4 }# T7 o, f - fprintf(stderr, "Failed to set font size\n");/ h: a. `! }# i; R( l7 Y
- exit(EXIT_FAILURE);
- c$ E; W$ M3 Y7 I2 r" H8 R* j - }
' g; I* k- @" z - 4 m h" G3 P' s
- glGenTextures(1, &fontTexture);
4 m* l) J, Q) ~7 s' j4 b - glBindTexture(GL_TEXTURE_2D, fontTexture);
! o# R8 {& z5 f2 L3 E" X - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
$ K7 I8 F' J! c% L* P
" i2 l1 m) \) u2 a- D; \- // 将字形数据传递给OpenGL纹理5 f2 S. w# `9 ]6 s: ?
- for (int i = 0; i < 128; i++) {
3 _& V3 k. A3 I( ]! y - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
) ]! j! J. T" i! o6 g; k7 Z% e - fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
/ |* s( f5 m% V; t5 o* l - continue;
; d$ k) ^6 k# W/ \ M - }
& s7 M2 d+ A7 k2 E9 O
4 g: R6 ]# Q7 c& H: m- G3 A( X- glTexImage2D(* N, ?! j5 w- _8 I( A" S
- GL_TEXTURE_2D,
( G. }3 `1 h& h( k2 K" I+ f - 0,
% [1 n% R/ ~8 l k1 ~ - GL_RED,* }, o. T& W' J; G: J
- face->glyph->bitmap.width,. u$ ?7 E2 k& t7 I
- face->glyph->bitmap.rows,- {/ d4 e- ?# u3 l
- 0,6 d# T/ I. B6 U- o. A1 K/ b( I7 D
- GL_RED,
/ d1 j) j! Z9 @( E5 A. L - GL_UNSIGNED_BYTE,
6 F3 x" B. k5 I2 D1 M4 | - face->glyph->bitmap.buffer
) p5 [0 o( }# a j1 O( s) k - );' G; a- w$ I: h2 m9 O( L0 E! {
- $ E) Q z% k+ }: ~7 z, E2 b r
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
9 g1 }1 s" l7 a$ n - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);7 m. E; G; W3 j+ o3 f0 m
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);/ @& t" A0 u% H. ], A7 T/ ^6 }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);, X9 x; B: [0 u
- }0 _5 d9 b( N) C# j7 d: p
- }/ s5 J- y8 C; ]; Z
0 |3 ?5 ^1 C$ K& v6 s/ c+ z; E9 ]* A- // 渲染字符串/ K' R& d6 i6 T5 [+ d* \6 r) L# a* z
- void renderString(const char* text, float x, float y) {5 R; r2 `- c3 w; j
- glBindTexture(GL_TEXTURE_2D, fontTexture);8 T2 t( K! v/ g$ a" \* _4 F
- 4 Y- H# v( a) j5 N5 u
- glEnable(GL_BLEND);% P/ X: C$ i% l5 x3 |( C
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);9 H2 R6 O( K( Z! X( h) r
9 i3 Z$ X3 S2 |# {2 x' I6 v: s- glBegin(GL_QUADS);
. O( O x1 {8 a8 j4 T: H$ l - for (const char* p = text; *p; p++) {/ R( Z8 f7 _- e% W# D' V* P
- FT_Load_Char(face, *p, FT_LOAD_RENDER);2 J% y/ @0 N5 _. m) ~
- ( O" X9 p: D3 A: f; s4 `& N
- glTexImage2D(
! h6 ]4 I" F7 C - GL_TEXTURE_2D,5 F5 a2 i' `9 K5 H) X( K( X3 Y
- 0,/ ^1 k: ~2 E' [/ k1 N; v# O* X
- GL_RED,) f" ]% o' S8 _& @' j6 j2 N
- face->glyph->bitmap.width,
+ z& M3 {+ U$ Q- {3 C - face->glyph->bitmap.rows,
0 H* q) D3 B% n/ S8 j9 u" o0 ^/ [ - 0,
3 T" `2 b* b( k" o& V. [5 ^ x" l- ? - GL_RED,
4 [7 v( P: \9 Z( C9 D9 a& y) V - GL_UNSIGNED_BYTE,
4 `0 s, l2 s% Z" _' e - face->glyph->bitmap.buffer, F* ]6 O4 R1 B" y! h* {
- );
/ e% E* g3 b' K( f
6 g& V4 S9 R# g8 Y8 f$ l) Q- float xpos = x + face->glyph->bitmap_left;
, H; X% d' l: x' ] - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
9 W" w2 [% l2 O
& G6 H ^) N" N- float w = face->glyph->bitmap.width;9 N% k7 a& e* D- a
- float h = face->glyph->bitmap.rows;# W3 t' t6 o" h2 `0 ^+ h
- # ^& S) @: E' G$ E0 J2 J! {' v5 h& Q
- glTexCoord2f(0, 0);
8 }# q# r! X8 E a. ^7 d6 k - glVertex2f(xpos, ypos);
' l) j( e1 _ L2 J3 m6 W4 ~' n
, E! J5 e2 A* [+ m( f- glTexCoord2f(0, 1);
$ \2 v1 h& l. l, u - glVertex2f(xpos, ypos + h);
: D& k* |) O3 k5 U) W# M - 9 Q- u- s+ P0 q8 R% s% H3 P) w5 `
- glTexCoord2f(1, 1);+ G# M7 D& I# \$ g, k1 l4 R; @# w
- glVertex2f(xpos + w, ypos + h);3 t3 ]( V$ i" _0 x6 K; S) f4 G
# j3 }6 b. Z- ^- glTexCoord2f(1, 0);
! W9 ]4 K9 R. o; C1 N - glVertex2f(xpos + w, ypos);
* t F! k* t6 ^; ?1 O$ F1 O
0 d& A+ o1 J$ r7 F x) V* p& o- x += (face->glyph->advance.x >> 6); // 字符之间的间距
0 X2 @& U* _4 A& u4 [ - }: M% {- O( j$ B" i/ ]9 z! _7 `
- glEnd();3 \/ i, L) Y1 L8 T1 P
- 1 Y$ G. i4 s. z* U8 U* I4 y
- glDisable(GL_BLEND);5 g y( P" v/ k' M3 C' {7 p3 T7 G
- }6 g4 c% a6 N$ ^# r o
5 Z8 O. @$ N: W2 r, ~0 I% B- int main() {% ^/ E4 S# W; e8 m
- if (!glfwInit()) {3 K' \( z$ w; _2 ~' t5 t) @$ |6 J8 |
- fprintf(stderr, "Failed to initialize GLFW\n");7 [. x5 L) i1 @& f G% K
- return -1;
! c( E: o! X6 @8 h: {& S k - }
% T' L% R* }# j @# F; h% v3 X8 F
; Y5 \5 ^8 Y3 ^; `& {# E- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);/ g! }1 z6 W5 c: ^* p
- if (!window) {3 P3 R8 N1 B% q' _
- fprintf(stderr, "Failed to create GLFW window\n");3 y: x) z; u: f/ ~8 Q; u
- glfwTerminate();1 }6 A2 `" }. B5 X" Z
- return -1;
l8 {% e9 \3 {2 ?% ~$ t9 D - }, |1 }' U+ O. y9 {( D1 O% `
W/ N% y5 i2 w( |( ^9 {- glfwMakeContextCurrent(window);; N1 H. n0 b9 v- k; h
- glewInit(); S6 b2 ?& r! x) t$ h P% R
- ' E; u) W- V/ L6 T( }2 \
- initialize();
# b6 ]# O: F3 e/ S - 9 |2 r4 J" @2 q8 _; Z
- while (!glfwWindowShouldClose(window)) {
8 @8 l t$ @5 @/ | - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
9 g# @5 s% t+ l - glClear(GL_COLOR_BUFFER_BIT);9 t y$ c8 ?$ H3 b
/ M3 y% q, {+ B: ]- glColor3f(1.0f, 1.0f, 1.0f);
1 X9 }$ p% y* H T/ o3 B - renderString("Hello, OpenGL!", 100.0f, 100.0f);
! ?2 ?* H9 W& z8 D
[+ x" N3 G& c6 M. ?" c. \- glfwSwapBuffers(window);$ c% W L; J" p) x& t Y3 Q
- glfwPollEvents();
( o; _& m- {/ c - }' r# H1 ^( i% @, U
- 7 S1 ~/ M& U/ |) ?
- FT_Done_Face(face);
0 j+ H6 T0 o1 e5 O5 r- R/ T - FT_Done_FreeType(library);: Z6 A0 t: D9 i/ p) X5 N
( T1 ~- d C# B4 q$ ]- glfwTerminate();
3 a; [; P* W) z - 4 g1 e `0 ]6 ^+ H% k
- return 0;
' Y0 | v h# x% o - }' i/ s/ H. W! q" E& `& R0 }
复制代码
k+ e! K% c* k
3 O8 }3 ]3 p# U. G4 N( d3 F1 Z4 L |