冒险解谜游戏中文网 ChinaAVG
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数修改2
[打印本页]
作者:
shane007
时间:
2023-9-6 15:25
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数修改2
本帖最后由 shane007 于 2023-9-6 15:32 编辑
5 E& @2 I' l, Q$ g- D3 ?
; l, o; ~6 j, [8 o
以下是一个用来做参照的opengl显示字符串的代码,使用了freetype库。
* ~( a u: N W7 S5 r3 d9 i0 o
本代码经过分析以及改写之后,将取代游戏原有的显示函数。
( u3 n( e0 X/ j( G
5 K) Z8 z. C1 }
代码详细说明如下
& T g1 E( O+ p% o% S
# z+ m! G7 n3 Y4 M* Z3 P
在上述 renderString 函数中,我们有以下关键部分的解释:
. E9 K* \: R" ]9 l& h
) t A Y6 s5 p/ i
glBindTexture(GL_TEXTURE_2D, fontTexture);:将字体纹理绑定到当前的OpenGL上下文。这是因为我们要使用 fontTexture 中存储的字形位图数据进行渲染。
( R: G& w# {: W9 E; [1 M
( ?2 p6 Q7 J4 b d6 B7 i
glEnable(GL_BLEND); 和 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);:启用混合模式以处理字符的透明度。混合模式通过 glBlendFunc 设置,这里使用了常见的源和目标因子来实现源颜色与目标颜色的混合,从而实现透明效果。
7 m% h: ~/ d" E# V
( N J0 I* F0 E: d4 R
glBegin(GL_QUADS); 和 glEnd();:在这两个函数之间的代码用于指定字符的四边形顶点,以便在OpenGL上下文中绘制字符。
& }, k& w! p- o. @. z0 W9 w
" a0 y. v$ ~: \; c6 L7 t" E3 e
for (const char* p = text; *p; p++) { ... }:这个循环遍历传递给函数的字符串 text 中的每个字符,然后为每个字符执行以下操作:
2 [" @7 N: W0 }: s V+ T$ F
( r9 m N0 W, ^$ N! b6 Z
FT_Load_Char(face, *p, FT_LOAD_RENDER);:使用FreeType加载字符的字形数据,包括轮廓和位图信息。加载后,可以从 face->glyph 中访问该字符的字形数据。
8 u# A) \0 Y" p
- H2 E7 ^8 B# w
计算字符在屏幕上的位置和大小,包括 xpos(x坐标)、ypos(y坐标)、w(宽度)和 h(高度)。
# Y: u) X' |9 A3 V
( p. z" x# C, b( y- ?
使用 glTexCoord2f 和 glVertex2f 来指定字符的纹理坐标和顶点坐标,以创建一个四边形。这四边形将字形的位图数据绘制到屏幕上的指定位置。
; s2 v& [9 d+ N0 U& V4 M
' y; V/ `' A0 ?. }2 e
x += (face->glyph->advance.x >> 6);:更新 x 坐标,以便将下一个字符紧密排列在当前字符的后面。face->glyph->advance.x 包含字符的横向位移信息,>> 6 是用来将其转换为像素单位的操作。
* B3 j3 g9 A# @$ c4 k! i
& a7 x( \* {0 |" d) ~- L
最后,glDisable(GL_BLEND); 用于禁用混合模式,以免影响后续的绘制操作。
( s7 _7 {* ]% V
% d O7 _( U( t, ]
总之,renderString 函数的作用是将传递给它的字符串中的字符一个接一个地绘制到OpenGL上下文中,使用FreeType加载的字形数据和字体纹理来实现文本渲染效果。渲染过程涉及到字符的位置计算、纹理坐标的设置以及混合模式的启用和禁用,以确保字符在屏幕上正确显示。
) Y: p" [1 t$ A- a) P1 Y3 h7 R
复制代码
+ z+ d9 n+ X2 s
2 O# T! P7 e( S. \; H" G9 ^4 ?% T9 w
字形数据处理的关键函数之一。以下是 FT_Load_Char 函数的详细解释:
# h' e0 {2 i3 P# _" @
e* M; f+ V1 a
参数:
/ t' v- b; Z+ L+ W% K$ B, I% \
" c/ A/ Y) e# ^9 T2 |: N' u5 H1 x
face:一个指向已经打开的字体文件的 FT_Face 结构体的指针。FT_Face 包含了字体的各种信息,包括字形数据。
& H- Y! r3 j" B$ _
char_code:要加载的字符的Unicode编码值。您需要传递字符的Unicode编码作为此参数,以指定要加载的字符。
0 k2 b7 X$ e4 m" ? J
load_flags:一个用于控制字形加载选项的标志位。您可以使用这些标志位来控制加载的方式,例如是否要加载字形的轮廓数据、是否要加载字形的位图数据等。
! ?2 | x3 T0 B1 x" E% F
功能:
* J. D5 e5 P6 w# Q2 J' b i
4 R9 p- C o' ~9 W. c' R
FT_Load_Char 函数的主要功能是加载指定字符的字形数据。
% b$ z# A3 C5 z7 K/ ]$ ~2 b
如果成功,它将在 FT_Face 结构体中的 glyph 字段中填充有关字符的字形信息。
7 O2 Z, `9 q" G! ^+ f8 T; A
这包括了字符的轮廓数据、位图数据、宽度、高度、位图偏移等等,具体取决于传递给 load_flags 参数的设置。
; U# c( c4 J1 q
使用示例:
6 e4 t& Q* g- ?1 d) E# v
; M0 U+ g2 r# Y+ \$ M0 m, n+ J
c
5 d4 x- V* ^# J1 z
Copy code
, B, @3 G" k5 e* ^
FT_Load_Char(face, 'A', FT_LOAD_RENDER);
; X9 N' x! y+ M1 M$ E) a& T" B# C
这个示例会加载字体中字符 'A' 的字形数据,并将其渲染到位图中。FT_LOAD_RENDER 标志告诉FreeType要渲染字符的位图数据。加载后,您可以在 face->glyph 结构体中找到有关 'A' 字符的相关信息,包括位图数据、宽度、高度、位图偏移等等。
$ x. M! D9 B, q( {; }" g) f
' I% e$ L9 C8 S. k) @' z2 Y
错误处理:
. r- t+ J6 j! l! t- R
5 U4 m1 A0 ]* l1 |9 |1 h
如果加载失败,FT_Load_Char 函数可以返回错误代码。您应该检查返回值以进行错误处理,并根据需要采取适当的措施,例如跳过加载失败的字符或终止渲染过程。
6 n) F- s) }- R( b6 d, x
总之,FT_Load_Char 函数是FreeType库中用于加载指定字符的字形数据的重要功能之一,它使您能够准备要渲染的字符数据,以便在文本渲染中使用。加载的数据可以包括字符的轮廓信息(矢量数据)和位图信息,具体取决于 load_flags 参数的设置。这个函数在字体渲染中起到关键作用,以便将字符正确呈现在屏幕上。
复制代码
2 s: Q5 K: T, }* D3 y
& v+ R# i$ W) N# x( Z) I
代码
4 J) y( U; O4 G" J7 [4 ?4 K# j
6 R) D- ^5 q6 u* g$ d( E5 S% b
% d; H8 P: }4 P8 C5 [
- R! {" A1 ]) T. D$ a2 e9 y3 |; U; e' ~
' r' M! r8 g2 ~8 J2 A
#include <stdio.h>
6 \# O; n3 g& f d1 L
#include <stdlib.h>
+ h" y. q. e0 W1 M8 y& I
#include <GL/glew.h>
) p4 p9 f& p; o0 @9 a$ K. v
#include <GLFW/glfw3.h>
( F6 ?0 g- {- N) R- j! p, @3 r2 B
#include <ft2build.h>
3 h% E6 y }5 A
#include FT_FREETYPE_H
/ V o/ x! G* `2 Z9 S
, W2 r0 b" }$ {8 Y1 _- h- Y
// 定义字形数据的字节数组
4 |3 j8 y9 e2 {
unsigned char fontData[] = {
! D# u1 ^5 X# q! ?$ }( B# Z
// 字形数据的字节表示
( S# G9 T7 u5 k9 f: S
// 例如,这里可以包含字母、数字和符号的字形数据
) S% X$ B* O: K4 ~) B2 u( g
};
, T" s' L* T4 L/ K6 y% F
4 U" l( f& y, h k( o
FT_Library library;
' ? m% [8 c! }$ g* `
FT_Face face;
8 Q( J# |/ u d! C
GLuint fontTexture;
2 B, D6 r% ]5 {) K5 k: k* A c
7 s3 A" C: U( {7 | @" l
// 初始化FreeType库和OpenGL
+ a: {0 J) Y0 K3 T% X
void initialize() {
! ^' N8 V6 i$ \$ W$ R
if (FT_Init_FreeType(&library)) {
( V( a3 m' U9 F" U6 {8 F
fprintf(stderr, "Failed to initialize FreeType\n");
+ l8 `" V, U! R! K8 g2 W* V1 R7 C
exit(EXIT_FAILURE);
1 ^1 C) X" ?# e6 Y$ a8 ~- b0 s# A
}
+ f$ D" [: c! J& W) T" r
' f0 X+ X: x2 i# H( {0 ^ Q
if (FT_New_Memory_Face(library, fontData, sizeof(fontData), 0, &face)) {
! g( [7 X( u7 x
fprintf(stderr, "Failed to create a FreeType font face\n");
& X. N' \5 |! s& d: A: z, l8 Q
exit(EXIT_FAILURE);
7 r; r. Q9 A- K' o% @* @
}
9 s. `( z* G7 \8 s. b
8 z7 W/ G3 ~$ I9 a- p
if (FT_Set_Pixel_Sizes(face, 0, 48)) { // 设置字体大小
0 u: w' Q: V: E- v
fprintf(stderr, "Failed to set font size\n");
, M2 [' [! X' \8 t
exit(EXIT_FAILURE);
+ t$ _$ j; _0 y& A2 d8 Y
}
: Y3 a' L1 T: q- K' u8 }# F
0 F! x1 i8 _0 d# N
glGenTextures(1, &fontTexture);
! [# W: E6 w$ J1 q
glBindTexture(GL_TEXTURE_2D, fontTexture);
1 Q' b# B& W9 i* ?$ K3 ~. q
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
7 G+ f: w$ N- x) v9 N
4 E h" ^7 p y) X. H
// 将字形数据传递给OpenGL纹理
0 M, q- R) D3 O3 Y
for (int i = 0; i < 128; i++) {
( e7 o+ M K# f7 u# w) x
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
~, h# [+ d4 G: S6 M2 T
fprintf(stderr, "Failed to load glyph for character '%c'\n", i);
8 A0 p7 v7 _5 C# R: l2 l, V! i, n& x
continue;
1 s9 }5 k4 N# j3 A9 g6 y
}
* h/ z( q3 ?- M7 y" u) P
, X) U5 }( Y$ X& K7 h
glTexImage2D(
# z' g( i. l( k% y
GL_TEXTURE_2D,
, E5 \. P& O0 G% o6 y5 j
0,
& O: { k' H* `1 b
GL_RED,
9 I. J. e6 J* M+ ~2 ?7 p
face->glyph->bitmap.width,
7 n/ |4 S7 L$ @& X. o$ H- k" }; h
face->glyph->bitmap.rows,
4 Y& q6 p7 x: T# e" C+ O( m2 ?
0,
) u$ K' T0 k7 Z
GL_RED,
& w- {" [) J' D9 ?! ^& G
GL_UNSIGNED_BYTE,
' p+ S# d; C- S) C( h, R3 F2 X
face->glyph->bitmap.buffer
# b! x5 Q' `/ a, r3 y3 _8 D! L
);
% Y% K" `9 P. ^9 @! d6 S& w& [
% V( A- V2 `2 b* a4 O# g! e
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
9 a; x. n! F, d
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2 u# W- N4 W, ~; u, F3 x
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
$ W; O7 z1 C5 `3 ^! I' }; t7 z
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
' B! p6 x, n. }
}
5 R8 K/ m$ Q# C' L, ` ]% P
}
4 v+ f D, h6 L% R; u
I. {3 D8 F S, N" U# Y! A
// 渲染字符串
9 d5 b: A! L+ P1 y" S
void renderString(const char* text, float x, float y) {
* x$ i4 ~) U+ L, ~# [
glBindTexture(GL_TEXTURE_2D, fontTexture);
& x/ D8 I/ j4 Y9 e! O8 W, w
3 f8 s2 `; D+ [( t# p: z% w; y$ H' Y
glEnable(GL_BLEND);
1 t( b5 s' q& o6 r R W9 e
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
. g4 L! M& }3 v% `7 _
/ P# f% h0 B. }/ R3 p' ?; @' @
glBegin(GL_QUADS);
2 Q( E4 z4 ?; t( [$ _- Z
for (const char* p = text; *p; p++) {
8 J, m2 D8 a( T/ o) S1 W% }; d! x$ W
FT_Load_Char(face, *p, FT_LOAD_RENDER);
7 v9 }5 ?$ `. S$ @" I+ y4 @7 @) X
: m8 d( i: t) I: S2 y# E1 V
glTexImage2D(
" G6 a8 {( U$ J
GL_TEXTURE_2D,
: t( z, ^& s# m1 r& m4 z
0,
2 C) d0 c+ V; P$ ~
GL_RED,
7 X, M& n' M5 M) I
face->glyph->bitmap.width,
$ r' Z2 T/ J! F+ X
face->glyph->bitmap.rows,
y3 R. }" Y6 p: l# f
0,
. E U1 l. g3 r* J F: |* S/ G
GL_RED,
1 X/ S6 E" f [- p' K
GL_UNSIGNED_BYTE,
& v5 z/ ^ [8 ~7 C6 m8 [* a" n
face->glyph->bitmap.buffer
/ i" w# K3 ^0 C/ Z5 ^" K; U v
);
/ O! u9 g6 `. `* I! s4 [4 Y
; A N6 Y7 [ h% Y7 e1 D
float xpos = x + face->glyph->bitmap_left;
1 u: y' l7 B7 Q9 L+ Y4 ~8 ?
float ypos = y - (face->glyph->bitmap.rows - face->glyph->bitmap_top);
( i: A7 W& P9 b3 K5 ~7 O
0 n* t4 s( g1 T0 x9 ^
float w = face->glyph->bitmap.width;
- `" ?% |3 v, R- @) H& _
float h = face->glyph->bitmap.rows;
1 h5 p. @' {0 i
; c- N6 Z! N: R% z
glTexCoord2f(0, 0);
9 _+ Y9 F) P5 R% H9 s
glVertex2f(xpos, ypos);
- p0 F- }% S9 z- i; ~) }
. C5 P; N( K2 |9 a5 Z! X
glTexCoord2f(0, 1);
8 ?+ ]& f1 L* [9 U! {8 x3 R
glVertex2f(xpos, ypos + h);
( p, @) N j; z8 ^9 g$ t
1 a5 @3 {+ ?5 s) C" W% u+ z' V& t
glTexCoord2f(1, 1);
" O' x r% o5 d7 O
glVertex2f(xpos + w, ypos + h);
9 ~/ k0 \! e, l& j& s( ]
3 A3 V' N, q. H0 m
glTexCoord2f(1, 0);
, q8 W/ [. {7 e) u1 [- o8 m e
glVertex2f(xpos + w, ypos);
- k3 |. D+ ?6 j' ~+ ?" _ b: P
4 S& k r ]8 F: a
x += (face->glyph->advance.x >> 6); // 字符之间的间距
* T" k+ t, R8 ^4 z } ~
}
# e1 A# Q! P# Q1 Y
glEnd();
G% k) R5 H5 U2 u9 O$ V
@: p+ I- A9 Y
glDisable(GL_BLEND);
: ~. J: N: N4 }0 C
}
6 y) H D. X: f+ S7 \: E. i
) k" O& [/ E- H5 I3 G8 N7 T& z
int main() {
8 }7 @1 L7 _; W
if (!glfwInit()) {
8 e5 X" q7 Y% j) g; T
fprintf(stderr, "Failed to initialize GLFW\n");
( y0 N9 }: O8 Z7 n% | t$ K
return -1;
+ G4 o$ D n% H1 u0 l% ?
}
6 P, ?+ J8 B+ W
. B0 m! f4 Y6 v+ p8 W
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Text Rendering", NULL, NULL);
% \9 l6 v! Q5 f/ [0 H4 i
if (!window) {
( \6 h- @' M3 \, {5 }4 M d
fprintf(stderr, "Failed to create GLFW window\n");
! {/ w2 O: w6 J$ l$ x- _6 M& e; ?
glfwTerminate();
' k9 z) _0 K' d5 E6 ?- O( ?
return -1;
2 m9 I% {! e8 e3 s- ~2 N
}
|. \1 ?7 O" J- @
. V4 d9 h: {* }; H, ~( B* @0 w4 W
glfwMakeContextCurrent(window);
/ l. p2 {" y V! h/ K
glewInit();
- R1 j$ }8 Q; b6 ]! O0 n
3 J T5 `- j; d ?' u+ W7 M2 ?
initialize();
$ @1 R& J! H, R, I0 o
3 Y( j, P6 J1 L; a
while (!glfwWindowShouldClose(window)) {
4 ]( g- G! V+ y2 X6 n
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/ i( d2 A) O# E% |' @
glClear(GL_COLOR_BUFFER_BIT);
5 m" {, P5 Y5 u& w
2 {4 U2 L7 F0 s+ t! N2 q( K
glColor3f(1.0f, 1.0f, 1.0f);
0 t, g; G; _: L6 g
renderString("Hello, OpenGL!", 100.0f, 100.0f);
, w; ~4 X8 x& t, h2 M9 q1 R( ]8 {
" |& P+ {- y6 i' Y6 S4 X# n& p
glfwSwapBuffers(window);
. @' m' N6 H( g3 ]# h a
glfwPollEvents();
8 X- Q$ ?, W1 Z. S, a
}
0 J: f7 R8 U9 d) c; }2 H
+ d, P" K- W2 _5 d9 d* a
FT_Done_Face(face);
7 M. \2 w D0 q* I& D1 Y
FT_Done_FreeType(library);
+ ^5 |, O v3 s- z$ ~& E' c* ?
) M C! Y( e8 Q
glfwTerminate();
/ h( q( a. Q5 y4 c
: {# z8 h8 y2 Z4 I4 U- h2 ~5 b
return 0;
& q" S9 l% p( x2 v( a2 I* Z5 }
}
9 {: U! e; x8 i0 g
复制代码
3 N3 G) @. g2 m/ q
0 G5 C9 H" Q+ V, x
欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/)
Powered by Discuz! X3.2