本帖最后由 shane007 于 2023-9-6 15:32 编辑
1 [) Y) o3 z5 z# j j
8 Q9 u! r7 e2 G# l3 m2 q0 M& e以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。3 o. _) j1 m* _, X# A5 K8 |: D8 S
本代码经过分析以及改写之后,将取代游戏原有的显示函数。
: N; @/ |$ @- S9 t: z3 j
- ], s: z ~$ A2 u7 V, a5 C/ V代码详细说明如下
G. K7 b% g5 j/ ` w+ i! E
$ k; M8 B# H R. |0 g- 在上述 renderString 函数中,我们有以下关键部分的解释:
, F* Y* T. \ |& D5 Q1 Q/ k$ E. \ - \5 k! C* C& S- a/ f
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
2 v" L: g5 z% _) d: | - ( H% q; ~7 w2 O, o* R" u+ e( B7 A- I
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。: h) X) f% S! h
- , p$ {' P: y2 @4 B- a
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。( W6 m& k) l) N# \
M9 h% N9 c3 S' _2 g4 |5 B- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
. J) H7 E: B9 v( V% { - * }3 N/ O6 T% Q" E
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
3 V2 _1 H8 B4 z F - 1 v l& l( N1 F" T* y
- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。2 _9 Y7 d1 p; O g; Q6 |
- ( A- ]5 E& P3 I3 j* Z* l/ K# ]. A
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。1 e% N( _9 c8 X6 G' p
- 2 p* ~: m/ _$ R3 R4 S
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。# p/ N9 W" b! h! I( C* N
- ! K9 { f. E/ S( u8 Z# C8 A
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。, N% H2 i1 L( Y, w0 R2 }4 V. g' g
& s) X2 L* C* \: L% G+ r- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
( G3 B' |. D2 o3 q, T
复制代码
3 @& W8 f( ^ W! H: O5 }% {6 l% B: |$ ~3 C3 q5 D" `. _
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:
" Q+ w5 U4 t- T1 z0 X/ e - 6 e. g: p& i1 I. [: ^9 ~5 c3 u: J
- 参数:9 @ F# I6 R5 [, j- n# |5 L
4 [2 w( v/ {; \/ ]0 w2 A$ g# s5 h- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。6 U" a7 P! O+ L0 F
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
" b' {% K: G4 T1 H - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。: a+ q" ]1 @3 t& u+ U# G7 S
- 功能:8 Q+ G( {1 S2 f4 }
- 0 P, G# X+ f& n- p# [+ g9 z% x
- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。 @! B1 D% V# M5 N; W0 k- C
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
/ d) \2 G9 q$ N! ?# `) d# w - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。) v" W9 i+ [+ z8 W" D7 B
- 使用示例:# Y& T) O! _& p- z, _
- V3 A% Y) t" c ] G- c
7 A) ^6 T1 y+ ]1 ?6 M( ^ - Copy code6 L: ~( v+ o6 ^! h3 i
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);4 [: ^% a @( B( `' a; ?9 I
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
6 r; D# \4 y1 t( y s
, h9 d0 } r7 U" f& X4 F+ t- 错误处理:
7 Z6 m( j' k* Q# T
0 H% \- W: D3 i C$ ~8 m- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。0 W$ V. o& K" y
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
7 m+ M& L5 N$ M/ S( E$ U- q0 ]+ A6 p2 \" U7 p' \* ]
代码
" Z1 _- q& T0 y) S# D0 H7 h: k9 c+ p# \" y: Z
- # t8 W0 A5 {7 }
' i( F* K3 ^4 h- 1 }3 q! @) v* Y! G' H! d( B3 l% x! Z, ^
- #include <stdio.h>. v0 f) w6 {+ \ Q1 q5 ]" G6 h
- #include <stdlib.h>
7 O3 l" v. Z3 d/ K4 R, A9 X - #include <GL/glew.h>/ U, s. L8 d: u& B. d7 `, `
- #include <GLFW/glfw3.h>
8 A+ l9 X6 N$ u c" s - #include <ft2build.h>
* E- H7 j* I. |, ? - #include FT_FREETYPE_H
3 \$ X, F+ k# V; y3 m - ' a1 `: X- n/ ~) U; k) Q
- // 定义字形数据的字节数组
. ?8 e9 S6 F: |; Z' E$ @ - unsigned char fontData[] = {
1 R: {0 P1 e0 Q( s* F3 y T: a - // 字形数据的字节表示
% B4 a( N2 C: j! _ - // 例如,这里可以包含字母、数字和符号的字形数据
X' c- ~( C/ T8 a4 L- D - };
( h" I9 |/ @! R; U3 s) f4 Q& { - & o4 ^! z, }+ L9 ]
- FT_Library library;0 C/ S; j4 I2 P3 P
- FT_Face face;
: Q" o$ `$ K9 a& _% D+ v - GLuint fontTexture;
n/ j% {: C; Z/ |0 b
& f0 Y: E; K$ V6 R9 P4 N3 @6 R P3 r- // 初始化FreeType库和OpenGL
) N3 U3 N' k; G) [+ B+ R - void initialize() {8 v4 r+ Q1 }1 l
- if (FT_Init_FreeType(&library)) {: l- }" j' e# a+ ?
- fprintf(stderr, "Failed to initialize FreeType\n");8 O, _# O" `0 ^1 f9 t2 ?2 u& ^0 K
- exit(EXIT_FAILURE);
& T4 C5 [8 u, n5 Z" s; @ - }
O8 k& C- J" I+ p+ u, a0 k; r! u' y - + G. H, |- Y1 A. K! r0 v9 A& m) L
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {: u5 o7 e8 {/ F* z7 U2 a7 R7 C
- fprintf(stderr, "Failed to create a FreeType font face\n");/ @% t' o7 x2 x" K6 g' J2 P
- exit(EXIT_FAILURE);3 {6 ?- j' I9 T
- }
7 {1 E8 ~9 `: ]8 L* q
( U$ S; A( Q6 r) k) M- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
( j& ]. }0 ~- Y, Z/ { - fprintf(stderr, "Failed to set font size\n");! A% ~& A( u2 ?, S/ P
- exit(EXIT_FAILURE);9 [) z, a& \. u# a) o3 b
- }
/ n# M0 o' x8 U3 x - 4 s3 d3 z- }6 G9 Z* P+ k# q2 Y' n, \
- glGenTextures(1, &fontTexture);
# H3 [; I& E& n7 p5 J! l1 w* Q6 i% s - glBindTexture(GL_TEXTURE_2D, fontTexture);
% a" Z! q( h# B3 L - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
, U$ d" [6 C% O9 E) E
6 ^* W( Z/ [0 F) B; T- // 将字形数据传递给OpenGL纹理
9 n4 T# t2 o& L- M2 L Z7 @. X* ? - for (int i = 0; i < 128; i++) {7 g: {1 s# e: P! i) u7 m
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {* q& X. u( ~5 L, i# x2 Y
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
1 e3 T7 w% W" M; r6 L - continue;
7 K* ~ a# d- b/ X - }
: h3 p5 @, t$ p - ) O+ G# z$ J' f
- glTexImage2D(+ k3 X& q1 M+ {, [2 }
- GL_TEXTURE_2D,, _/ e+ z9 [ j8 p& @8 m
- 0,+ E6 Q$ B* j2 I
- GL_RED,
' S" u. u% [; v5 | - face->glyph->bitmap.width,, ]0 }: I. c; p( ]
- face->glyph->bitmap.rows,3 [1 a! F* o- t$ S- f
- 0,
9 w$ t! C+ J; z7 p4 f, @ - GL_RED,
; U* j$ x0 ~, {5 |$ ], I4 z. e - GL_UNSIGNED_BYTE,
% R! e7 P/ M' M0 f7 o3 ? - face->glyph->bitmap.buffer
+ A+ [9 L+ q/ d - );
9 X/ E. h/ l7 p8 q( ]2 ? - $ Y+ V3 R+ X! t( u
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
! k! m" l) e9 C* n1 R7 c- m - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
. M+ [/ B- b+ `. x - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);& D! y- x2 X- z5 p; M5 R
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- z/ C* w5 ?+ f S1 d6 O* m - }
6 X9 W1 x0 N# q \- V5 S$ c! q - }
8 S- K# N* v6 u) Q" Q8 q
+ P3 L8 e( [0 k- // 渲染字符串
3 U- \5 W- z2 f0 K9 c/ T; o- \- b - void renderString(const char* text, float x, float y) {
% V' h6 n$ ~7 Y* ~1 C, b) D: O - glBindTexture(GL_TEXTURE_2D, fontTexture);/ \' p# k9 @- Z2 v: |# k
- ( P+ L5 i O" i' I1 T
- glEnable(GL_BLEND);
( m/ I6 M4 P% I/ ~' `1 Z* S - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);2 ?; I7 g! V s; E, V$ H6 W6 x
- : C! }, g c6 v% b: Y
- glBegin(GL_QUADS);6 a# Q) F3 U2 v8 ?. S* S% ]' h
- for (const char* p = text; *p; p++) {
5 `1 [- {6 ]2 D - FT_Load_Char(face, *p, FT_LOAD_RENDER); V& D' c0 D% {0 s
- ! {9 P9 ?6 M( ~$ w
- glTexImage2D(
# ]: B+ ^: V& h( i& [) H) _! U - GL_TEXTURE_2D,0 D2 |, u7 t. l7 z% n$ }& T
- 0,
6 x" |+ }# O, A9 R# f8 F - GL_RED,
/ @- J: H5 b( d) K# y- | - face->glyph->bitmap.width,
( M; b2 y9 L! s1 T - face->glyph->bitmap.rows,
, A: D& l4 q9 K2 r2 ~6 ` - 0,
8 D3 g G$ s) M, _$ ~7 c - GL_RED,
$ C; d; z& ~5 z - GL_UNSIGNED_BYTE,
: d0 D; o0 |: R( X# p4 M - face->glyph->bitmap.buffer
$ O" Q3 E4 w, M - );: T) H- t+ d: ?- H2 s# ?
1 c7 Z: p2 p2 l! G- float xpos = x + face->glyph->bitmap_left;
/ q; @3 ` w; K/ G- m; M0 Y+ y2 p - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
) B9 U4 N7 D7 Y5 l - 4 m" C: N4 l; Z" u
- float w = face->glyph->bitmap.width;2 p- v0 ?. r7 o! K4 o8 [) \! ?
- float h = face->glyph->bitmap.rows;
. C+ S6 K4 G" |& O( I' Q4 r' e - 3 r& A; w. Z' K p& A# o8 i) N% y
- glTexCoord2f(0, 0);% d4 j# a( ~- P& ?9 V+ ^. }
- glVertex2f(xpos, ypos);
% u4 F5 e* T2 m) ~5 V - * U6 k9 `# A; j
- glTexCoord2f(0, 1);) v5 d' s& z1 W9 D
- glVertex2f(xpos, ypos + h);& ^& V3 U: Q/ Q* ~0 s4 }- F% k% w
- ! O3 H" q: {+ @
- glTexCoord2f(1, 1);7 r6 g" o9 j T8 a4 ?6 l
- glVertex2f(xpos + w, ypos + h);- e# x8 J9 ^* I) ]
+ S+ k( X5 _6 M+ H% d' P- v- glTexCoord2f(1, 0);
1 Q& E c3 r# a! @2 A! d - glVertex2f(xpos + w, ypos);& |3 y9 ]3 c4 q( w" L+ ]
4 o2 X5 T i5 g/ j* \- x += (face->glyph->advance.x >> 6); // 字符之间的间距
* P+ r, j {! T8 k - }
/ {7 i" Q+ i: c4 t - glEnd();1 o3 b) c" k, V t
3 U( W9 X2 l7 Z \2 H- glDisable(GL_BLEND);
: | l+ M7 n) q" U - }
r. R6 e7 z. s% O8 A* K4 ] - : k( ~1 V( @/ ?
- int main() {
* d0 w ?: K$ z9 e" D. M - if (!glfwInit()) {. ?6 D5 t9 b/ i( [& G$ ~. Q
- fprintf(stderr, "Failed to initialize GLFW\n");
. b4 |# x' k4 a$ k$ `+ E+ x - return -1;
1 J/ t" b/ R/ t- a9 l - }) z+ P3 T# f. Y3 q2 h8 W+ `
/ b; \) G% S7 p0 n# }- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);# F. K) b( Y" H+ Y9 r* }
- if (!window) {/ n4 b8 ]1 T& [8 c @, Z, V# ?+ \" Y
- fprintf(stderr, "Failed to create GLFW window\n");
( L+ M$ k- N, E6 Z# {, x - glfwTerminate();
) A2 z# h6 y% p2 n - return -1;
5 B# _" Y5 l# K" v, ~ - }, d# Z2 j0 b2 _4 F1 l: N$ `0 l
- ) o6 n/ I. e- z1 |* ^) Q5 d3 J
- glfwMakeContextCurrent(window);
/ E/ B/ {4 }! a* F - glewInit();3 O5 n& P! u- K) p; N7 d
* ]0 M( k% N' A, G- initialize();
1 s1 _( }( g0 T v7 I
: h/ f2 Z& ~8 n/ M/ |- while (!glfwWindowShouldClose(window)) {
. U" h. F3 u2 k4 y& s$ m - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);7 B' D3 T- S- a" o: Q7 s' c0 C k/ w$ h9 J
- glClear(GL_COLOR_BUFFER_BIT); U: r' ^. p! P- {( X5 s. q* u% t
% a. N# ]7 N* T( O" E& x- glColor3f(1.0f, 1.0f, 1.0f);
+ D# Z" }0 |9 w; o" P6 w$ D - renderString("Hello, OpenGL!", 100.0f, 100.0f);
N9 g9 n! O# r; L0 F8 f+ \
4 L; W0 l1 U* u+ U# b0 L! h- glfwSwapBuffers(window);( p* \( v: Z$ @2 [
- glfwPollEvents();
6 O/ d; X, p1 n& i; A5 E; D - }( h/ h8 G' ]+ T$ {5 Z4 {0 x
- ! m* G5 {8 `: ~; l7 k
- FT_Done_Face(face);+ y' |$ F" n7 ]6 c& P
- FT_Done_FreeType(library);
U/ M: @ i" w a9 R" _% L - $ r2 Y& u2 j6 E. R. M$ {
- glfwTerminate();
$ m1 F5 V" F2 I$ N! J* j6 y9 l
W& i; v/ ^" M& E+ h9 K- return 0;5 `) I2 b J; X/ F
- }6 g6 f ?+ \% A B& L1 E
复制代码 . v1 p7 z" A: y: q/ o
& u) H6 k0 N; x& D# J |