本帖最后由 shane007 于 2023-9-6 15:32 编辑 & H( p7 c: D& e( i4 J2 f# E
! S3 [0 y) S" b% x
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
6 G( V: j1 d/ N+ e. }本代码经过分析以及改写之后,将取代游戏原有的显示函数。5 Y+ h3 F- i3 u: |6 n6 s( B, K
5 @' {! e& Y0 p& N/ I% Z0 \# P$ I. U
代码详细说明如下4 X3 D4 z6 H: U7 h4 C
' ^0 j5 `0 K8 w- 在上述 renderString 函数中,我们有以下关键部分的解释:1 n" l1 ~9 D! h& h
- . I2 ]- R+ h2 K5 m% C- D- n
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。9 _9 q2 Q. ]; F1 p1 M7 `
# Z% L& j% H4 ]# n! t- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
% R* }& _% W7 R' D2 L6 h
- p* _' R$ f$ E8 [3 N/ q- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。: O \1 f* Z* q! e e- A% J
- 2 U* q+ i y* @1 n4 o8 h f
- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
: G. A a8 l! @' G/ A( D! z
) V0 d4 E2 J" |( l- w4 ]8 D- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。6 {1 M7 |* J+ y2 G
* n \* N. ~- B2 ^* `% P( {- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
8 f/ F( R0 M+ M& Z5 V* z
$ F8 U7 C6 U9 R3 X, J6 m- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。* r8 m4 V- k+ w% `9 J3 v
, C/ \$ p& z& g% D7 O5 b7 w7 \- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
& K0 Z/ w* ^* r2 Q
. x3 u1 X& R2 H o2 I- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
* U7 ]/ z8 ?1 O7 x A1 \' L - 1 z* c" ?# U$ B! Z( i* A
- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。, I' x2 U0 i8 n# ^$ _0 q
复制代码 0 s% S5 _5 l' l# f
. Z) y$ L% S% k2 k( c" u
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:+ r, T' X9 M/ W7 g$ }1 @
' i/ f; m" g) P& ]; y8 _- 参数:
* d+ w8 \) W p( T. U1 n+ ~
- U- v5 ?! z+ z% s- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
+ L7 p! v/ ` S- O2 B* |$ R U6 L - char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
+ N" y( ^* t% N3 ~ r' h: Z4 k - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。7 o% Z( r' D1 L$ D) o
- 功能:2 ?) L% x7 n. r- P$ F
- 1 N k9 Z& _8 ?. V. b1 C
- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
7 D/ D8 w" R# r* d" v. M - 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
: d4 S5 D; P3 X" ~3 i4 [$ _ - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。4 `; B) \5 ^& W, m' R% L8 k6 h
- 使用示例:: n( @! A! A7 @2 h
- 0 F4 v" ~8 \9 B( G1 N# u9 q
- c
+ `' l2 c+ J8 i8 ^# q4 I7 K - Copy code, ~: z2 g" i" @+ H7 c% y1 G3 R
- FT_Load_Char(face, 'A', FT_LOAD_RENDER);* V' Q& |. k6 T5 e
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
/ M5 \) e d4 l - . d* D; K, Y* @& @1 K8 n. ]
- 错误处理:
) x2 P1 ?' {- _4 d5 @3 b/ j n& u
1 A- Z b6 q3 J- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。3 `; g! q9 F- x( ?5 D: y
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 1 R' h" D( W3 ?6 T* L
. h& L" P& D) ]8 i/ N& _& Q) F( r- Y$ _代码
6 c( ?4 q. [0 [$ _/ Q( J" @8 k% f% r% Z% {3 G
0 ~8 i4 H5 m% H" }; t% _/ J$ ?- + H" |4 ~% P9 U, V; g& g5 e& Y
- & F- {5 F' j2 H/ u# e5 }: }* N+ I, I
- #include <stdio.h>3 F. f, G/ h! w1 w4 }( [: A" f. t/ \
- #include <stdlib.h>6 d& V; [/ E7 H. M7 I
- #include <GL/glew.h>" g5 `( ~: {6 y. h5 K
- #include <GLFW/glfw3.h>
) o) ^, b$ H+ W3 _ - #include <ft2build.h>/ q7 @9 U0 T3 l5 H- [0 ?6 p$ d
- #include FT_FREETYPE_H
& A2 X9 h3 h0 H, m: j- C- C
- @# h* y; q' P4 A- // 定义字形数据的字节数组
& \$ w$ `3 ~: x- h2 r! H - unsigned char fontData[] = {
) |! W2 S5 ~& f9 L. J - // 字形数据的字节表示4 M x5 j2 m" z# k) I+ i! h8 d( q' l
- // 例如,这里可以包含字母、数字和符号的字形数据
* {. j/ C6 G6 E2 m8 v6 ^ - };
- n! F/ j; S2 ?1 F+ e& E% i - : o/ h+ r2 ]. c& b U3 F& N- g; m- K6 F
- FT_Library library;
: ]( R, |+ N: q$ a) ^ - FT_Face face;
' n. [$ u5 c9 P( O; J- q+ W - GLuint fontTexture;- `1 C' i& H0 E, S, I% V0 M
- 9 K$ S/ y+ K c) s* M' b
- // 初始化FreeType库和OpenGL {/ l" g% M+ D5 [# w5 g" s
- void initialize() {* K) o3 J" D( E; [* v# ~
- if (FT_Init_FreeType(&library)) {( ^# M5 W) W# ~) ~0 }# b2 C" U
- fprintf(stderr, "Failed to initialize FreeType\n");3 s6 S$ J- ?" E v8 m
- exit(EXIT_FAILURE);
( l: E5 o# _ S9 n# B! y" M1 N - }
+ i& c7 ]" y7 h/ J& H! U- _/ a% | - 7 T2 \. X4 _# F3 P; m }
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {0 ?& X }, h0 G! x* o- C& W" t- x- }
- fprintf(stderr, "Failed to create a FreeType font face\n");
9 O1 O9 u4 g3 {. w/ d/ o9 F - exit(EXIT_FAILURE);
' w/ U% i) D+ v$ I - }' j e/ C9 X0 t. h' ]
- # I1 t' n k W8 ]/ s
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小+ s v+ S* X: u& G! n: f
- fprintf(stderr, "Failed to set font size\n");# H0 d* _- T* c9 Y
- exit(EXIT_FAILURE);
' @/ z8 {# m9 n# ~8 ^7 Q4 R - }# R7 X: k0 c1 H+ ?6 G. G
$ R- r# j9 Y$ F) D- glGenTextures(1, &fontTexture);, H3 H8 P- N1 A; }9 y F' U" F* r
- glBindTexture(GL_TEXTURE_2D, fontTexture);' Z7 \) {: {% {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
4 H1 h# ?6 F# I- \- H
) A8 h2 K |0 c- // 将字形数据传递给OpenGL纹理
# d5 |/ P6 o, O - for (int i = 0; i < 128; i++) {
S8 t$ |+ Y+ ^- R - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {! | f0 t3 |) z! X$ g( h5 g
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);* {" C1 C) B8 ~# F7 \4 f
- continue;
# l( E5 f) e1 U( Y7 s - }' u7 d& i5 m4 {3 i$ K; |% ~1 p
- % T3 O: T7 C8 e9 [& i7 t
- glTexImage2D(- U& D! E0 d7 F4 o7 B
- GL_TEXTURE_2D,0 i3 M F) {% l" `2 _4 U
- 0,
1 i* u/ l! k; A! w0 w: X5 M, B - GL_RED,
& a" m4 s8 O! X5 p - face->glyph->bitmap.width,
+ H/ R0 | L: @/ B* E' g0 d H* ~ - face->glyph->bitmap.rows,
* m/ f. o1 m/ @# Y8 e - 0,5 m0 c# _" t1 O1 o
- GL_RED,
* g( n" U3 ]; `% e. Q - GL_UNSIGNED_BYTE,6 u C& Q- w8 x& L5 X+ i
- face->glyph->bitmap.buffer2 Z# n |: h8 b0 Z
- );) i& o; {+ d1 s) y
$ F$ c/ G, o8 f, X! j- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
% q! ^6 n4 M) A( n* Q4 C - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); Z$ [1 E# ~3 Z. w. v2 a1 K! Y! \
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);& j* D! E7 B( y$ r9 \5 v {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);( s3 {0 }' o. V, ?( n2 m7 ?
- }' G7 E+ V- R1 o
- }: D4 `5 z! d1 b
( b, ~3 x5 O: |5 X* q! X* S# m0 ?- // 渲染字符串
( b( B; R7 U' k- L+ X- i - void renderString(const char* text, float x, float y) {
3 c7 Q6 l7 r* O% v8 O - glBindTexture(GL_TEXTURE_2D, fontTexture);
' K; e8 I& ^4 A! C9 `( t
# P: _+ E$ U3 i" R* X0 s- glEnable(GL_BLEND);
, C b6 t4 i8 x; W" i) o - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
! n) a( o% _6 ]/ y9 E - 9 Q$ p$ {( O* k2 a6 G% \
- glBegin(GL_QUADS);; i8 j5 e% i9 H w, d/ ~8 N
- for (const char* p = text; *p; p++) {( M8 V* i8 z7 k5 n, f% u8 K7 g
- FT_Load_Char(face, *p, FT_LOAD_RENDER);
4 n# Q2 C; x0 L; H1 |2 D$ R$ n
& U) r+ c/ P n+ x# K" i; r- glTexImage2D(
* _, k$ W& v9 R& l6 g) b; `! W - GL_TEXTURE_2D,( o" z- D- o5 y- R! v; W
- 0,
: J& v8 [$ c, c& ^. y m3 `$ X - GL_RED,: w: l! q& n! p8 j* L7 o6 @
- face->glyph->bitmap.width,! O. O. w9 m. u! C& i& F1 o4 X
- face->glyph->bitmap.rows, x9 a# S0 e+ I8 l8 k
- 0,
, \% [0 d: z3 ~4 s) n - GL_RED,
& |" X, |- m8 t. W+ d; ]( e3 n - GL_UNSIGNED_BYTE,: T+ \6 C- @7 S9 y1 |- X: G
- face->glyph->bitmap.buffer
; U/ `9 f T6 j" o2 o - );& M- {& h: K |1 X/ m
( Q2 V3 S& {* h% h' g- float xpos = x + face->glyph->bitmap_left;
! ^. e' q0 W; K9 d4 {! y9 D - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
& W7 r1 u! K" ]8 s - * s0 T7 t2 g" t
- float w = face->glyph->bitmap.width;0 ^1 t& W+ _" d! ~/ M3 Z
- float h = face->glyph->bitmap.rows;) o3 R& s4 P: k
6 b+ K; O4 q, H6 R9 l S- glTexCoord2f(0, 0);
9 Y3 `1 k5 U! { - glVertex2f(xpos, ypos);" U \: N! t9 {) _2 z3 }
- ! U' z- L8 X5 u1 @6 W) V- e4 P. Y
- glTexCoord2f(0, 1);; b/ I0 w' C7 W; ]
- glVertex2f(xpos, ypos + h);5 a" k8 T( v6 P
- : X1 b! S) V3 b/ B- ?; l
- glTexCoord2f(1, 1);
" y5 L. x' g5 J5 z( T& n+ T+ \: x - glVertex2f(xpos + w, ypos + h);
" X2 ~* m G& S - ( k2 d- u) f6 Z# |" ^
- glTexCoord2f(1, 0);
; L1 Z Y' O7 ]+ K6 C o - glVertex2f(xpos + w, ypos);& j, M, i3 {- J/ z
' R9 I. d2 I1 s, v$ v- x += (face->glyph->advance.x >> 6); // 字符之间的间距
- L S$ e* E* a, L% s! w" y - }
' M8 C q+ |: Z4 ?. l5 u( I - glEnd();
' O6 p) w- x) o9 s2 R
7 F: l3 F( ^: \ y- A- glDisable(GL_BLEND);
; x. t: q; p! i1 V1 @ - }$ |( r8 u3 S; b. [1 W1 k7 O. C: |) b
- 7 t! _7 E# G/ U# m Q
- int main() {
* w* E7 C$ L- x. Z - if (!glfwInit()) {
! g3 E9 t; C" P - fprintf(stderr, "Failed to initialize GLFW\n");
7 v t- k- g8 H3 K0 }& x - return -1;
- C- T- A; _9 W$ O& g8 f/ r# w& K - }
$ f. \! [( ^5 N! a - . c" `: i# l' w1 s+ |6 m
- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
4 r. K2 p" A7 t - if (!window) { R" y9 A: G4 o; r) ^- x7 k
- fprintf(stderr, "Failed to create GLFW window\n");% {- z4 o7 |9 A. J
- glfwTerminate();( _. U# w8 r( {0 @, O
- return -1;- }" p, L+ b. k$ K
- }
. @% x* |6 B0 E' U; s: m! [ - |1 r3 j+ p. k* b
- glfwMakeContextCurrent(window);" q1 e9 h, b% S; `( c% `
- glewInit();
. T% d& p! y' `! l
' e9 m7 n9 a2 }: q0 x- initialize();( E4 f3 ]. w/ Q* Q: f, a! o
/ x! h7 x/ |% @: c+ j: l# `- while (!glfwWindowShouldClose(window)) {
/ ^) ~ B) \' k8 d. e: h; V1 G* S1 } - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
, W/ W. Q3 i: D8 {( w - glClear(GL_COLOR_BUFFER_BIT);7 w- l- q, @- K6 F! I& H
, G& g l$ A$ |6 |, m- glColor3f(1.0f, 1.0f, 1.0f);& u& `4 g+ q' t, O: e. `
- renderString("Hello, OpenGL!", 100.0f, 100.0f);
: U! i! M& H7 k - 0 D' {' n5 s. l- t. Y* |5 x
- glfwSwapBuffers(window);1 ?( j T4 w# e; ~$ Y+ }1 d9 j
- glfwPollEvents();
7 `0 d" G% M5 s: w! l: c" L& r - }; l. ^4 p" ~3 H o) A4 g
5 i# y' ]5 E7 o. D/ M$ y0 W+ ]7 P- FT_Done_Face(face);$ O7 V, P$ }7 P# y Z- G6 O
- FT_Done_FreeType(library);3 \' B6 G3 {% R' @& W$ D
- 2 {. @; G, m; {! {/ @8 R
- glfwTerminate();
7 [0 e; K+ X5 k% y6 |2 C/ }' b; _/ c - 1 t% x7 w' m' U. D0 _* K" W% ?% I
- return 0;8 O) |( N9 Q$ Y+ v; o
- }. s4 G' U8 U) `
复制代码 , z$ o: n% A/ ]+ q6 P ?# J
/ T) p9 w! b6 k8 |* a |