冒险解谜游戏中文网 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
  1. void sub_451474(char *a1, ...)- P* w7 J5 {8 ?0 p% ^9 d1 d
  2. {
    ( S7 F( {1 U% W: t
  3.   GLsizei v1; // eax, @+ v- a5 C3 R0 ]  V* D1 V
  4.   char lists; // [esp+4h] [ebp-800h]
    ( ?8 a  u/ i1 ?. @+ E  F3 v0 }8 e
  5.   va_list va; // [esp+810h] [ebp+Ch]6 o) k  t# D  G

  6. 6 y; `2 G0 W: h1 x+ M
  7.   va_start(va, a1);, t; C" x6 i+ w2 A$ m4 v5 U# k9 D, |: z
  8.   if ( a1 )
    6 M' @) H; b( U/ @
  9.   {9 C8 M! C1 T9 i+ D$ \
  10.     vsprintf(&lists, a1, va);
    + U) s5 C  r2 g/ g  R
  11.     glPushAttrib(0x20000u);* {- M# y- n( }" ^) \1 m
  12.     glListBase(base);
    , c$ U# \" j- T4 F4 c6 ~+ h
  13.     v1 = strlen(&lists);  P0 H' }! W4 B7 n) s% S. y
  14.     glCallLists(v1, 0x1401u, &lists);
    . Z$ Q8 b! H2 z/ C) n" p) x
  15.     glPopAttrib();
    , x/ m: Y9 |. j' }5 }4 N, k2 z' L& b
  16.   }
    $ _: f$ c& p$ p/ t+ w, |
  17. }
复制代码

: }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
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
    , u, W1 a" J6 m) ^; K
  2. {/ O7 n2 b; p  m: Q. c
  3.   int v4; // eax
    ; e; c: V, \( }2 K7 P
  4.   GLsizei v5; // eax
    ! k9 o4 B# F- G0 o* t; f9 L$ C
  5.   char lists; // [esp+4h] [ebp-800h]% o0 W3 P+ s, ]1 l% [/ y  ]
  6.   va_list va; // [esp+81Ch] [ebp+18h]
    * y1 ?" z9 ?3 G

  7. 7 [, B- j; |5 o( O4 R$ V, A5 {
  8.   va_start(va, a4);
    + d* R! _0 E4 H% d: c
  9.   if ( a4 )$ v' a" n& a  R7 f3 n
  10.   {9 g. I% t* l) `
  11.     sub_44F8A0(a3);% x. z+ Y$ M  b0 c8 N. C( t
  12.     v4 = sub_40BB44();3 |0 m- u6 W2 Z* w$ {
  13.     glRasterPos2i(x, v4 - a2);
    4 A7 p; K* E" w8 M: G# c
  14.     vsprintf(&lists, a4, va);
    6 D  k5 A- n  \$ F9 Q1 k  U
  15.     glPushAttrib(0x20000u);
    $ W! k( y7 O# \( W
  16.     glListBase(base);
    6 C! N* ^/ X3 M1 K7 N
  17.     v5 = strlen(&lists);
    , j0 u4 i  g2 d0 s# z
  18.     glCallLists(v5, 0x1401u, &lists);8 T" i+ b, C6 N# C& I! ~/ u& j1 L( @
  19.     glPopAttrib();; E/ M3 D6 B. S6 \1 i+ \- y/ V0 s
  20.   }
    0 `& W- `  k* z6 K% O8 T' [& p
  21. }
复制代码

( 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

  1. ! ]: V  U  S: A6 ]; O. i7 r! l, N
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
    7 q: E9 {7 _: M0 c9 v
  3. {5 E3 C6 G% N( X2 T( l, n- l
  4.   GLvoid *v7; // ST08_4$ K4 _+ u8 M: G# |+ c. K( s
  5.   GLsizei v8; // eax
    % d, X* w  Y7 \( C0 `0 Q8 Q
  6.   int v9; // [esp+0h] [ebp-1018h]  f, r) |! M! L. R4 x7 F6 o7 @
  7.   char v10; // [esp+8h] [ebp-1010h]7 g& G) m4 I! s/ R
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]
    5 y9 M( ^1 M* J* n* B
  9.   char v12[5]; // [esp+1013h] [ebp-5h]3 Z0 e: T) ?( w! X4 }! B, U( |
  10.   va_list va; // [esp+103Ch] [ebp+24h]
    : S0 W0 m$ k$ X. Q% Y; _

  11. 7 v& K% P# z' O7 O5 t5 s2 ^6 J" z2 x
  12.   va_start(va, a7);  |3 \  T1 w7 J
  13.   v9 = 1;2 k; J- e, Q7 [; \+ Q$ j
  14.   if ( a7 )7 T  S+ c5 }2 j" c
  15.   {
    ( O2 F3 B; T5 U4 K0 I/ b$ D
  16.     vsprintf(&v10, a7, va);
    0 p' T. }( g) [% }/ Y/ j
  17.     glPushAttrib(0x20000u);9 G( f4 C, s* ?+ \( t- h7 m
  18.     glListBase(base);3 g* `4 u3 V3 [2 ]
  19.     lists = &v10;  c: t$ z# L) t6 Y' j  G
  20.     do
    7 T( {  ~0 W. l
  21.     {
    ' z( f+ Q) V$ A  |- n* \
  22.       *(_DWORD *)&v12[1] = lists;
    ' v6 ^1 k. h7 K, S. E8 r& _7 v
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )9 k( W: e; B8 L" M9 S
  24.         ++*(_DWORD *)&v12[1];, s7 M% W/ n/ O  F
  25.       v12[0] = **(_BYTE **)&v12[1];
    ; A4 A3 y( I* k* E. [
  26.       **(_BYTE **)&v12[1] = 0;
    $ F9 B: Y- a& N+ b
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
    # e8 C- q+ }4 ~" c8 |& b- a
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
    3 s( g2 F% c5 [9 P
  29.       y -= a5;1 p; J8 L5 {' [1 ?2 y- x6 f# b
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);
    % h8 R4 a$ q, |' V" u% a/ o: T
  31.       v7 = lists;
    * ]: B0 F$ F, H+ _3 j2 |+ b$ p
  32.       v8 = strlen((const char *)lists);
    2 @4 X/ g6 G. z0 K/ z8 a' R
  33.       glCallLists(v8, 0x1401u, v7);  ~6 i: ?! P7 E6 o8 z
  34.       if ( v9 < a3 )5 V+ ?! }  `0 C- Q/ H( g
  35.         a4 += 4;
    $ v1 H' z/ T6 e4 x. n
  36.       ++v9;
    ! i& C3 J4 \0 V( b( d. W
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);: m+ V% a4 T! S" z6 D) t0 O
  38.     }
    0 d  \  y+ O9 i0 M5 t! i
  39.     while ( v12[0] );! s0 V5 [1 _- @+ g  B- I
  40.     glPopAttrib();
    3 C1 K, @) k  J1 S; E
  41.   }# J, w7 N0 T4 f4 d8 N
  42. }
    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
  1. .text:004512B1 52                                         push    edx             ; char *2 e- l( S' c( |! v, H7 W* ^$ V
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]6 m  K% ~/ ~6 j# s9 N
  3. .text:004512B5 50                                         push    eax             ; base" x. @1 Y3 E) p# m8 i) D/ i( L, U
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]% x/ s5 Y& Q4 T! R. }
  5. .text:004512B9 51                                         push    ecx             ; int, C8 e6 q1 a( o" I3 ^8 R+ V
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]5 ]2 b2 r* t' G2 Z
  7. .text:004512BD 52                                         push    edx             ; int3 F% p+ N" C# s& r1 f/ n+ Y& A1 _# _
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]# x( j1 y; y9 e" m( J, b
  9. .text:004512C1 50                                         push    eax             ; int2 `9 i! ]; ]' C; E9 y/ A# \
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]4 x- V! z+ q3 z0 Y, p  P
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]
    % U3 g4 e# h: A- f6 c
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C]+ k9 |" c5 o: n: e  j: ^
  13. .text:004512CB 51                                         push    ecx             ; y8 _. K& e; M2 {4 A: Q! b
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]
    # R$ [( `. K6 C' R; u! L& N- V* y
  15. .text:004512CF 52                                         push    edx             ; int; X. w2 E) N) R' i" j% B+ S8 W) i
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码

# b9 [0 X9 Z! h) k) C) ^& x! q, J& |8 JchatGPT整理过之后,如下: M$ u" o# G1 |& C4 n$ d2 |

: v0 C" g" q# w5 Z8 j2 s  |/ e
  1. 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
  2. {
    ( i3 i; e- J0 D3 O3 N- i4 I8 \4 t
  3.   GLvoid *textData;         // 存储字符数据的指针) {  Q4 c. J) v( h: t# G
  4.   GLsizei textLength;       // 字符数据的长度$ ^% x' @1 J4 H( q$ i4 `3 F' v
  5.   int lineIndex;            // 行索引
    ) R- J1 g( O! ~& p8 I* _* v# Z
  6.   char formattedText[5];    // 存储格式化后的字符数据& Z% X1 Q$ B/ t+ `9 }
  7.   GLvoid *currentLine;      // 当前行的字符数据指针
    4 x; O; P& H* V& [
  8.   char buffer[5];           // 字符数据缓冲区% m$ }& j3 A" V) U; H2 D7 c
  9.   va_list args;             // 变长参数列表4 c" H0 L1 x  }1 `$ w- |9 Q' g4 Y

  10. ( v2 r" t) O2 m6 C
  11.   va_start(args, text);     // 初始化变长参数列表: a# O7 l: Z8 z# }
  12.   lineIndex = 1;            // 初始化行索引为1+ D( S  f2 ~' ]1 Y

  13. 1 h0 f: O) V2 S3 F. t' c0 L3 D
  14.   if (text)                 // 如果文本不为空3 @  r) [: f" R+ a$ |! N  Q
  15.   {0 M& Y# q1 \3 k$ \- K3 N2 E( g
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
    , X% s8 x6 p, D% G! I* L
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态- X% N7 G! a, ]; o; c
  18.     glListBase(displayListBase);          // 设置显示列表的基础值
    / o4 A8 E0 x, j/ J2 Q1 _7 u! z; b
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置
    : I% s1 \8 R" G' H$ B, @
  20. 0 D$ J8 U& Q( @8 v0 u* ]
  21.     do
    9 d8 M4 [) M4 o! ]7 L( A6 r
  22.     {% ~! s: ]/ W8 }1 P4 N, F- |
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素
    5 b+ K9 |8 r9 R$ W/ z( M$ h
  24. ) `& z- G+ \+ r$ K1 O$ \! n0 }
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束# Q9 V3 m6 l& x% }# o: Z
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素! J6 `/ o$ F% {

  27. : F' x8 |# d+ X1 O  O  X
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素
    * ]% ?# V$ N, M6 j) ~- {
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符! z/ _& N: ^/ P' I5 }2 Y, `

  30. ) i# A8 T3 K6 D7 u1 m
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)7 A0 a2 H+ P) }
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符$ x- e. A0 m- y( b1 C
  33. & r" E/ l0 Y+ {$ N1 A" B5 u0 x+ c9 b
  34.       yOffset -= lineHeight;                // 更新y坐标
    7 f8 T8 J, }$ P& u* |
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置
    3 j/ O- c& n5 U
  36.       textData = currentLine;              // 将textData指向currentLine
    2 E6 V% G0 U) ?5 V% @5 [
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    # C9 j* z. S" B# L  n* |
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表" O. P& [9 `8 q4 t& v3 c
  39. 9 I% z! |  g& q8 f' I4 h1 u
  40.       if (lineIndex < numLines)
    9 U' I+ P" f$ v! J3 R
  41.         lineOffset += 4;                   // 更新lineOffset
    ' @$ H5 T3 \  J
  42.       ++lineIndex;                         // 递增行索引, \" A  S' k6 `1 T& k
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据' j& ?3 d: p5 N5 Y( |5 ^- `/ o
  44.     }, h; i$ [: }# @' F; w# f- e% X/ i0 z
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环
    " D  Y! |% A& _+ O
  46.     glPopAttrib();                          // 恢复OpenGL属性状态
    + u4 I$ k. \& F) a# L
  47.   }
    * m6 m- h5 h+ O
  48. }
    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& _' Oint xOffset,      字幕的x坐标( `1 m8 A/ l1 d: c  v
GLint yOffset,    字幕的y坐标
8 i0 a- L# r7 n- R& Pint numLines,     字幕的行数(较长的字幕为2,一般为1)
9 q0 Y1 r4 v" x0 W' J$ Wint 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