本帖最后由 shane007 于 2023-9-6 15:32 编辑 : X$ m1 o% F8 Q. b- Q1 O7 O
" r6 z% r7 Q( ]
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
: u J! O: D' H0 \! y3 ^- R本代码经过分析以及改写之后,将取代游戏原有的显示函数。
8 h% o8 ~, U* I' Q. q2 N" r% L- G# B$ u( r' @, N* X5 a
代码详细说明如下
! D5 e) \8 K/ C! @1 {
! j9 c% l; w. S: T5 d- 在上述 renderString 函数中,我们有以下关键部分的解释:
( F' E# L X" o) y6 _) a: `
/ M# D9 h1 E9 \7 x- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
4 L" r' T) x$ I- H - t* D% M0 `% r
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。, n. v8 M0 v" T2 h! Q, D( T
% A" G# h& P1 t% h1 G- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。2 y5 t& V# m7 A* ]
- 2 `+ s" ^8 t( t4 O
- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:$ A7 B& i: I0 T o9 q
- 3 C0 a5 ?- h; W3 p% {
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。7 y5 a) F% l. O; g4 k$ W! X, e" l
- # s! Y4 l+ s9 m) F
- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
8 U: h# V3 e$ M0 t! O8 ~9 w5 e8 b5 ?1 s
& U! i; B; ^7 ]! H" E- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
* V. e+ s7 D* o; f+ S! f4 [* n
, N, J0 z. [& s$ O' g& ~: Z- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
0 Y* {6 ^( @/ @7 c7 N0 c+ I3 K8 ~ K
: W7 G: d$ c+ W- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
; d! ~8 o. E% G3 L3 C
8 f! x1 d9 S* b5 r& u- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。* p3 J6 Z' n* N
复制代码 5 }" k& f8 Z; W. O1 X
( g: E& E# F. _, h, k- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:7 D& ], s, j+ @. i- k2 I
- - W7 ~) V4 p5 K! T0 K3 p
- 参数:: ~) f/ i8 Q- V4 k! P% J
' r% I8 h; d$ V- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。# I8 _6 ?; Q" U0 N. K- y, h) N2 q
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。/ Q4 p, U3 t3 a) E3 X4 I" A" _
- load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。. U' h9 V9 h8 D( S0 \# C6 K
- 功能:
+ W2 \# e; E1 \; C; [
- E+ c2 k. `) n3 @- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。& a& f9 f# }8 y; s2 P, A; B
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。* v" {) u( l7 z
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
. j3 ~4 L$ s, E* Y6 @* z6 I- j5 O5 p% Q - 使用示例:
1 O5 ^( ?8 W5 c - : t* O: M/ T8 C) ?6 d8 p+ v3 I
- c; f* u2 m) B( V) g; J' N' `5 A0 E
- Copy code
3 ~% g9 @9 u! `2 o3 I - FT_Load_Char(face, 'A', FT_LOAD_RENDER);
9 H' p; Y0 E7 m- M - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
- l9 @; m5 N& t& h/ c6 m5 ]4 ^
, ] s9 B" k* g% Y; Y# Z- 错误处理:: w3 _5 I, }* `2 ?" F8 F
. y8 }$ n: \% Y3 k. t2 L# W) o% ?- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
# i2 `6 A% l/ R# S - 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 / d/ F/ |1 a. _/ T' E+ z& K
! G6 I- Q& w R _5 R" y' L代码
2 p* J8 ]3 B) E3 K* B* d
* X E/ M3 C$ `- & w' o# l! D, F/ M
. y& C$ S# y2 ]0 @3 ]6 ]' L ^
2 k1 V; |+ F3 T h" O# B6 V5 B- #include <stdio.h>* M- {% z% u' C: i( k# z9 [
- #include <stdlib.h>+ j9 x3 G4 o/ m% P1 n7 g: i. U. s: _
- #include <GL/glew.h>3 u0 ^7 F3 p" O1 |& K; Q
- #include <GLFW/glfw3.h>
& c$ M* N8 l+ V1 p9 e6 m - #include <ft2build.h>7 S: b$ c1 \9 C+ l* Y5 D( R! s% K
- #include FT_FREETYPE_H
- H& V, F* |9 j
# [3 G% ?5 O X" ~: y- // 定义字形数据的字节数组, H" G0 D' d& t6 B% ^# T
- unsigned char fontData[] = {0 p% C; |" p* B) Z' z; u4 l
- // 字形数据的字节表示
9 k6 S9 M" i! K; L+ B - // 例如,这里可以包含字母、数字和符号的字形数据
# o8 `1 F$ u$ C% Q" G% e2 p1 F - };- o- P! M- ?7 C/ e% `/ j; r
- - b/ j, I, q# K. b1 D
- FT_Library library;
& Z" C, x, V/ a$ F3 D3 \0 t P% M - FT_Face face;9 D8 X8 E1 W4 i' Z( }
- GLuint fontTexture;
0 `3 g- e4 D0 D, d - - B4 h) \; X: o
- // 初始化FreeType库和OpenGL8 C" _6 F4 T: W
- void initialize() {
! X' R+ r* F3 G7 q ~6 m" Y - if (FT_Init_FreeType(&library)) {
6 E5 r0 _. Z7 ?, P- H) X( _ - fprintf(stderr, "Failed to initialize FreeType\n");
' l8 J8 y( N: _$ c. [! h4 S - exit(EXIT_FAILURE);
0 V6 L9 a+ L( a: G& G - }- p: O" v4 u8 [0 W) |
1 S6 `/ h- v& j( J- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {& H. Q: h1 y" v: k3 H/ A! g* v
- fprintf(stderr, "Failed to create a FreeType font face\n");3 z; w; S) a& T0 G5 U: u! s
- exit(EXIT_FAILURE);
6 s' _+ \6 B4 M0 h - }
( ]& v) ^4 M+ {. _. `! R: m: x - 6 [2 [7 ~3 d1 N7 A% c: g
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小* h& m: [" p1 x- ]( L ~; L
- fprintf(stderr, "Failed to set font size\n");" D0 Y) `0 x3 v* I! Z6 K ^
- exit(EXIT_FAILURE);, a& Q" |( b/ ]
- }
2 g7 C& I, X. W( G2 c* O k& M - $ t& O& |) I& p) f
- glGenTextures(1, &fontTexture);) M m, i- D4 r' [
- glBindTexture(GL_TEXTURE_2D, fontTexture);7 C; U* B q, b2 W/ f7 z
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);7 x5 k7 o) d4 u% H" F0 X& Y
/ j/ a4 \9 e+ x+ U1 f0 F- // 将字形数据传递给OpenGL纹理
% K! ?) X. ]9 X5 L% { - for (int i = 0; i < 128; i++) { O% n3 t) F! N
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {/ M o+ O( z/ G' j
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);6 z1 z7 z3 |# V- U: W/ s& @1 F
- continue;
3 v# K+ B; }2 a5 B - }# x. c; Z# W& ?8 f7 N9 `
0 U( x% R. e8 b# B U- glTexImage2D(/ \ x1 W0 p7 q1 Q) h' O$ l$ M: P
- GL_TEXTURE_2D,
6 k5 `) d9 y+ @. I7 X9 t - 0,& p( T; Z; i Z) y$ J, N
- GL_RED,3 v H) {% _3 c
- face->glyph->bitmap.width,
9 P# B7 u1 K d( @ - face->glyph->bitmap.rows,
/ N- N0 x7 B" M6 l - 0,- H* x# ?* o3 D1 a# n# W5 p
- GL_RED,
+ c) M5 `- [, |! v - GL_UNSIGNED_BYTE,
7 D* C% a$ k0 c8 ^% u# l5 @, [ N1 y - face->glyph->bitmap.buffer3 d. [9 w* r% I
- );
9 B: W5 U0 Y9 ]: V* B7 l - " z: t2 }0 k5 I1 N* Z+ [
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);. v( R3 E; \4 ?0 m( Z
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);' v7 Y5 y& p7 ` t
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
, |* x1 g3 ?# d; h" R6 I8 K. E - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);+ w0 s$ _9 O. o5 M4 p
- }
* ?+ v; O# A/ O" `; l - }$ t9 ^+ ~" @7 G, Y/ Y
- ) `, H: k8 w- ]
- // 渲染字符串
7 y: O/ |% b1 P" Z - void renderString(const char* text, float x, float y) {
1 }* j0 H0 Y }3 O& Z- r0 V$ ~ - glBindTexture(GL_TEXTURE_2D, fontTexture);" t8 [8 _. G# M8 D/ k9 l
: b! {9 ^" h* f0 C/ x( N& |8 M- glEnable(GL_BLEND);8 \! J& Z& o) F6 S3 }; z) k5 L
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);6 E* d" E5 w8 K7 x
- , w6 E# P9 @! O# e- U$ P* L% ?) F) k
- glBegin(GL_QUADS);6 O1 ^# H8 D2 }! l8 t( N) |1 W
- for (const char* p = text; *p; p++) {% U$ d5 i( u, l0 v
- FT_Load_Char(face, *p, FT_LOAD_RENDER);- |* x) D1 \* J* T G
- & r, s7 U: |* H1 Y% p9 J
- glTexImage2D(
7 s( m; C6 a6 s. i8 W - GL_TEXTURE_2D,
& Z% g# K* {: g- { - 0,) F$ b* y+ g' J" Y8 v
- GL_RED,
b3 P" z ^ t$ o1 L9 E3 R - face->glyph->bitmap.width,
; l4 t3 V1 Z0 o+ C - face->glyph->bitmap.rows,
* p* v9 @5 h% d9 J0 a - 0,
; i3 I; y! L8 O- p2 I B- w - GL_RED,
9 C A- O7 X; S0 b% Q- S2 }+ @ - GL_UNSIGNED_BYTE,
. M/ Y% q6 l6 d0 T3 |" N - face->glyph->bitmap.buffer2 G; u! b* K$ P; `
- );( Q" W6 U, g) f( o& Y
4 y! M7 P2 m9 j& I2 P- float xpos = x + face->glyph->bitmap_left;
# a/ {2 ~) j3 ]. [ U - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);- d2 K0 o. K2 M5 d4 ]/ ?
- : J. t" ?5 R/ I/ a' Z+ [4 ]& i/ Q
- float w = face->glyph->bitmap.width;
6 X2 e9 y0 v9 w4 C# r$ S( [% N - float h = face->glyph->bitmap.rows;( m) Y7 x# x8 ~: K) G `
$ V0 a7 ]" y3 }- glTexCoord2f(0, 0);
7 H$ I' S6 O) u/ `7 R' M - glVertex2f(xpos, ypos);
5 x. k: Z* i0 n" L" Y7 l - ; v* \& G! V2 j* a% f% @" L
- glTexCoord2f(0, 1);
, ?9 _) ?3 p, u4 A - glVertex2f(xpos, ypos + h);7 _. \( z ^( C- H- z
G% w' l. S$ `# d% _1 ?5 E' |9 V- glTexCoord2f(1, 1);" |& Z2 d0 L x' c; J1 P1 x: ~
- glVertex2f(xpos + w, ypos + h);: f) Q4 R$ J9 m1 }
2 }/ G/ ]0 U5 C- V# X% A! l, {- glTexCoord2f(1, 0);3 O: H8 _$ R6 k* o
- glVertex2f(xpos + w, ypos);3 g* z- M. ~$ ~ m8 {+ K
+ W5 x' H7 Z, O- t- x += (face->glyph->advance.x >> 6); // 字符之间的间距) o' ]: }$ s2 w: g
- }
# u# |" l9 o. j" x) } - glEnd();! T% v8 J% G7 A7 c. N: |( z
- , S, ] U6 v+ @9 w. T$ X6 C* P
- glDisable(GL_BLEND);/ @! _' w# k: j( |" O; {" b
- }
" N# m" k/ R7 F% k# Z- v' K - 6 T: g+ \9 |! w) ~2 f( p
- int main() {/ S' @ ]- T o" ?3 s* ]1 r0 K. S$ |4 t" a
- if (!glfwInit()) {
, K1 ]% ]' a6 f5 L- w" f - fprintf(stderr, "Failed to initialize GLFW\n");
! [0 i5 i/ Y# H+ T2 w. V - return -1;
& P1 ~2 p) s1 q! y0 A* f+ m - }. a0 W) Z; W' B: Y1 n9 e
+ @, _0 Y6 d; q- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);: s& Y# S7 z8 Q
- if (!window) {
' K$ O4 }7 n0 D+ ]( v8 S4 W2 f - fprintf(stderr, "Failed to create GLFW window\n");# I/ a) t- V0 q6 j; f2 Y
- glfwTerminate();$ j. E) E5 s0 v0 ~
- return -1;1 K1 i" i9 { u8 K
- }) W7 F: n, A5 C
- 0 [3 z$ b8 t: {3 n
- glfwMakeContextCurrent(window);
6 c6 Q4 ~; p" ?2 @ F {& u9 a/ a - glewInit();
p3 G9 i) f+ Y2 n5 _ - 9 v/ x6 W* {4 P8 s9 W+ \& D3 M! O
- initialize();; u% i0 L$ `) N" t
1 w; T1 B1 }+ S3 A6 i- while (!glfwWindowShouldClose(window)) {
" { C+ s/ N; W! x$ B4 ? f - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);3 K- l3 K% C5 h6 r% c6 Q" z
- glClear(GL_COLOR_BUFFER_BIT);
" n5 {% S% F: H* X4 W# A2 L6 R
7 @ X9 s) }+ y2 q' P2 Y3 X- glColor3f(1.0f, 1.0f, 1.0f);
- _1 B6 T) N% b# |. p8 |4 M( N - renderString("Hello, OpenGL!", 100.0f, 100.0f);. w5 Z9 ?) J U2 U* |; y
- % S. m$ C; D1 L2 A
- glfwSwapBuffers(window);, w- X, |* h4 G9 C# h
- glfwPollEvents();3 ]$ Q/ n* O+ j" o7 `# T% t
- }
3 g) d$ d2 Y" C: j - 4 {# N' a3 p0 [4 P
- FT_Done_Face(face);+ P' }; `' J, [& o! _$ Y; t/ w7 K
- FT_Done_FreeType(library);
2 i% [% \2 F# V - 8 u& U& y5 y" C' i% N6 E9 z
- glfwTerminate();
; ~3 Q9 m1 H" c% }1 z0 H - * v7 Z- T6 \/ b! R
- return 0;& C/ B% ^, B' d1 J& x& j( R
- }. E$ m; Q3 x7 {5 N! ]' F
复制代码 ( x& h2 i5 J. m( B
4 j& E4 u' H1 \9 I1 k" W |