本帖最后由 shane007 于 2023-9-6 15:32 编辑 ' m1 ~9 o! j4 C% ~. z1 d
5 t+ y5 }# U' D7 ]) B& ^3 d8 J
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
. H: N# s* c. _本代码经过分析以及改写之后,将取代游戏原有的显示函数。( m( J; B! z: t/ ~
: i: B6 ?6 s1 a/ O! T1 V; @+ y8 R
代码详细说明如下- ~% r6 ]% `+ u5 j' Z' j+ j
/ f' U0 v6 o4 d3 U# n8 e6 I- 在上述 renderString 函数中,我们有以下关键部分的解释:
* \& J3 Z5 j2 `! k' z - $ N3 M2 v7 x3 v% T# b7 ^
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。) Z7 Y W- D4 d" K3 I3 ]
" }* G9 h( z( e$ r- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
3 m F- d( `, _7 G8 D; V- \ - 3 }0 }1 H, P5 `
- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。& `+ \0 F8 B5 d% v3 K( f7 L W
G, D. `" \& `7 o- `- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:+ r) q# }; N6 {
- $ L9 S7 R8 N/ C: X* w6 k
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
0 y1 o: o1 W8 ?2 t$ J - i4 y: n/ U5 A% l: o1 {
- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。5 i ]7 w/ H0 d2 t
- ( `) L# k- [9 y) z, {
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。; [2 t* n+ z5 E( s" J0 B
* U3 N6 {6 N" @5 ?% s9 I# Y+ q }. ^- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
2 O. T* U3 z( @' U& ^" Y/ r - % E9 h8 Y( |. |4 A8 S0 s) [4 ?
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。1 r6 m+ I# k! C+ |1 j
8 D/ c% B1 Q; [. V: T* Z6 F9 [0 A- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
3 C$ G& V. t4 p
复制代码 - e. o/ Q8 s# N$ ~- L* f
. N, g! j0 z1 S$ S; o8 @
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:+ m1 x2 Y; k K8 o
/ r5 q- p( n0 w6 a% l- 参数:
, x* g8 j K* }) Z" y
( A# T) d3 b/ Q2 g# e- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
/ z$ G' |. ?# { - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。3 e8 h7 L" N" n3 W- A! \
- load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
L @! ]2 J5 l3 b - 功能:) W+ x) s* r X) l% Q
% u9 V4 e' h5 \2 t- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。 U M" I( v0 t% ?' D
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
) g( R' z, ~8 O( } - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。" ~' r Y7 e" i/ W- o% U5 h$ h
- 使用示例:9 a; j v$ W$ k5 }6 G, y
6 U0 r/ ^8 V7 d m X- c
5 K( `4 I/ M. F; J' y - Copy code
5 |& s! S* m- W1 f - FT_Load_Char(face, 'A', FT_LOAD_RENDER);
2 Y1 I( l0 f7 V G" e, `2 e - 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
# c' v Q% O& b2 G- V$ A - 1 e- G' g5 [# T1 b
- 错误处理:7 u+ T# i0 A4 `( b! |+ m
9 o' v* e7 s. N4 t- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。" X! y* V4 g; p9 o: `6 \4 {
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 7 S8 ]+ c. `8 W( g% G6 W5 \2 {2 v
8 _5 h2 ?6 s, h! ?" F代码
- B" n% \9 Z6 J" l' Z1 j6 L
7 N" j- d# o- J M6 V2 C! w+ [- + N/ G4 t7 ]' ?1 n* x
- 1 |( n8 ^/ _, n% d0 ~' F
+ Y; q/ V1 \) B+ ~% ^- #include <stdio.h>
, U, X# \8 P& d - #include <stdlib.h>
7 f7 ^& s" v+ `: G @" J - #include <GL/glew.h>
' N; A* l1 q$ Y8 B* Q - #include <GLFW/glfw3.h>
: r ~3 ~; _% i6 R) [ - #include <ft2build.h>; F2 ^" e( f3 A$ y6 \& t) q; t& [
- #include FT_FREETYPE_H; D3 L7 m0 r* N5 l
" t4 w+ r, @ ~ v. |: @1 O. [& L- // 定义字形数据的字节数组, g1 N& W' C8 w- o4 h
- unsigned char fontData[] = {9 B1 ] e4 a3 w9 K0 \) D! _
- // 字形数据的字节表示8 C# H. f2 B, P$ Z
- // 例如,这里可以包含字母、数字和符号的字形数据
5 ^# Z. {% z0 F - };
: m: n4 }) @& r2 @7 ^ - / {0 d! a0 W- ~0 a
- FT_Library library;+ Z# b4 \. ~! }
- FT_Face face;) {" z; g, H4 A1 t0 C
- GLuint fontTexture;
6 u$ k$ M k0 ~0 ?& [3 {
& Z2 a9 p0 H' q* S* l- // 初始化FreeType库和OpenGL) i3 O$ _) X9 p( ?$ t- S
- void initialize() {
9 K4 q+ D2 V# y$ z( k B - if (FT_Init_FreeType(&library)) {# z9 t2 `% o9 s4 z9 s! n
- fprintf(stderr, "Failed to initialize FreeType\n");
9 v4 I- c' n9 A( z6 [( ^" } - exit(EXIT_FAILURE);' S/ u2 |+ @- c
- }
0 B0 d, i" r, F$ h+ ?: L% ^
8 }+ W- b3 O4 P2 H- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
5 z l0 ]0 c( J: P; b5 L4 K: { - fprintf(stderr, "Failed to create a FreeType font face\n");
& ]) ]( T8 E" o* V4 A - exit(EXIT_FAILURE);
; V0 Y) I7 P0 I" H - }0 M& e2 \1 ~) j6 Z2 f" `
- 2 ^$ l1 Q9 i; H/ y7 q% Y G
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小3 G5 A% F( a3 e( C+ T9 |
- fprintf(stderr, "Failed to set font size\n");) s' y/ v3 E- D
- exit(EXIT_FAILURE);# G$ L3 e1 x6 K& X' m: l$ Q U
- }
, b; P7 i2 m1 f* ?7 z - 8 I8 D& j) Y0 {$ E( M' j
- glGenTextures(1, &fontTexture);
# ]; E8 p# m/ T - glBindTexture(GL_TEXTURE_2D, fontTexture);9 ]& F3 B: f8 U3 z; x, D
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);2 H* f7 [3 ?0 I! `
- ! s# i) }$ t# f/ M
- // 将字形数据传递给OpenGL纹理% f- b3 q0 X A4 ~
- for (int i = 0; i < 128; i++) {1 q5 { r U$ \; a3 [
- if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {( G, k- p# `4 O
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
3 S* P3 t! v% m' u* i - continue;8 `4 I* T* w1 c' h; g# T4 J
- }
8 G9 `. H% z/ J. y0 j8 }
$ x+ C0 L! J& Q2 C* p+ ~" W- glTexImage2D(! c$ c( l: V( ?; }* J
- GL_TEXTURE_2D,
1 `1 k# J! N, E% ^! j: a7 E2 F+ ^ - 0,- k3 W+ p9 n3 |4 w1 C
- GL_RED,& o) B* C- e7 s5 N ^5 ?) Z! f
- face->glyph->bitmap.width,
) t) e* v. n! a, h. M3 P - face->glyph->bitmap.rows,
, H# U% }* G a9 B. z+ a. l4 Z - 0,
& {, i" {0 |. Y: R2 t# f5 K- E - GL_RED,
6 \+ s W7 m: h+ i - GL_UNSIGNED_BYTE,* O3 d& e9 H6 r0 @- ~" K
- face->glyph->bitmap.buffer
" K7 ~) h8 Z( n. j; k - );2 k0 j* C6 d/ [
- ; K3 S* J3 y6 b6 k7 x0 d( z
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);% W& C( c- z) u/ \
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);1 i8 _) U K7 ` X7 H$ v
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);$ R, x9 Z6 Z A s
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);$ F4 s3 }* J; S% d* g
- }* R0 o- [% w6 \2 ^. W
- }9 s" g2 i7 q, c; n) r# g
% k3 w/ h0 ] q# G$ `- // 渲染字符串5 E, C. {; v) b, D
- void renderString(const char* text, float x, float y) {# s5 t7 q z1 H* F6 R
- glBindTexture(GL_TEXTURE_2D, fontTexture);( q4 ^/ I4 \# \+ u# `
- % o% Z% w2 u# P$ J1 V' S& D* H
- glEnable(GL_BLEND);
4 o$ }) M4 u7 T - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);, E. I7 h+ B% U( x" k |8 P
) j! [. w- m- R* c' N$ x8 K- glBegin(GL_QUADS);: T( G5 H' `9 |. j9 g! h% T, M
- for (const char* p = text; *p; p++) {
+ S' |- P9 T8 D* y - FT_Load_Char(face, *p, FT_LOAD_RENDER);; s: A0 B% ]! Q% g# U
& t% `" x7 T! z: Z% x- glTexImage2D(
( c: o/ @' n! l - GL_TEXTURE_2D,/ ^2 N* o' U: F
- 0,6 A" G" O7 d/ k6 r) _" z" Q
- GL_RED,+ v+ R2 T% M5 \: v& m* @' D
- face->glyph->bitmap.width,
) w! F) d+ r4 w0 M3 Z: w - face->glyph->bitmap.rows, {3 C1 J. {0 C1 g( Q7 h. j
- 0,
6 u# H0 T, d) v; ^& S - GL_RED,$ N) D8 X) ]1 x8 E
- GL_UNSIGNED_BYTE,4 `" l; Q" l0 s6 a! L
- face->glyph->bitmap.buffer
- g2 a, o4 g! `9 H1 Z9 H - );. K- J, g- q6 _
- ) |. m( r. \8 R, Y+ F: J
- float xpos = x + face->glyph->bitmap_left;# U: ?* E$ y) m" o3 m' ~5 R
- float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);& D/ ~# K b* P) W# i' R5 z
) @4 O$ Q# I5 |3 r8 m5 R5 V8 `8 H- float w = face->glyph->bitmap.width;' E& a, k" @/ J8 p2 [8 U0 x, I
- float h = face->glyph->bitmap.rows;4 }8 r4 z/ _8 v
# o6 t5 _$ Z5 F$ i8 s- glTexCoord2f(0, 0);
) ?8 d/ d8 T% \/ P2 `) u* m - glVertex2f(xpos, ypos);; N3 a; j0 \. Q1 V- H
3 T$ s8 p: {/ ^% e) R1 E- glTexCoord2f(0, 1);
! C# z5 M6 @) `$ S - glVertex2f(xpos, ypos + h);( E* ?; t9 y/ _4 U- |
- 1 B/ h' l }! K+ ~( X
- glTexCoord2f(1, 1);
8 A9 R( Q% e1 E# O" [# o' ]4 i+ F - glVertex2f(xpos + w, ypos + h);+ [' y6 b# ~" s9 o' C( x2 y
: v C& m% b) B1 s }- glTexCoord2f(1, 0);
: v8 r% b) `% s: y8 o - glVertex2f(xpos + w, ypos);0 [! P) |, Z& V3 e- V
- . u6 W/ t* L' Q# Y
- x += (face->glyph->advance.x >> 6); // 字符之间的间距! E6 R+ I% L' a# j$ u K
- }# s) E0 P: d7 _
- glEnd();6 D7 C9 L* v$ O
$ O5 C! n+ ~" `9 d# I. r2 ~- glDisable(GL_BLEND);
6 q6 G, Q8 E' @! L, n; r! w" J$ F - }, g' _7 B; C6 h3 [3 c9 k
- : V: n1 D9 I/ v4 v' e9 Y
- int main() {
/ r2 _' B5 ~; [8 _) V# E" t - if (!glfwInit()) {
/ i0 d. O1 z; p: [! ^' r - fprintf(stderr, "Failed to initialize GLFW\n");
! q% l' ~- {$ A! C X - return -1;
, `" n& S1 D/ f7 n" ~. { - }
" I' O1 w/ k- S, Y/ Q - ' C# G6 t `9 h' z: J- n" A
- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
4 ]& C0 f: m) D% U - if (!window) {1 Z I4 x* `0 z3 b" c
- fprintf(stderr, "Failed to create GLFW window\n");
" z/ }% } |) [4 _* y - glfwTerminate();: \9 {, H' ?5 z& O7 `9 B5 K2 y
- return -1;$ b2 f& h E8 J
- }( x i' n6 P7 l6 A& D9 i8 m
4 O0 a2 E( n; f- glfwMakeContextCurrent(window);
+ d) V5 ^* I9 w" |! E" o. T - glewInit();
. `8 I! d- i) r5 g - : g5 o8 ?1 r% A' x' s# I
- initialize();
( Q3 c, {0 H/ J1 `8 ]! E - 8 q: s; u% @0 D4 u. Q7 M: |1 c- `
- while (!glfwWindowShouldClose(window)) {9 B2 f8 p9 u# k( g* Z" L
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
' t7 {# [7 {: a9 t2 l% ?; C - glClear(GL_COLOR_BUFFER_BIT);
" E k& H8 t, I8 G
0 r* J5 r) Z& i- glColor3f(1.0f, 1.0f, 1.0f);
- ]. d1 v1 T. i; C - renderString("Hello, OpenGL!", 100.0f, 100.0f);
( g5 [' z6 L4 v1 l. p) v$ O - : P6 g& G+ Z2 A. y {
- glfwSwapBuffers(window);" X8 g4 E/ Q y7 y
- glfwPollEvents();6 P2 N; U# F5 E2 T/ O B
- }
- s4 V9 [. }! R# [ [/ S. S: V - % x% b/ x9 o5 |. \
- FT_Done_Face(face);' s1 J* M1 ?/ _' ]% K" n$ q" b
- FT_Done_FreeType(library);
, r+ O/ D+ N4 L) p# j, B6 F
6 V8 I @: Y- F% T( J0 B- glfwTerminate();
9 w! h2 x+ H& U3 G7 S
2 l" z- Y( g- \; I) y- return 0;3 `- a( v% K K# F
- }& d0 `2 o8 ?' l: I$ ^
复制代码
7 l# {: ]6 y4 O1 a( }1 j3 u( P$ R' `- [
|