本帖最后由 shane007 于 2023-9-6 15:32 编辑 ( R( i/ {! q; o+ ~
7 c. L {8 p; A% b' w( G
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。" e" U) n% m1 u* v
本代码经过分析以及改写之后,将取代游戏原有的显示函数。/ m n# }0 N) D8 s
. K1 J; j( C3 Q; n5 h+ S
代码详细说明如下$ k2 i. S4 t9 W* D& f: m4 P
3 g; e+ Q: }* L. k- 在上述 renderString 函数中,我们有以下关键部分的解释:4 K" F' c( v% {9 e! A$ F% i
- ; x g) l C3 K7 n6 o4 [
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
0 A) _4 `$ o& S1 Y' w - ) b" H3 N& W& l! E; n) Z- K
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。; h( k: Q0 w) J( K4 n5 z1 O" x% L
9 Q4 `5 W6 a, Q7 E# j- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。) k6 N4 ]% o, V$ t
% E3 {( ?* S; D2 p0 N5 R5 j- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
+ [( ?' [; ^, P+ C6 W
- {/ ^0 v$ ^/ C3 v+ D' v* H- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。" d! p( Z {0 a8 T/ r" v1 @
- , o2 h; e. Z5 h0 D
- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
" H1 m& d D* r: ~1 o- `
1 T8 H+ t- M: u& ~$ V. w- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。( y; d1 _0 P# j$ V+ _" _/ E
- C; v; b+ v( T/ B# m' L
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。: c7 |% k1 Y5 \; @
- ; S& b+ W0 W7 K: ?
- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。* V2 t1 D0 k; V% T& {
' }0 Y! z7 B+ a8 ^- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。& C, b& B6 D$ B: s: @
复制代码
& j) |: d' s8 H9 ~. A$ j5 ` M9 A# }. D0 B) t, F% j5 Y! a3 ]
- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:1 t' M% u3 |" ~+ z# [+ m) O. J, m
- ) S; T: O/ e. o9 G! Z8 c1 }. h7 O
- 参数:& G% r+ t7 V+ r- h5 ]6 ]
- , m5 {4 j g3 K+ B
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。& u( O/ E8 ~) S: [6 J" P4 o
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。1 H5 }1 {, m- Y6 u' {
- load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。: u+ Q8 w8 |, a5 m3 q+ u# f( B: |
- 功能:6 I9 [: Z$ }. j; Z/ L# c0 H
7 }% Y, w) e* I- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
( J+ I$ C2 @% W8 ~5 c - 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
2 @+ x* w1 i: l - 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。( x% d- }. ~6 Z7 T ~: J
- 使用示例:
6 Y6 E0 \$ X/ @5 y" n/ u - 4 }/ P# C# U& ?" D2 G
- c/ G1 a4 e1 ~8 Q' o: C- u
- Copy code
5 I' B6 s- e+ r/ }# N' I - FT_Load_Char(face, 'A', FT_LOAD_RENDER);. D7 y5 E& p: d Z0 c8 v
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
( I* f) O# L4 l6 S* z# p. Z/ f; X - / |3 q: q* q5 o6 p n& [
- 错误处理:
_4 x2 Y7 C( u# e/ {$ F2 y
( u3 W& R0 Q4 L0 A- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。3 d9 E0 ~# N4 \9 B% j; F! q2 [% D
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码 : d5 W9 g3 w G
1 B! j+ u( d7 O" G
代码
. O7 E1 j# `) f, n8 ~ n7 n# H" S
* q" O& \8 e# w7 g0 p. i6 L, I- ' D; ]5 u- h' ^
1 u4 L) Y- Z5 D. |6 w6 k- #include <stdio.h>
" a" i6 Z" ?. Q! x5 x# S( A - #include <stdlib.h>
7 u: j9 P1 W$ d1 U* Q K) X - #include <GL/glew.h>9 j$ j, _0 v, q% `- \+ W
- #include <GLFW/glfw3.h>
( d$ w- T$ N1 T* Z- ^5 `$ K5 {0 e - #include <ft2build.h>! m/ p% C# `$ ~
- #include FT_FREETYPE_H
8 m4 @. l# l8 {. W' m% s# k9 Z
* Y+ p) K% v T& d, R- // 定义字形数据的字节数组
" J+ D+ e3 l. t0 o& M' g7 f# e - unsigned char fontData[] = {
1 g* I) u6 M; u+ ?. D5 e0 U! o4 U - // 字形数据的字节表示
) S' W+ E0 ?" `/ C# F - // 例如,这里可以包含字母、数字和符号的字形数据
( ^/ Y- b2 J( Y3 V: b, u+ Q - };0 N1 Y7 F: v7 }' {/ o
$ C$ S) i, ~. K5 `2 \- FT_Library library;8 k/ i+ V" y. ^' X9 N& O/ h. r
- FT_Face face;
, C" m# B0 [6 D* w6 w6 D& ` - GLuint fontTexture;
% o4 g. v: N4 O0 } - & _: o1 E/ t4 {' ?, l% R
- // 初始化FreeType库和OpenGL
5 ^8 b0 z3 _! m* S+ Z - void initialize() {
, R! d$ g; n' n$ G. ~ - if (FT_Init_FreeType(&library)) {
( Q8 e; W9 l6 \2 W3 a5 U0 s. G - fprintf(stderr, "Failed to initialize FreeType\n");! ]1 k9 }' h+ d- n- B, R
- exit(EXIT_FAILURE);
$ y' H5 {5 u( |% ?' I. { - }0 ^4 o6 s, b9 m9 }: c" G+ b# x4 o
8 E! O8 f# n" R9 t/ C- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
$ c7 H! |0 V& s$ P( | - fprintf(stderr, "Failed to create a FreeType font face\n");
" M( b$ E2 b9 |8 [ {0 X - exit(EXIT_FAILURE);
6 z3 R$ [9 S: n# i6 i - } j% U: h! n# H
: F4 Q$ h1 v% L0 S6 z( u- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小2 q8 M l3 N# P
- fprintf(stderr, "Failed to set font size\n");8 p, \( |* `. s& g F
- exit(EXIT_FAILURE);% D' X* j9 B2 y2 X" | P
- }, P7 `$ ~7 j( S+ d0 Z D
- ) c8 C; V! a8 O
- glGenTextures(1, &fontTexture);7 P; u; P, r- ] N5 O2 ^
- glBindTexture(GL_TEXTURE_2D, fontTexture);7 c$ j& P" t; p! m5 [) A, f
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);% ^8 m: U( K3 H5 V& N$ y
- 8 j3 K6 m2 e4 G/ }/ l) `
- // 将字形数据传递给OpenGL纹理1 E8 o* g( y. D( H) V
- for (int i = 0; i < 128; i++) {
% V1 k% N5 V& l, n - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {# s7 q- O; S* G+ |" g* \- K
- fprintf(stderr, "Failed to load glyph for character '%c'\n", i);+ S) j' S" Q: ^8 d
- continue;
/ m! |2 c- k$ I' r- m - }
+ d# Y/ S+ W3 t: }" T# ]+ o, k - ( a8 M+ L7 A/ G, Z; W
- glTexImage2D(. B" J! _0 y. ^2 @% N1 ]7 r) Y
- GL_TEXTURE_2D,% H- b& Q* p+ P* ?, T* ^$ i
- 0,- L" f) A9 c7 H1 a, E0 k
- GL_RED,7 k% ~+ b4 D E: I; w" G
- face->glyph->bitmap.width,+ \: {$ D8 @9 I$ A( F5 C( L
- face->glyph->bitmap.rows,
3 r* N' F. d" X; r: n - 0,0 [& | G+ y* l1 H. C# P
- GL_RED,
d8 K" v) A$ X k' J: X - GL_UNSIGNED_BYTE,8 p* j0 a" A* k$ B x0 M0 y, Y
- face->glyph->bitmap.buffer# n; c/ R7 T! t6 Q( D" M8 m9 n
- );
/ R9 f" V' V* t6 Y Q3 B$ K$ T* t - ( t1 ^6 ^0 d1 E9 d1 c s
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);, \3 {' k5 N7 E k0 b* `% F6 F
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
! }+ w) l0 H S8 O: p9 B - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);8 T# O- ~( r5 h5 a8 Q1 v
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);) _% @! a, j: H6 n9 T; v' T
- }8 a$ e8 G9 |6 O6 P
- }
* S; l! Y( O& [( [( J; {
! z$ n2 J( k4 ]- // 渲染字符串) `" N! P4 ?. z2 b
- void renderString(const char* text, float x, float y) {
- }0 S# |, P9 I' [! `0 H( q: R2 K - glBindTexture(GL_TEXTURE_2D, fontTexture);) t2 f5 K% y- Y# d; v) P3 i
- - @3 v( }8 A5 J% j* A N3 ?. N
- glEnable(GL_BLEND);
5 K+ e, I' k5 q( }, J - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);2 i! g: l/ D; f! Y8 W* |$ t
- 1 p8 z* ?3 A$ {1 D* N7 W, A
- glBegin(GL_QUADS);
: J V) O& b6 R# F3 r. a0 p! N - for (const char* p = text; *p; p++) {& A5 K( E4 k- B3 m+ s% @: r% B
- FT_Load_Char(face, *p, FT_LOAD_RENDER);
4 T: y& w: a! S4 ~* q8 c. q
" a/ D& w* ^8 Z" \, i: I- glTexImage2D(8 i+ w4 g& M5 |# w. v( p$ R/ @
- GL_TEXTURE_2D,
+ V: T7 p1 t: c: G/ X- \ - 0,
6 Y( W1 X0 x2 s - GL_RED,
! D& ~ p+ f2 h1 c. g$ H - face->glyph->bitmap.width,
) U0 }7 G) k5 d8 I3 w( w - face->glyph->bitmap.rows,/ j; @4 y1 q- H; ]' A0 d
- 0,% L" W& \" F" l2 C5 v. [1 D
- GL_RED,5 b- z, f: C3 [9 C9 h) S
- GL_UNSIGNED_BYTE,5 l" T. E4 V' B) H
- face->glyph->bitmap.buffer
) ^9 q0 o2 [8 X; y - );& Y5 I: h) t4 ^3 Q) [
) c; p! e9 `3 r3 k3 v5 M- float xpos = x + face->glyph->bitmap_left;
0 N: U! L1 M# I/ f - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
& ?7 \* ?' P) v1 ~* u. q+ S
/ l! y+ v' w" J% L- float w = face->glyph->bitmap.width;7 _# U( M1 x4 J, o! ^% f
- float h = face->glyph->bitmap.rows;
4 f" F3 N5 L# ?- W; v1 F& T
- d2 `/ W/ d" `: ^- glTexCoord2f(0, 0);
3 P* ]& k8 J4 T7 ? - glVertex2f(xpos, ypos);
% g- z$ P3 ^3 l% }7 j; M' D/ E - + A5 w. x# [7 f& F# C
- glTexCoord2f(0, 1);
l2 G, ]" A9 j - glVertex2f(xpos, ypos + h);
* Z. j, H; B6 v7 p
/ f" N4 o* ~6 q* P2 E! E* g- glTexCoord2f(1, 1);$ D% `, V3 X( g* }; ?* p2 g( R& ?
- glVertex2f(xpos + w, ypos + h);
; |9 u, y0 H' ~6 c - ( Z5 E( c! x! r' o$ S* x$ K. x
- glTexCoord2f(1, 0);) w. ?4 ]/ N. B- P- C
- glVertex2f(xpos + w, ypos);6 X9 C4 n( @* ?0 N
$ c' N! m7 [, {. R- D x- x += (face->glyph->advance.x >> 6); // 字符之间的间距: U$ h& ? r# `' w! c4 i
- }0 V0 @3 ?5 d! M+ j9 W
- glEnd();
# W4 c) M1 |( }4 E) d$ r! M
3 u5 c" T8 H" A' H6 `3 d4 S- glDisable(GL_BLEND);+ Q# |0 t! ~$ O7 R9 e% I/ b6 u
- }
" Y7 e4 [4 E) M7 R$ F& w: ?" s - , ~1 m. q. M% N
- int main() {
& x9 [! @8 C4 q9 |' E - if (!glfwInit()) {' S; v4 p# l* v
- fprintf(stderr, "Failed to initialize GLFW\n");
$ P6 n, O- ~$ d! y - return -1;2 g8 P1 u5 C9 {9 E
- }
- B- C& A4 S' k$ h5 _4 Y
3 E5 D- _7 s6 w- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);, L) M7 h! w5 \4 `4 e( t1 F& C
- if (!window) {0 e4 {! o+ J! w6 p
- fprintf(stderr, "Failed to create GLFW window\n");
0 n7 v1 ?; q, I8 Q" M# n - glfwTerminate();
" x( W. d0 t( G - return -1; h N4 k! D1 ]- `' \, C
- }
3 f- f8 k/ g. ?2 {7 m - * P( A; [8 Z1 c9 z ]
- glfwMakeContextCurrent(window);
7 |, r1 L4 N. \2 K5 V - glewInit();
# N" t6 S4 O" [
8 y' x1 c. j5 v- initialize();
2 h- D8 T( a- y9 |5 Q
( P: L! p* I3 ` j7 F' H- R- while (!glfwWindowShouldClose(window)) {
# T. }$ [2 e4 X/ S2 Q - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
' _: I2 B0 I/ F) X4 U5 j* A - glClear(GL_COLOR_BUFFER_BIT);
6 e4 I+ H8 F; Q& R9 q; W8 z - 6 q4 N% `3 b8 A/ _
- glColor3f(1.0f, 1.0f, 1.0f);* `5 E+ `8 I+ y9 N! g& S$ y
- renderString("Hello, OpenGL!", 100.0f, 100.0f);4 i2 O7 t& g! t! p/ @/ R
. B. m$ m5 P4 B4 K- glfwSwapBuffers(window);
$ e$ d1 F( G! {9 U0 M - glfwPollEvents();
/ S4 G0 x, j B0 z - }
+ ]* v3 [0 C; n: m9 x7 g
8 N8 ~" T, B9 G- FT_Done_Face(face);4 U1 q# x3 A# X7 J4 ]+ Z7 x& J
- FT_Done_FreeType(library);
. R3 ?0 T& M# i/ u) ~5 j q - % |- b# v" L# n& |: Q
- glfwTerminate();. H) \& u* {/ h; H8 [% }
' l# g+ l( k1 y* F4 S- return 0;6 ^$ \! C1 X' E" [5 B
- }
; }* K; X J7 x6 ]! N
复制代码
7 J! a' w6 W/ v7 L. H- J8 |) e5 N) Q# x' u4 N
|