本帖最后由 shane007 于 2023-9-6 15:32 编辑
/ C4 H' z9 u' a$ E2 ~6 P0 {- o
O* F3 S2 U% f以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。6 ]' q) I7 d7 `, }& ?" b# Y
本代码经过分析以及改写之后,将取代游戏原有的显示函数。7 ^# b; H+ \3 N
$ o, ?5 z3 ]9 Q代码详细说明如下& I% C0 E/ \2 y$ V0 }* O
. E3 ?1 ]& w' U# A- 在上述 renderString 函数中,我们有以下关键部分的解释:
q5 d2 v5 K. @4 M$ o) M: @ - - Q" L q: {7 x8 ^- j
- glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
6 S$ X% p! o7 J4 W8 a" f5 a5 X - 3 T$ e- _. x! R. F8 E
- glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。$ T5 {& e4 o% t6 t
4 u2 B/ W( F/ C" B6 ^, I- X4 |3 J- glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。( g6 a" G! x7 x N
. O/ c" p) C {- for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:3 W- T/ n! m$ Y2 K; E/ q) z7 \& a
- + _5 r. e! [3 h8 ~4 v
- FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。0 B5 E7 {2 d1 b' J: O
! G. W# o0 u1 d8 K! d0 o- 计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
; {+ d: X6 e' A: ]: @3 I - , @3 e5 j6 U+ i, b2 S
- 使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。! N/ o# x- T/ H U; u
- : f! [# ?7 H" ~9 t
- x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。. {5 k1 D2 e! ^- t h/ j
' r; |# w n' T' e7 G* h9 y- 最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。/ \; }* M% x- e: ~( t# R: H* X" \
$ u+ J- ]3 }% B5 ~7 x- 总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
; K" G3 X. i0 Z2 b7 V' Y5 y, S/ R
复制代码
& k- ~- U3 u& M# q
9 P8 f9 o# v$ T# _+ `, j1 M* l- 字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:
& j: R/ c1 q4 _3 M - % \% L" E) [8 y
- 参数:
+ C( \1 s O" h9 Z3 Q( d - 2 W' t8 I# \5 m. |1 o# S
- face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。2 I% K" b1 X% v! \) f
- char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
( U9 V/ e( \8 W' @, P - load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。2 k# V" h) b% A( b( }7 E8 a+ T, r
- 功能:
% f- R2 l: m3 _: x5 L6 `
* T( N" E. t0 r3 m/ c- FT_Load_Char 函数的主要功能是加载指定字符的字形数据。9 k. f# i, M2 L% O! X; k" {. O4 `
- 如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。7 ?: H2 z5 c# D4 x9 [+ F: n
- 这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。# `1 w. [! x6 j% {( x& t, j1 D
- 使用示例:6 D, x' x& t2 t6 S9 s) I- s
- ' z ^) q$ N+ k& v
- c4 a! V3 ~$ r* h+ U' _9 n
- Copy code
% [" Z9 i+ A- N - FT_Load_Char(face, 'A', FT_LOAD_RENDER);- H& [5 P" `' R" Y$ k! o" ^
- 这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
# y; T; d7 ^0 z! j
. G; k8 i& T3 s& D3 c2 z6 v& c- 错误处理:
+ O$ g% j, [ j2 ]' u- o
7 s+ N% ]& m6 z& i# b! [- 如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。8 e# Z/ C0 t8 N7 [ q- T% F( ~
- 总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
0 d& s! M% J+ v! L+ `( o4 L3 |* q0 t9 ^; v& B6 o6 U
代码7 k" h8 z! }" Q
& B- }% f. K7 l& b$ F" N6 V
2 {+ p X; @1 X, F9 w- : V% w: X p1 l+ V+ M- j" h# h" k' A
" g# B) _ Z$ L; y& m- #include <stdio.h>
4 R+ o: H T8 C9 y/ F. Z - #include <stdlib.h>
- y& ]$ g3 V. V! {1 n - #include <GL/glew.h>
8 v$ Q8 f! [1 X" q" \3 a9 q - #include <GLFW/glfw3.h>
7 L6 x5 M8 W# @4 d4 B0 `% L* i - #include <ft2build.h>
^0 E4 L: g7 F5 H9 _8 f. d% N - #include FT_FREETYPE_H
4 h( N" @# h! H5 w/ }0 w - % I" d) ^* k* O0 I2 Z4 D, F
- // 定义字形数据的字节数组
( W2 v$ u* [; ] - unsigned char fontData[] = {! j% F) m8 N" P* R- o" E6 \
- // 字形数据的字节表示1 o& F4 s( p8 T9 e* q m. h3 m8 f
- // 例如,这里可以包含字母、数字和符号的字形数据
% Z5 w) t5 z. n - };. u& b1 f3 e, Q' w- \
0 A5 [1 q2 m; d% D- @0 P1 N- FT_Library library;$ K5 m, [4 a5 N! z5 q# S3 y
- FT_Face face;0 \% }2 N! h* \( @* \5 W! ]
- GLuint fontTexture;. ~0 z! s8 q5 {
" Z% J8 u4 h1 w4 `3 z- // 初始化FreeType库和OpenGL5 |$ F# b2 }( r y5 m/ ]( R( D
- void initialize() {
, k; ?! r7 R2 K( |/ H4 q3 F - if (FT_Init_FreeType(&library)) {
6 H4 z9 \ j- W9 `8 x7 A* X - fprintf(stderr, "Failed to initialize FreeType\n");/ c5 Q# ]6 A/ u# m0 M# L
- exit(EXIT_FAILURE);
% d7 d- w- X3 ^ - }4 j% J7 n/ K9 T; a3 U( g
- " _7 v7 \0 J: Q$ i# M4 p M8 i
- if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {/ j- ^$ A3 ]5 G: ^0 v
- fprintf(stderr, "Failed to create a FreeType font face\n");
H2 [& q# e* M7 W4 M: J - exit(EXIT_FAILURE);9 \" y6 O5 \/ [& s
- }
* x0 h- [: a1 o8 S( F: C1 \# l - V' }6 X" x/ ^" i
- if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
$ _0 p$ K. p1 ]) i/ _ - fprintf(stderr, "Failed to set font size\n");$ U5 q8 p" i( y6 M7 C& A1 w8 `
- exit(EXIT_FAILURE);& a4 r) W" g. ]& _" d$ |: I
- }0 O. q- _( Q |/ n O$ A: I
- $ A9 o6 P: Q! ^( p* ?2 y
- glGenTextures(1, &fontTexture);
$ u) y. r& A1 H# |1 _' N3 e - glBindTexture(GL_TEXTURE_2D, fontTexture);3 H/ @* V9 t1 r2 v; R/ U/ u; Z
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);" J, o3 n& U1 q- V ]: r
- * j; E0 r, Z! k2 r* M7 e
- // 将字形数据传递给OpenGL纹理
+ q- D7 f$ j6 \, x - for (int i = 0; i < 128; i++) {
& \* D# m! k6 Q8 @* z. X% T- p4 ~ - if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
' [: G* g% e3 a4 f - fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
7 K, D! X6 U( N0 q d/ m2 S - continue;
# ]' @$ L/ D4 p- h3 a8 Y - }
" u0 T2 Q$ `' y: T4 e" U - & _/ X9 W Z6 s4 P' b
- glTexImage2D( i$ ]) n5 j! N+ J4 Q B
- GL_TEXTURE_2D,5 [# g" O/ F3 D; F" G! }/ o
- 0,
; c- D: v9 D: {( V( m# a6 X - GL_RED,
, W o( T) w+ m5 U9 Z - face->glyph->bitmap.width,
% P0 z( k1 `' \. e$ B2 @& ]+ Z) {/ z - face->glyph->bitmap.rows,7 K4 ]$ ?- \; a7 K
- 0,4 i8 _, s# Q" L, A j, _
- GL_RED,
3 [ r+ Y! s' K) w; |; v! Y2 u; T - GL_UNSIGNED_BYTE,
. ^. V) G7 Z% A) p9 L - face->glyph->bitmap.buffer
" Z+ K, y: U9 B - );
$ Q2 z' s2 ~5 }! A) B; l- L( @
: C( ]9 E( _" a' S0 [& _- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
" [2 C ]* `8 Y( ^! H - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);' y/ O& A# k* v4 G
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);3 B( V0 M5 P3 V' h+ `, I
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3 ^* Z9 @& c6 U7 v0 d - }* ^' k5 m7 c6 G+ q( q, R- x
- }
2 A1 r0 j5 }, G4 n
8 E$ r4 ?8 Y" E: c- u1 g2 y- // 渲染字符串
" |' A: H/ W8 F7 I$ `% y' D5 k - void renderString(const char* text, float x, float y) {9 _! `+ q, h1 Z8 i$ v
- glBindTexture(GL_TEXTURE_2D, fontTexture);
$ g, I8 a; L+ p9 D) A# @5 [ - ( e# e; h+ \/ K
- glEnable(GL_BLEND);5 ^- O; T$ Z9 Q/ W2 s
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);% W2 T: x8 p+ m# r8 q" c6 q9 }
- , A; J% Q8 N- q; g' J' w5 d
- glBegin(GL_QUADS);" P" @0 Z, g5 R9 m, S9 D- c7 X9 o
- for (const char* p = text; *p; p++) {5 b6 x, [. E$ h
- FT_Load_Char(face, *p, FT_LOAD_RENDER);7 }4 U' R3 ~+ X+ G
- " f; k& l0 @6 y+ t, T6 N5 o. P$ _
- glTexImage2D(
. |. g V0 ^6 U0 @2 }" G - GL_TEXTURE_2D,3 m# ?/ `. Y: R: y6 v: A
- 0,/ }/ E6 k8 T( x
- GL_RED,' v# U* `1 _: I7 i' I( {/ v
- face->glyph->bitmap.width,/ G* V/ x) I, P2 N. E/ Z
- face->glyph->bitmap.rows,' X. ~' [1 C3 Z7 _; D
- 0, U+ _- X$ w- T' {# g. q
- GL_RED,$ O$ w0 q7 A3 g" D" l- Y" ]
- GL_UNSIGNED_BYTE,' x6 e7 B) L! `: |1 _
- face->glyph->bitmap.buffer
' f& n! f5 A9 o: } - );
) L D/ z/ ?9 x- b
2 a. [8 L: U9 H2 O' }1 F6 z$ T- float xpos = x + face->glyph->bitmap_left;
# X2 o6 O3 g" a- A* u - float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
; g# {( V+ O0 O
- ^& e( e0 n; h- float w = face->glyph->bitmap.width;
9 F' a/ m" q% J& N2 A' h' w - float h = face->glyph->bitmap.rows;& E' E) M% S3 L! e3 N
. Z) x5 _3 r# K/ k! u% J2 g- glTexCoord2f(0, 0);9 k: G9 N9 g. h/ x T
- glVertex2f(xpos, ypos);
2 r4 a; q" b5 G, ] U* w8 v- g5 x - 1 I% x8 `+ f$ [ @+ ^
- glTexCoord2f(0, 1);/ B( K" k) X/ `1 }& O; T# h
- glVertex2f(xpos, ypos + h);
5 z G+ h/ i$ y- N( n; ^4 W2 z - + n5 i) Y3 |% |- c7 }3 k% a
- glTexCoord2f(1, 1); i& Z! [" \9 E5 Z) W
- glVertex2f(xpos + w, ypos + h);
) ]8 U% s" R- A% s6 G4 @( R
. g" [' t! \) A; L' b) u- glTexCoord2f(1, 0);( V/ D) u9 x$ [! i$ \4 q
- glVertex2f(xpos + w, ypos);: L- l# w$ M$ m2 g" u
' u; L) r& r9 r, }9 c- x += (face->glyph->advance.x >> 6); // 字符之间的间距
! I; S: L% L' ?' K0 L6 q - }
, R+ o8 f! w) i, u0 K+ ^% x - glEnd();
: M1 O6 P0 R; a* y
v% Q/ n6 v6 J/ s# L0 [! O) \- glDisable(GL_BLEND);
; }) L, b0 [. X. a' u( F- M - }- r# b z* t; g
- ! C- M- m6 q- V* r( N
- int main() {
. Q' A, y2 C# t2 ]# X. \, _" N3 d - if (!glfwInit()) {# S8 U" H# H% ?& W4 r' H1 f
- fprintf(stderr, "Failed to initialize GLFW\n");
; z2 J3 T8 r- |% q0 o* M - return -1;
( ^% d+ h* p0 S* g& b1 ~* P3 ^ - }. x/ o" g! {! ~) J
. U! }/ @+ Q( C/ F- GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);/ @8 J, c1 n. w' W* }' |& L7 Q3 o
- if (!window) {
& H$ X% P, b+ O1 q _/ A6 j0 F - fprintf(stderr, "Failed to create GLFW window\n");: L! i) m0 `0 t, R8 y, ^
- glfwTerminate();
0 N$ k- [8 p' `- V& Q( X$ ~0 ~ - return -1;
, B% w# ~9 w- s: J - }
8 Y& e; P1 l5 o) ]
3 U- B% B3 [8 L; g# b) o- glfwMakeContextCurrent(window);& J' Q& e4 e, U7 I# k
- glewInit();
$ f* C. R8 n2 H9 b3 M+ A - & b0 v( }0 n4 c: ~* F" }1 k. S: m
- initialize();
) A! }/ Z+ ~+ Y- o0 |2 {: @
4 @( M" `1 r5 q7 Y4 X, _- while (!glfwWindowShouldClose(window)) {
4 V8 W, c5 P( P1 B" M! \2 e7 z - glClearColor(0.0f, 0.0f, 0.0f, 1.0f);, _# O: Y# o. W/ @
- glClear(GL_COLOR_BUFFER_BIT);4 _% n+ u: z& l( b& T! [
- ( K: L: k# ^5 ^- k
- glColor3f(1.0f, 1.0f, 1.0f);
' X" H$ b: u, p4 R - renderString("Hello, OpenGL!", 100.0f, 100.0f);$ X, e3 ]1 s0 Y* A
. T- v3 J. S1 f, ]; |1 f# ?6 Q- glfwSwapBuffers(window);" a6 S( B9 R: {$ z8 c6 f
- glfwPollEvents();/ ]. [/ e1 y9 D9 C8 a
- }" j$ Y4 B; X3 f) c; _; s4 v/ U4 [* E
- ' a0 m- ~+ j1 B- l8 S2 i, N2 n
- FT_Done_Face(face);, c+ I, s# {; B# v( m% W
- FT_Done_FreeType(library);
# k5 D6 o% G$ A" J; u6 E4 U
% Y) R% P2 Z; V- K% j$ |- glfwTerminate();
( I4 y* m2 f5 x, H8 u) |+ t: z - ' n8 y. b8 d w9 ^6 z9 {& z# P
- return 0;1 ^& Q# t3 K1 L( r
- }9 i- R! R& g: F) o, e/ Q; t* x
复制代码
3 S3 d3 e+ Y- q6 j+ R V
' [( z& P* R' `+ L$ G |