冒险解谜游戏中文网 ChinaAVG
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数
[打印本页]
作者:
shane007
时间:
2023-8-27 13:49
标题:
【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数
本帖最后由 shane007 于 2023-9-5 16:49 编辑
) A3 f9 n& W+ H# m
; M: w; h! m1 b
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
& o) ]0 C" H, F: I: U& z p
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
. @5 ?9 T/ {/ x$ w* j7 I( v; W* B
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
2 V1 f% _7 D: C2 M
第1处
. u* v- c5 s/ [- e2 P! m) O. D/ l
void sub_451474(char *a1, ...)
/ B3 i' g, Y+ y# A8 U+ G W1 N
{
/ O+ }+ S0 K+ |$ d) y
GLsizei v1; // eax
: x' w' u- Q( v' @! P
char lists; // [esp+4h] [ebp-800h]
) E+ N- j a: ^# H3 q+ c0 U$ @1 D
va_list va; // [esp+810h] [ebp+Ch]
7 |8 Q% C. G$ A' D4 m& V$ H
" I! z& E) f% Z9 s4 e: x S/ g
va_start(va, a1);
, r& ~8 ?5 `, l
if ( a1 )
, n3 w. ] X5 S( x% a3 E
{
$ u1 ?: v1 _( B. \0 T
vsprintf(&lists, a1, va);
4 X+ G0 N) N Q4 B/ \
glPushAttrib(0x20000u);
' `, @0 ?) ?3 ]$ a2 r
glListBase(base);
& W! z* ^& D0 _* N$ V* `6 G
v1 = strlen(&lists);
" W% D* {; j4 r' d! h) R% H8 h l
glCallLists(v1, 0x1401u, &lists);
+ K! m2 n/ ~& \( Z0 s; I" @4 r- j
glPopAttrib();
9 {( K/ y: M3 I
}
f: O2 s3 i1 o. E8 i0 b
}
复制代码
0 ]4 `+ b8 a6 C" L1 `- t
& n1 J) i- u% M; z& Q
0 C% T* @; @: b& w7 N/ M1 b
第2处
; m% C& Z0 G' n4 L+ f3 P# _8 _
void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
! @$ K$ P2 b ?
{
% |8 P# c+ }- G6 i% g! F
int v4; // eax
& f1 j6 ~, y3 }) F) T1 o% t
GLsizei v5; // eax
& M( Y$ U u$ G' O
char lists; // [esp+4h] [ebp-800h]
& k! F7 b, D/ V3 o% [
va_list va; // [esp+81Ch] [ebp+18h]
, c* s& y* a2 Y; [
4 u# a( S3 d3 }) N, i* W8 P; a
va_start(va, a4);
0 z4 a) p" o; M3 U6 {, f e
if ( a4 )
+ V# n( c& d9 Q& Q
{
# k ?% I; V% l7 g- y& q; `
sub_44F8A0(a3);
' _% I* ^# O( K- x
v4 = sub_40BB44();
/ ?( u' U, O" l1 e
glRasterPos2i(x, v4 - a2);
4 k+ C8 N/ a$ ?4 }$ w% I* N
vsprintf(&lists, a4, va);
- C) i: _- R: a* ^
glPushAttrib(0x20000u);
1 S' `; @% h: X
glListBase(base);
/ g A; _( T8 L8 a
v5 = strlen(&lists);
! H0 m4 L) E. f
glCallLists(v5, 0x1401u, &lists);
I4 r2 v2 Z# ~* I
glPopAttrib();
0 g5 S+ B* r0 R
}
$ q: E5 l; P. U3 b5 I
}
复制代码
) @5 B9 Q& W# p- p/ g* T
+ f! R# x) A2 T8 e
2 J" T, \* K) H; Q+ B* Z
第3处
% c! I( S2 s8 c+ p. I4 z
, l% F5 }* G9 @+ E, H( ]3 I( j
void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
$ Z# m% w, w/ a* ^0 }) w: p7 f
{
. z* Q9 q- J4 i, w, W' P+ A
GLvoid *v7; // ST08_4
0 e! P" S! p- S1 x I7 D5 A
GLsizei v8; // eax
2 X9 X: _& w2 f# x; K; c# R# n
int v9; // [esp+0h] [ebp-1018h]
! {& C& K; f5 [2 o! P
char v10; // [esp+8h] [ebp-1010h]
$ P6 `% x6 f+ \2 Q- @9 R% I' }# `/ C
GLvoid *lists; // [esp+100Ch] [ebp-Ch]
]) q7 \$ k7 z! q
char v12[5]; // [esp+1013h] [ebp-5h]
* G6 _. q) i: y5 X1 o
va_list va; // [esp+103Ch] [ebp+24h]
7 E" c- Y( s# {3 m' N9 n. d
2 n3 X. i+ ^* R5 a% O* W3 h% y0 G
va_start(va, a7);
4 |& G" f- B+ p6 K' g
v9 = 1;
! ^4 i0 y! p7 J5 Z m8 {
if ( a7 )
# q; N: n( H) q: Z5 f8 Q- @
{
; h% a' s& O: X
vsprintf(&v10, a7, va);
" T% K8 f4 P7 |5 M
glPushAttrib(0x20000u);
4 J5 x! I/ P$ J% r5 J
glListBase(base);
) y/ \; _1 A3 m4 p& R
lists = &v10;
( `) {1 Q) Q. q1 ?9 c) k# p
do
0 Z' Z5 h5 ?' T8 ?# [, O
{
/ i. A B# e& p( c( K$ f
*(_DWORD *)&v12[1] = lists;
& n+ t. i: B; o y! h8 O1 G
while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
9 H1 @/ e+ A, [. K( i0 G* N' I R
++*(_DWORD *)&v12[1];
2 W( {9 G' x1 c2 h1 x
v12[0] = **(_BYTE **)&v12[1];
- U+ Z) @; \0 L3 q) l/ p
**(_BYTE **)&v12[1] = 0;
1 j; M- y8 a D: @" Y% U1 m
if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
+ v0 @! }$ ~$ v/ F: ?
*(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
! b4 u* M( a7 h% ?8 G/ Q" s; B# m
y -= a5;
) ~( p! j$ u9 B$ {. U1 n2 X
glRasterPos2i(*(_DWORD *)a4 + a1, y);
. I) \; e8 ?! X% y& `. N! W Y% t
v7 = lists;
4 ^& r+ C2 I" { X% w
v8 = strlen((const char *)lists);
+ F5 ?" ~4 r8 l \
glCallLists(v8, 0x1401u, v7);
0 `& f& {3 L5 a' Z% r- f7 g
if ( v9 < a3 )
0 [3 r3 J4 C9 y( M
a4 += 4;
1 i& w1 A2 ~: z6 |/ Z! ]
++v9;
% G/ w* _# g) _. H( X* A
lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
8 w9 s( @1 M/ }+ p* D; S% ^' c
}
! h5 W2 j) @6 |" D. u% q
while ( v12[0] );
' v0 }2 p% D) U8 c( p w' C' t
glPopAttrib();
0 k+ L. v9 }0 }
}
. o+ M" I' o7 e7 y* ? c
}
5 ?5 J H; E" ]5 [! s& a; t
复制代码
# q, e2 K& Z% l: z
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
# i9 R5 `* r2 E" G# P
' F! B) h0 Q: Q4 {
.text:004512B1 52 push edx ; char *
" S8 O7 N; I9 y
.text:004512B2 8B 45 30 mov eax, [ebp+base]
! [) F4 }2 H8 o0 a
.text:004512B5 50 push eax ; base
) v0 G/ Q2 _% L6 A# f* s
.text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
: \* W6 k# p2 Y/ N l
.text:004512B9 51 push ecx ; int
' @* |' z' f9 Q# V# q7 w: b- _- G# d
.text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
\, y @5 M. f8 Z; o0 W; O
.text:004512BD 52 push edx ; int
2 K+ t. k0 i& g- C% z3 q: r
.text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
9 l# c! v9 g5 ^0 _7 \
.text:004512C1 50 push eax ; int
7 B8 O( V; B( f6 f$ }& k3 |
.text:004512C2 8B 4D 0C mov ecx, [ebp+y]
' e" z. y) \) a
.text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
& ^; p. _9 r. R+ J% v/ {# X
.text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
" A& I9 t4 K. j4 v7 X* C- y
.text:004512CB 51 push ecx ; y
, u: w3 ^, [5 ?* `9 c7 c) x& B
.text:004512CC 8B 55 08 mov edx, [ebp+x]
6 ^. m/ E, _0 ^
.text:004512CF 52 push edx ; int
2 L7 U+ ?% ^3 R# N, w E
.text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
; J1 i6 l! t2 t, ]
chatGPT整理过之后,如下
; W9 X% I/ ]3 h# D" f' q B
6 v0 M# Q+ A3 a" F+ z
void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
% ~' D6 }- t7 }8 q! Z1 a
{
: ^$ g5 w8 [3 T3 @
GLvoid *textData; // 存储字符数据的指针
" M" E8 Q+ Z+ h; g( C& f; y& N4 E
GLsizei textLength; // 字符数据的长度
, o* d' O: }0 E* p
int lineIndex; // 行索引
# `$ R8 A2 X5 }% g6 N5 D# l* H" S
char formattedText[5]; // 存储格式化后的字符数据
% @# t9 N' v) H* N! ~
GLvoid *currentLine; // 当前行的字符数据指针
5 o# b) X/ E6 B. _0 _2 t: y
char buffer[5]; // 字符数据缓冲区
' Q! e+ Q- T! v: K8 w
va_list args; // 变长参数列表
2 i/ P0 x& V8 y- v/ T
! v8 y5 b j. o/ n
va_start(args, text); // 初始化变长参数列表
2 r5 J0 c* i# e
lineIndex = 1; // 初始化行索引为1
! }% c3 f) a& Z# {
/ V- x2 E' `, P7 x$ e
if (text) // 如果文本不为空
! T3 S; W4 J' X6 r; Z# U, O/ L1 M
{
, x4 E( ^+ f- I4 t% V
vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
( w) J% J& Z) K1 e* ]7 Z. e
glPushAttrib(0x20000u); // 推送OpenGL属性状态
! H: o( Z2 L2 c( T F4 `) d
glListBase(displayListBase); // 设置显示列表的基础值
: C4 U7 @, e5 g2 A0 [" S9 W- {
currentLine = formattedText; // 将currentLine指向formattedText的内存位置
9 F7 D, J0 U1 ~
0 X$ b4 U. O6 {2 W
do
; y0 V! \; f, Y. p# Y0 ~& O
{
5 @: h9 A+ k$ W
*(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
. L1 _+ E% a% \$ c. J. h* M
2 U7 p J/ ?9 n
while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
3 z; P8 [: ]0 Y# @
++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
6 t. G r0 t9 ?+ ?
( S: l: j+ a# ?" R1 d& f
buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
, G' v ^7 p# ~& i; a8 g8 |0 w
**(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
8 X% N- b+ W3 Q. v4 j
7 D' s0 c# P: a
if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
q& _* G; E t& k8 Q* R
*(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
4 j9 E$ u3 W8 I* r4 u0 m4 ]
6 S" v- \% ]8 F" |
yOffset -= lineHeight; // 更新y坐标
6 T8 T! @% t) T+ J% h+ X5 ] r4 O
glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
/ F) i! H; a( U8 G5 q+ t
textData = currentLine; // 将textData指向currentLine
/ y/ B' f$ h q, X. L3 E1 I
textLength = strlen((const char *)textData); // 计算字符数据的长度
; a; G( e" ?' l4 G( Y
glCallLists(textLength, 0x1401u, textData); // 调用显示列表
$ u; X. W4 b1 N( K
5 ]6 n9 v) a _' C/ V7 p
if (lineIndex < numLines)
) H2 |0 l2 B& | v
lineOffset += 4; // 更新lineOffset
. L* o2 Q; v( C
++lineIndex; // 递增行索引
4 [" t0 q" d, E7 K
currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
) E) c6 H* Z- B; I5 l/ ]5 F5 v
}
& W+ D* r. w! y! ^4 ~
while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
& p9 T) l. e( `* f0 u1 U% _
glPopAttrib(); // 恢复OpenGL属性状态
' A# H1 q1 w) P6 h* W+ A" e
}
1 ~ R! X n- F! N4 H
}
5 B4 z J6 h% N) L5 H% J
复制代码
) M/ I; g% g* g, B& c
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
% P8 e# j1 g( Z; q7 m& [
; p- N0 x; S+ c* R u0 l
int xOffset, 字幕的x坐标
3 M$ a$ K% Y8 ^ {+ X* y- D
GLint yOffset, 字幕的y坐标
- K6 V. T3 W3 A% y' N
int numLines, 字幕的行数(较长的字幕为2,一般为1)
3 p9 U Y( b U- a
int lineOffset, 这个需要再研究
' e6 B% b2 W8 Q- u( E
int lineHeight, 字体高度(或行高)
% W' r, A5 A" g2 b: c+ G
GLuint displayListBase, 这个字体对应的base值
3 c. a3 e! h, E4 X% o1 P6 ?
char *text, ... 字符串
8 l! e' g+ M G( `# t: q
" a" ~) v- c) x# C3 q9 o
作者:
shane007
时间:
2023-9-4 18:53
顶上来,顶上来
* j- I) ^- d5 J$ _
欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/)
Powered by Discuz! X3.2