冒险解谜游戏中文网 ChinaAVG
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数
[打印本页]
作者:
shane007
时间:
2023-8-27 13:49
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数
本帖最后由 shane007 于 2023-9-5 16:49 编辑
( t5 G+ [: ]. W* d$ F, E# w
1 m) E# f% z* V' x
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
+ j& K1 a8 y$ ~# z" k% Y
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
( P) g! @# S. A0 p& @ O
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
1 [8 ^3 G' C' D) H3 Q! X
第1处
* y; D/ {, @3 t+ z8 A* P' ~' P
void sub_451474(char *a1, ...)
- P* w7 J5 {8 ?0 p% ^9 d1 d
{
( S7 F( {1 U% W: t
GLsizei v1; // eax
, @+ v- a5 C3 R0 ] V* D1 V
char lists; // [esp+4h] [ebp-800h]
( ?8 a u/ i1 ?. @+ E F3 v0 }8 e
va_list va; // [esp+810h] [ebp+Ch]
6 o) k t# D G
6 y; `2 G0 W: h1 x+ M
va_start(va, a1);
, t; C" x6 i+ w2 A$ m4 v5 U# k9 D, |: z
if ( a1 )
6 M' @) H; b( U/ @
{
9 C8 M! C1 T9 i+ D$ \
vsprintf(&lists, a1, va);
+ U) s5 C r2 g/ g R
glPushAttrib(0x20000u);
* {- M# y- n( }" ^) \1 m
glListBase(base);
, c$ U# \" j- T4 F4 c6 ~+ h
v1 = strlen(&lists);
P0 H' }! W4 B7 n) s% S. y
glCallLists(v1, 0x1401u, &lists);
. Z$ Q8 b! H2 z/ C) n" p) x
glPopAttrib();
, x/ m: Y9 |. j' }5 }4 N, k2 z' L& b
}
$ _: f$ c& p$ p/ t+ w, |
}
复制代码
: }6 I' M" w* ~# C% v! Z3 @2 y
+ `- S' n2 @+ w
8 Y7 i. R: r- P3 z- W( o
第2处
z: N/ C9 a- t, f
void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
, u, W1 a" J6 m) ^; K
{
/ O7 n2 b; p m: Q. c
int v4; // eax
; e; c: V, \( }2 K7 P
GLsizei v5; // eax
! k9 o4 B# F- G0 o* t; f9 L$ C
char lists; // [esp+4h] [ebp-800h]
% o0 W3 P+ s, ]1 l% [/ y ]
va_list va; // [esp+81Ch] [ebp+18h]
* y1 ?" z9 ?3 G
7 [, B- j; |5 o( O4 R$ V, A5 {
va_start(va, a4);
+ d* R! _0 E4 H% d: c
if ( a4 )
$ v' a" n& a R7 f3 n
{
9 g. I% t* l) `
sub_44F8A0(a3);
% x. z+ Y$ M b0 c8 N. C( t
v4 = sub_40BB44();
3 |0 m- u6 W2 Z* w$ {
glRasterPos2i(x, v4 - a2);
4 A7 p; K* E" w8 M: G# c
vsprintf(&lists, a4, va);
6 D k5 A- n \$ F9 Q1 k U
glPushAttrib(0x20000u);
$ W! k( y7 O# \( W
glListBase(base);
6 C! N* ^/ X3 M1 K7 N
v5 = strlen(&lists);
, j0 u4 i g2 d0 s# z
glCallLists(v5, 0x1401u, &lists);
8 T" i+ b, C6 N# C& I! ~/ u& j1 L( @
glPopAttrib();
; E/ M3 D6 B. S6 \1 i+ \- y/ V0 s
}
0 `& W- ` k* z6 K% O8 T' [& p
}
复制代码
( H8 Q* ]" _8 h- c+ A% Z
+ Y/ q+ |1 f1 Z, r
+ r/ R" h! k# b M/ T- r% V" R! [! H
第3处
9 P6 f; V1 ?7 z! t- p
! ]: V U S: A6 ]; O. i7 r! l, N
void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
7 q: E9 {7 _: M0 c9 v
{
5 E3 C6 G% N( X2 T( l, n- l
GLvoid *v7; // ST08_4
$ K4 _+ u8 M: G# |+ c. K( s
GLsizei v8; // eax
% d, X* w Y7 \( C0 `0 Q8 Q
int v9; // [esp+0h] [ebp-1018h]
f, r) |! M! L. R4 x7 F6 o7 @
char v10; // [esp+8h] [ebp-1010h]
7 g& G) m4 I! s/ R
GLvoid *lists; // [esp+100Ch] [ebp-Ch]
5 y9 M( ^1 M* J* n* B
char v12[5]; // [esp+1013h] [ebp-5h]
3 Z0 e: T) ?( w! X4 }! B, U( |
va_list va; // [esp+103Ch] [ebp+24h]
: S0 W0 m$ k$ X. Q% Y; _
7 v& K% P# z' O7 O5 t5 s2 ^6 J" z2 x
va_start(va, a7);
|3 \ T1 w7 J
v9 = 1;
2 k; J- e, Q7 [; \+ Q$ j
if ( a7 )
7 T S+ c5 }2 j" c
{
( O2 F3 B; T5 U4 K0 I/ b$ D
vsprintf(&v10, a7, va);
0 p' T. }( g) [% }/ Y/ j
glPushAttrib(0x20000u);
9 G( f4 C, s* ?+ \( t- h7 m
glListBase(base);
3 g* `4 u3 V3 [2 ]
lists = &v10;
c: t$ z# L) t6 Y' j G
do
7 T( { ~0 W. l
{
' z( f+ Q) V$ A |- n* \
*(_DWORD *)&v12[1] = lists;
' v6 ^1 k. h7 K, S. E8 r& _7 v
while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
9 k( W: e; B8 L" M9 S
++*(_DWORD *)&v12[1];
, s7 M% W/ n/ O F
v12[0] = **(_BYTE **)&v12[1];
; A4 A3 y( I* k* E. [
**(_BYTE **)&v12[1] = 0;
$ F9 B: Y- a& N+ b
if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
# e8 C- q+ }4 ~" c8 |& b- a
*(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
3 s( g2 F% c5 [9 P
y -= a5;
1 p; J8 L5 {' [1 ?2 y- x6 f# b
glRasterPos2i(*(_DWORD *)a4 + a1, y);
% h8 R4 a$ q, |' V" u% a/ o: T
v7 = lists;
* ]: B0 F$ F, H+ _3 j2 |+ b$ p
v8 = strlen((const char *)lists);
2 @4 X/ g6 G. z0 K/ z8 a' R
glCallLists(v8, 0x1401u, v7);
~6 i: ?! P7 E6 o8 z
if ( v9 < a3 )
5 V+ ?! } `0 C- Q/ H( g
a4 += 4;
$ v1 H' z/ T6 e4 x. n
++v9;
! i& C3 J4 \0 V( b( d. W
lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
: m+ V% a4 T! S" z6 D) t0 O
}
0 d \ y+ O9 i0 M5 t! i
while ( v12[0] );
! s0 V5 [1 _- @+ g B- I
glPopAttrib();
3 C1 K, @) k J1 S; E
}
# J, w7 N0 T4 f4 d8 N
}
4 D5 W$ u* Y& M4 }* @4 }
复制代码
( p h' D3 }3 u+ m
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
! W0 c7 {, ?( p$ E4 k/ i
/ S+ h7 F/ s% G" k' j
.text:004512B1 52 push edx ; char *
2 e- l( S' c( |! v, H7 W* ^$ V
.text:004512B2 8B 45 30 mov eax, [ebp+base]
6 m K% ~/ ~6 j# s9 N
.text:004512B5 50 push eax ; base
" x. @1 Y3 E) p# m8 i) D/ i( L, U
.text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
% x/ s5 Y& Q4 T! R. }
.text:004512B9 51 push ecx ; int
, C8 e6 q1 a( o" I3 ^8 R+ V
.text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
5 ]2 b2 r* t' G2 Z
.text:004512BD 52 push edx ; int
3 F% p+ N" C# s& r1 f/ n+ Y& A1 _# _
.text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
# x( j1 y; y9 e" m( J, b
.text:004512C1 50 push eax ; int
2 `9 i! ]; ]' C; E9 y/ A# \
.text:004512C2 8B 4D 0C mov ecx, [ebp+y]
4 x- V! z+ q3 z0 Y, p P
.text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
% U3 g4 e# h: A- f6 c
.text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
+ k9 |" c5 o: n: e j: ^
.text:004512CB 51 push ecx ; y
8 _. K& e; M2 {4 A: Q! b
.text:004512CC 8B 55 08 mov edx, [ebp+x]
# R$ [( `. K6 C' R; u! L& N- V* y
.text:004512CF 52 push edx ; int
; X. w2 E) N) R' i" j% B+ S8 W) i
.text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
# b9 [0 X9 Z! h) k) C) ^& x! q, J& |8 J
chatGPT整理过之后,如下
: M$ u" o# G1 |& C4 n$ d2 |
: v0 C" g" q# w5 Z8 j2 s |/ e
void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
' z) d- S( }& F% {2 ~: _2 O; U4 i' W
{
( i3 i; e- J0 D3 O3 N- i4 I8 \4 t
GLvoid *textData; // 存储字符数据的指针
) { Q4 c. J) v( h: t# G
GLsizei textLength; // 字符数据的长度
$ ^% x' @1 J4 H( q$ i4 `3 F' v
int lineIndex; // 行索引
) R- J1 g( O! ~& p8 I* _* v# Z
char formattedText[5]; // 存储格式化后的字符数据
& Z% X1 Q$ B/ t+ `9 }
GLvoid *currentLine; // 当前行的字符数据指针
4 x; O; P& H* V& [
char buffer[5]; // 字符数据缓冲区
% m$ }& j3 A" V) U; H2 D7 c
va_list args; // 变长参数列表
4 c" H0 L1 x }1 `$ w- |9 Q' g4 Y
( v2 r" t) O2 m6 C
va_start(args, text); // 初始化变长参数列表
: a# O7 l: Z8 z# }
lineIndex = 1; // 初始化行索引为1
+ D( S f2 ~' ]1 Y
1 h0 f: O) V2 S3 F. t' c0 L3 D
if (text) // 如果文本不为空
3 @ r) [: f" R+ a$ |! N Q
{
0 M& Y# q1 \3 k$ \- K3 N2 E( g
vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
, X% s8 x6 p, D% G! I* L
glPushAttrib(0x20000u); // 推送OpenGL属性状态
- X% N7 G! a, ]; o; c
glListBase(displayListBase); // 设置显示列表的基础值
/ o4 A8 E0 x, j/ J2 Q1 _7 u! z; b
currentLine = formattedText; // 将currentLine指向formattedText的内存位置
: I% s1 \8 R" G' H$ B, @
0 D$ J8 U& Q( @8 v0 u* ]
do
9 d8 M4 [) M4 o! ]7 L( A6 r
{
% ~! s: ]/ W8 }1 P4 N, F- |
*(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
5 b+ K9 |8 r9 R$ W/ z( M$ h
) `& z- G+ \+ r$ K1 O$ \! n0 }
while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
# Q9 V3 m6 l& x% }# o: Z
++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
! J6 `/ o$ F% {
: F' x8 |# d+ X1 O O X
buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
* ]% ?# V$ N, M6 j) ~- {
**(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
! z/ _& N: ^/ P' I5 }2 Y, `
) i# A8 T3 K6 D7 u1 m
if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
7 A0 a2 H+ P) }
*(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
$ x- e. A0 m- y( b1 C
& r" E/ l0 Y+ {$ N1 A" B5 u0 x+ c9 b
yOffset -= lineHeight; // 更新y坐标
7 f8 T8 J, }$ P& u* |
glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
3 j/ O- c& n5 U
textData = currentLine; // 将textData指向currentLine
2 E6 V% G0 U) ?5 V% @5 [
textLength = strlen((const char *)textData); // 计算字符数据的长度
# C9 j* z. S" B# L n* |
glCallLists(textLength, 0x1401u, textData); // 调用显示列表
" O. P& [9 `8 q4 t& v3 c
9 I% z! | g& q8 f' I4 h1 u
if (lineIndex < numLines)
9 U' I+ P" f$ v! J3 R
lineOffset += 4; // 更新lineOffset
' @$ H5 T3 \ J
++lineIndex; // 递增行索引
, \" A S' k6 `1 T& k
currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
' j& ?3 d: p5 N5 Y( |5 ^- `/ o
}
, h; i$ [: }# @' F; w# f- e% X/ i0 z
while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
" D Y! |% A& _+ O
glPopAttrib(); // 恢复OpenGL属性状态
+ u4 I$ k. \& F) a# L
}
* m6 m- h5 h+ O
}
5 h1 a& o& O) n7 g8 l
复制代码
, y$ _* l# N9 G& A5 g/ U
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
+ M+ k9 C+ C- Z7 d+ J
- b. v& A7 @/ A& _' O
int xOffset, 字幕的x坐标
( `1 m8 A/ l1 d: c v
GLint yOffset, 字幕的y坐标
8 i0 a- L# r7 n- R& P
int numLines, 字幕的行数(较长的字幕为2,一般为1)
9 q0 Y1 r4 v" x0 W' J$ W
int lineOffset, 这个需要再研究
; n4 v6 S- h! ~# m/ |
int lineHeight, 字体高度(或行高)
: [# k: O- f N
GLuint displayListBase, 这个字体对应的base值
1 D% q/ S& Q) V. O7 f
char *text, ... 字符串
, \/ j3 U% e- r) |( u# U
3 ]5 [7 `, S' q1 i( ~+ U: H; G
作者:
shane007
时间:
2023-9-4 18:53
顶上来,顶上来
) h$ a. n; N' h) m: ~
欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/)
Powered by Discuz! X3.2