本帖最后由 shane007 于 2023-9-6 15:32 编辑 ; r3 k% q3 @: t2 z; s7 L6 M( T
7 }8 q$ |3 X* c1 J1 ~
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
+ _% u1 F$ u* Y' q, x本代码经过分析以及改写之后,将取代游戏原有的显示函数。
} b; ]& E# |4 G \1 L5 l0 b" y0 H# d3 M* x0 n% P
代码详细说明如下
5 P/ o; r4 q; R2 O9 j4 W% `5 `. a1 g* A5 i" O9 P, B
- 在上述 renderString 函数中,我们有以下关键部分的解释:3 [" H3 S/ X) ~
- - d1 |9 W6 y% Y, e. C. ^ ^
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。# r( X6 K: q- m. V
- ) W) z [; r- R, Y6 N# Z6 ]& d
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
, ]2 V0 o1 ?% m3 h/ c6 I
* B8 P$ Q* e3 n- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。) _& A# g; f- o$ f
- - n' Q x. [2 P. L" \4 y$ ]
- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:. `# e6 Q8 D( [* X$ F2 B2 S- ~
' n: t% `3 i: V; P! i# J- T! |% J- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。' o0 X8 ?* |1 p9 x
S, h0 j/ D9 W6 y6 P- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
5 T& ^3 x2 V9 Z9 N - . f8 e1 R7 X+ v/ B4 G5 U
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。5 e2 ^5 G8 U& q4 D
) O; S# ?" d/ h' P- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
+ I6 O' E& m3 O+ l8 }7 T
) w+ P# ^1 H. Q& J Y6 }- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
$ q* Z8 B. x& N% ]- i2 C* x
, s% q7 T _, `. v/ r- o- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。# m: E2 |7 e- }# C n
复制代码
: C D0 Z8 n( g' V) F6 I1 u; }& f9 G1 p$ J- E X* }, [* _; @
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:/ f) N0 h. {3 i3 a
$ |+ U0 |+ |3 p8 R- 参数:
8 m Q9 O2 L$ s2 B5 { - 7 X4 H' \9 W5 o
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
& U' i: ]! x; p6 o& ^/ j6 A - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
. r+ F6 z; N4 |# r$ c+ k4 d - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
) b0 E) _- t8 j* F - 功能:
* i$ D/ k9 |& T* r
- k: X- g: P- c5 R8 Q1 u- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
3 m6 a+ [: e9 _ - 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
/ M6 @: K8 _# K - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
4 h0 W U# h1 V" T7 u# Z - 使用示例:
' o" P% S2 S0 Q0 Z. Q6 d4 p: L
/ n# t! N) C, N- c
* J+ r7 q8 E9 v5 P, `, f# | - Copy code# m7 [# p5 p. T4 ^' H8 P% P
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);
8 r, Z2 |5 `% ~) c0 o7 R - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。% a) X8 f3 G' j) o, E ^
- " ^8 u, ?9 N9 [" l5 Z9 R
- 错误处理:
" O# j }% a6 R. j3 d
# I: x8 d/ f- h; t$ ^6 U: G' j8 c- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。& U9 \ k- ?3 N4 T2 h0 j! c
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
x. ~9 E- O1 f3 G; K2 P6 J0 C- ^; ]% z! x% f) s' V% {7 X/ C; F6 B+ Y! X
代码7 W8 D5 A6 `% G# S
. s3 ~& n; y% M5 l
4 `% ?0 Z0 @2 L9 f6 W1 W. h- . y5 c1 |4 _6 ?" ?; i
! @2 r( p1 `' T5 } Q- #include <stdio.h>
4 ~; q, d) q, |$ n' D6 P - #include <stdlib.h>
& G+ f' q2 D# l, C9 s( J - #include <GL/glew.h>
1 ?! B( J/ A+ J) G% ~3 |$ ~* L - #include <GLFW/glfw3.h>3 B! E' q; B& s
- #include <ft2build.h>
" _) r6 u0 e$ h - #include FT_FREETYPE_H
; k |& b9 d7 j - 1 z9 Z, J4 G- J: L
- // 定义字形数据的字节数组1 D* X& x8 b. Y. ~+ u* M
- unsigned char fontData[] = {
8 ~) x: D9 X# T8 ~1 w! d - // 字形数据的字节表示
/ S* f! l( f0 n: b5 } - // 例如,这里可以包含字母、数字和符号的字形数据
3 X( c M4 B0 x7 q" z - };
+ G: T8 m5 b' X; d( q: h1 R - 9 f4 u. u5 \8 v
- FT_Library library;
/ H: P. a r. j. f$ Q9 Y4 l, @ - FT_Face face;6 T- t n5 E: ]. m( C
- GLuint fontTexture;
' I$ Z$ c0 i/ H* e+ F* N - , y6 S+ _( u1 M" h, I( U
- // 初始化FreeType库和OpenGL
+ w: }8 {# ~6 t" {& S& m! o5 A - void initialize() {
0 t& l, m5 b- g4 e - if (FT_Init_FreeType(&library)) {
9 [- A% \+ v( z' I5 |* X; F, l( `9 S3 { - fprintf(stderr, "Failed to initialize FreeType\n");0 C; A! G- U6 }$ l B( m( M. S# `
- exit(EXIT_FAILURE);! x# g8 i' w( ]/ l6 I; v n
- }2 _& E4 Y" |$ L6 v5 O0 ]
' M0 m, z) i" t$ L/ F- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
' b1 h$ P, l2 \7 q6 G - fprintf(stderr, "Failed to create a FreeType font face\n");
" Q7 J1 Y* b) p Z% S- B( C - exit(EXIT_FAILURE);" r4 `9 G% ^" ^# w0 P
- }/ q" Y2 s% ]0 [. ]
% z3 K$ O/ K2 c- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
- U/ f3 p# ?; L3 c+ \. ] - fprintf(stderr, "Failed to set font size\n");( }8 U, y y6 q3 D, j% w
- exit(EXIT_FAILURE);/ G% J- g# J# T6 l7 M# n9 g
- }% ~" q+ L0 |' W0 T# ?4 i$ n' x
p- S: b" |& D6 q0 I- glGenTextures(1, &fontTexture);* |* G$ S) w( H( K2 @1 t
- glBindTexture(GL_TEXTURE_2D, fontTexture);
' g- m8 R0 D/ L6 P+ u - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
7 S& H3 S1 x/ j7 I
# H, Q5 _' |$ o' \4 ?. N- // 将字形数据传递给OpenGL纹理
3 s' c2 p" C: K" |, n - for (int i = 0; i < 128; i++) {5 ^$ o- Z* \+ \7 d* e7 m
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {3 W' N" O" @+ I( P+ X, M
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
* `/ O. N8 f5 [. I p4 T - continue;: p- ]9 |+ ?' J3 C' i% G9 O
- }
* x4 h+ V, l3 y1 _- m) a. W' E - - `- c, B: Y: f$ Y& P
- glTexImage2D(
: y( A; V8 p, n$ N* w2 T - GL_TEXTURE_2D,) |& T* {; |9 x4 Z1 s; t% G! E9 {
- 0,
1 R% ?4 J7 D, v9 a D- O4 c( ] Y - GL_RED,
* ~3 p8 m- @& w, y - face->glyph->bitmap.width,5 n) n2 q/ l. |+ n2 X8 ]8 y% ?6 h! `
- face->glyph->bitmap.rows,
7 i8 W0 f* H2 x6 S! d) Q2 B - 0,
. V* ]4 s' A6 p0 O5 K' i9 o - GL_RED,0 o) o$ O( A' @0 g4 P
- GL_UNSIGNED_BYTE,9 z* Q m$ Z* ]6 x5 L2 S. U* S
- face->glyph->bitmap.buffer
7 a1 i7 c, z: I, | Z. M4 W/ ` - );1 P: [6 t1 E6 Q
5 y, M0 M$ C- C2 |7 B- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
! N" G) |4 S" @ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);+ ~: c( k& |) M$ ]* @
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
# T# k( O, R F* _) w$ k: N - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
O7 B- x# R e5 J - }/ \6 F# b/ M1 }/ c2 @ {8 z
- }( V* o. l- ?/ x' L1 {
- $ i6 i7 E; O( ?1 D6 j7 v/ F- M
- // 渲染字符串
$ }: r7 S3 r% O1 V - void renderString(const char* text, float x, float y) {
" f4 u4 h( t; P - glBindTexture(GL_TEXTURE_2D, fontTexture);" U7 T' s& ? F0 `; Y2 X
- # ^6 s1 R- k. ^# X/ J, n1 ]* b: R
- glEnable(GL_BLEND);
' M ~, Y, K3 @- S N - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1 Y" Z. @7 f( a9 e) H& z - : D+ a( C3 F, a( `0 _! V
- glBegin(GL_QUADS);
3 U8 ]% q: K9 g! c - for (const char* p = text; *p; p++) {; } v7 U4 v6 K, F$ K' g/ k. \
- FT_Load_Char(face, *p, FT_LOAD_RENDER);
7 {- o, z. a8 L6 {9 ?. w, Y - $ P& R2 h1 n& l9 d( W7 y
- glTexImage2D(
' b' |4 L8 Q3 ~ H/ Z - GL_TEXTURE_2D,0 V8 ?' Z# y9 ?
- 0,
" z& M" y4 v# q& m8 w( r - GL_RED,0 i; [) e$ U1 a; t$ i$ Y2 j5 H
- face->glyph->bitmap.width,
8 i0 z+ A8 S$ M1 S# ^( {( w8 h - face->glyph->bitmap.rows," }: o) O( u! h9 y
- 0,' {; X4 c+ }$ |/ l
- GL_RED,. k( ~3 i# @" e* _. H
- GL_UNSIGNED_BYTE,
& [6 @1 W1 G% P# \+ g8 `8 ]5 D4 K' H - face->glyph->bitmap.buffer0 l8 v+ c( K e; d3 M7 {' ]
- );
0 \; h, t# x6 H4 W6 V - 8 H+ P9 R3 E- a7 A
- float xpos = x + face->glyph->bitmap_left;0 S' H. P) j5 H A2 y8 ?
- float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);+ P9 }9 i3 K( N5 `4 w6 |) Q
- " G. ?5 m5 x; R' Q- o
- float w = face->glyph->bitmap.width;
! G, _3 @8 T, [( z - float h = face->glyph->bitmap.rows;
6 Q F% g6 i. l1 F - 6 }, a7 ~1 ^& R3 g8 P
- glTexCoord2f(0, 0);* t- @7 X; H" B
- glVertex2f(xpos, ypos);$ W, ]3 x6 t. x# G3 Z4 j
- 7 k0 c2 l5 s# Z' k8 U) l0 a
- glTexCoord2f(0, 1);$ s9 {) g- i: H. {' a6 R$ W! h i
- glVertex2f(xpos, ypos + h);
& s4 @7 g; W: U$ F5 I1 i" y1 A! W3 v - i2 a( b7 S! k h. Y6 `/ q& ?
- glTexCoord2f(1, 1);8 |. K4 A3 {0 @8 Q, q
- glVertex2f(xpos + w, ypos + h);! E# L0 e1 p5 I5 Q2 f4 f, ?: J
- 8 } `7 ~3 _ p. }
- glTexCoord2f(1, 0);
+ r5 F/ x% n% Q: v - glVertex2f(xpos + w, ypos);. r4 N1 ?8 \6 ^9 H" Z/ u
* S$ l0 J- u% v- x += (face->glyph->advance.x >> 6); // 字符之间的间距
0 S( S( ?9 s% N) u4 _( w - }" K# Q0 x, U" C$ z# l% c; C& |- t- @6 i8 Z
- glEnd();/ P4 j) z% {4 N9 N+ S, q
2 ^' F$ [: j6 Q, P9 W# \- glDisable(GL_BLEND);
1 q; h$ V/ m& w5 c7 i. T1 L5 W1 S - }/ B& k/ r, ^0 n
- 7 t4 ?7 A$ L; }5 m* n
- int main() {
; d- _ f; o1 P% W* W! D - if (!glfwInit()) {* A. }5 {: K" n. l: c
- fprintf(stderr, "Failed to initialize GLFW\n");0 ]8 [& k. W# s- a, c8 n3 x
- return -1;( n8 d' Q- b# b, e9 |+ E' K
- }
' H( u# X, X3 t" k$ a
. l0 G: Z1 P4 r0 B- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
& r3 M* _6 {: { - if (!window) {
" m* O q3 S: h) m U - fprintf(stderr, "Failed to create GLFW window\n");" X5 I4 X5 E$ U; r+ ]
- glfwTerminate();5 {8 e- z2 {) F, L
- return -1;3 |; f- F% H/ j
- }! C+ ~* K1 X( Y5 x* b1 f$ z
m7 H& e! J" A" n7 j* Z- glfwMakeContextCurrent(window);
! J" ^% F8 y: O0 {0 H2 \+ _4 p5 k - glewInit();$ B$ E. g; K7 f( V _7 L+ n2 D6 N' B+ n
- - }" q) y7 w3 \0 g5 i
- initialize();* G7 e) |; [6 i; `2 Q; _. M3 i2 ?
, r; O& n" Q( t. C1 `6 ?8 W- while (!glfwWindowShouldClose(window)) {
1 Z9 e+ C. z% ?8 `) C+ r3 h1 L - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);. o. t! ^" Z" }
- glClear(GL_COLOR_BUFFER_BIT);9 t5 y" v V$ Z: V$ \! o2 k' E7 B
- 6 W: ^. y) Z% B z
- glColor3f(1.0f, 1.0f, 1.0f);
" j7 o7 G" i' B: p5 t- W - renderString("Hello, OpenGL!", 100.0f, 100.0f);
+ l& [+ U' `" e& r
: V& `1 U5 D( y3 L0 l! f1 h1 i; ^- glfwSwapBuffers(window);
. V! i5 j+ V7 Y) ~9 b: ?3 l" Z - glfwPollEvents();
8 d3 O0 D$ K6 J8 ~ - }4 @( j9 a- ]( {6 ?/ R
# e6 Q/ u4 Y* E' u& J7 u% Q- FT_Done_Face(face);. G6 J" a# A e* x' t
- FT_Done_FreeType(library);
X( u) N+ z. ?3 p( \
3 r. v+ m) |$ o3 s, z; f: Q- glfwTerminate();) A4 V: E+ U; d0 F% n% F$ R
; \) F* i) U* t* x$ z5 z- return 0;
$ C$ Y" [& \# q, R2 J% E1 \9 x3 T - }7 S2 o0 K! t9 \3 H# c& R: V
复制代码 / D% K) E4 Z4 o+ v- W: _
& R5 y6 S, W$ V, V |