冒险解谜游戏中文网 ChinaAVG

标题: 【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数 [打印本页]

作者: shane007    时间: 2023-8-27 13:49
标题: 【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数
本帖最后由 shane007 于 2023-9-5 16:49 编辑
  u- ?% ~$ O' J- ^0 V! J) h# |) h! {4 _
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
9 J5 J* g# S: S" R7 a* r( R因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
8 o1 q7 r" }% [* uhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=1540819 v; J9 O0 |. _# J8 `
第1处7 F  O4 L( w- l& a5 [" e9 j
  1. void sub_451474(char *a1, ...)
    5 c* g$ H4 R; H0 T7 H. j
  2. {- ]; J( m! m7 C
  3.   GLsizei v1; // eax1 O2 w7 Q, W/ O8 v8 ?) [5 e% E
  4.   char lists; // [esp+4h] [ebp-800h]& }; ?/ M* s6 j
  5.   va_list va; // [esp+810h] [ebp+Ch]
    3 \: E' `4 F* M7 y8 |/ M5 l
  6. 3 _! _! A! `9 G
  7.   va_start(va, a1);
    3 T) |- L4 A: n, W4 b. y/ `& \
  8.   if ( a1 )  B. A5 L3 I9 s: N- }; d
  9.   {6 f1 Y( y5 T& j
  10.     vsprintf(&lists, a1, va);
    & H, E1 t. j, p9 p
  11.     glPushAttrib(0x20000u);% \4 k$ k2 t  E1 s: S( z  T  i' @
  12.     glListBase(base);
    0 U, x) n: o  v' H4 V6 r' R
  13.     v1 = strlen(&lists);( I7 _! R, {% v  Z4 D) q: V
  14.     glCallLists(v1, 0x1401u, &lists);
    ; m1 F5 B* k, T  ]8 r2 A
  15.     glPopAttrib();
    $ j/ v+ \- A% S/ T
  16.   }
    4 m; A/ }6 m* H2 Y
  17. }
复制代码
7 Y2 Z$ G6 k! ^( [
2 W9 W& j# Q" ^4 W* O3 W

- H9 t+ h+ K7 X第2处2 y( `" T- p) M* n) f. R( l
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
    , }  P- m& G% w# p! M% `8 F
  2. {
    3 k1 h: K! U: C: g) n
  3.   int v4; // eax
    ) e3 `5 C3 S5 P
  4.   GLsizei v5; // eax( Y; ^, K/ f8 S' X0 X! q7 ^/ t5 x
  5.   char lists; // [esp+4h] [ebp-800h]* W; p* W! Z6 T$ i3 O9 T
  6.   va_list va; // [esp+81Ch] [ebp+18h]
    $ `# g# F- T  M

  7. . \. m+ x" y+ \. N
  8.   va_start(va, a4);
    ( i: }% V' |8 X0 {
  9.   if ( a4 )
    ' A* l3 N5 H* e! F
  10.   {
    " s( Z1 t4 K, w* @7 u
  11.     sub_44F8A0(a3);
    4 p8 D$ x6 N5 ]9 B# Z
  12.     v4 = sub_40BB44();
    $ @7 t/ K! [7 c9 x% L  B' v& w
  13.     glRasterPos2i(x, v4 - a2);4 @2 U( f% X; w) L% K( J) Q+ n5 w
  14.     vsprintf(&lists, a4, va);: o+ v1 c9 I8 w; k( [$ ?. e
  15.     glPushAttrib(0x20000u);- C, G" o  A0 ~- E
  16.     glListBase(base);
    ) b+ {- M2 M, L4 K  i' F
  17.     v5 = strlen(&lists);
    1 U2 A2 d9 a! ]: \( A: Z" l* ~
  18.     glCallLists(v5, 0x1401u, &lists);8 x: O( i. `/ V0 Z) f
  19.     glPopAttrib();5 v7 ?) m9 n1 q/ L
  20.   }
    2 r2 h# Z& n$ a4 a2 w+ d$ E
  21. }
复制代码
, X2 L0 f: o+ T) F% N
+ I" p3 k' n$ R: u

- N3 H& e. C( e* u( L6 I) ~" \0 H第3处- w# W6 }  g' q: M% T& J+ q

  1. 0 F* X: r5 r6 x+ h( }( W2 t! L
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
    . H- D- {  y4 q+ @! P6 H- M$ r
  3. {% g4 F. T6 D, X" K% S* H, q
  4.   GLvoid *v7; // ST08_4
    ) V+ `6 y3 Y) }! q# _9 b9 V
  5.   GLsizei v8; // eax! ~; F8 D# G0 r. x( |
  6.   int v9; // [esp+0h] [ebp-1018h]
    0 k. \' c- u% b- [* G+ R
  7.   char v10; // [esp+8h] [ebp-1010h]2 l; u* }  o: Q" x( \  M6 ^8 V
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]5 R- [( w9 `! x% p& |& B3 {
  9.   char v12[5]; // [esp+1013h] [ebp-5h]
    0 H" {5 \% y% G0 y3 p
  10.   va_list va; // [esp+103Ch] [ebp+24h]
    ; g2 {0 u7 S* n1 ?  b
  11. 0 F+ V* S& `( ^/ M& v7 M4 d$ B! }0 ~
  12.   va_start(va, a7);! q& {1 r) |) z  s3 X6 B& P
  13.   v9 = 1;
    0 O) A, u: c4 O  B& O
  14.   if ( a7 ); t  l3 a' s- N1 l" V7 {
  15.   {2 b$ j! z+ k- \2 i- o$ k6 f
  16.     vsprintf(&v10, a7, va);
    5 [7 [( F; B$ z! f8 ]
  17.     glPushAttrib(0x20000u);: _0 u: V" w! y. U! W6 O: z
  18.     glListBase(base);! I8 o5 e. k0 e* t# z  {/ u
  19.     lists = &v10;1 T. S/ _# e! Q7 w5 |
  20.     do
    : [& y% J6 B8 D; N- \
  21.     {
    ( `' d2 c4 C7 n3 \2 i8 {
  22.       *(_DWORD *)&v12[1] = lists;
    % y6 C; j/ m' D  c; V
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
    & f7 V/ W  s0 C3 f
  24.         ++*(_DWORD *)&v12[1];+ p- n' N0 d. X# x
  25.       v12[0] = **(_BYTE **)&v12[1];
    & ~8 p  W' }% B& K- I4 Q
  26.       **(_BYTE **)&v12[1] = 0;& X$ }! s' J: l
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
    ! l' H1 N! V! U( _1 [5 L
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
    " S( f- o) ~9 A( I1 p- w: ?0 n
  29.       y -= a5;) b/ G0 w& A9 u. K$ _
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);* g' b% |( m5 P. p# @
  31.       v7 = lists;
    * G; z3 g5 c$ S8 _. h  v# ?. m
  32.       v8 = strlen((const char *)lists);
    5 e% Z' _/ @1 ~9 x
  33.       glCallLists(v8, 0x1401u, v7);
    . c6 c% V2 U! r
  34.       if ( v9 < a3 )5 z& A+ w$ ?& e# t
  35.         a4 += 4;8 H" {; q7 @% Y' J
  36.       ++v9;9 b6 A9 k' w6 K8 K) B' q7 e
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
    / m8 E* A  X, D7 {, p' ^
  38.     }
    0 |) B5 E2 G0 S0 Q
  39.     while ( v12[0] );2 @4 G( t# N1 U. l
  40.     glPopAttrib();5 J6 h' |* O/ I6 n% u6 p9 O, @  r( r  C
  41.   }( X# N9 E2 c0 B. E) T- g8 z% V7 ?6 X
  42. }
    8 P8 r0 T  @. T; T) j
复制代码

4 z/ K& C) w/ j" K9 L" J4 O/ O调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
1 B# V) g, A3 e, R1 E
% z! t+ b' ~7 U% h/ L
  1. .text:004512B1 52                                         push    edx             ; char *' Z* r" j4 v" _
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]3 W& r0 g! s- Z, u9 O& a( T7 V
  3. .text:004512B5 50                                         push    eax             ; base
    7 K( b9 m3 n2 X' s3 F5 M" w$ ?8 M, X
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]
    , S+ ?7 ]' ^0 ^2 H! U% ^1 Q: r5 c. r0 g
  5. .text:004512B9 51                                         push    ecx             ; int8 Z& k8 Q' s; D
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]; ~. ^7 t2 a; N" K
  7. .text:004512BD 52                                         push    edx             ; int4 q: E+ t- v9 }# p
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]
    7 F* _6 t: Z, s# H) E! O. Z
  9. .text:004512C1 50                                         push    eax             ; int: B' m( J2 B" S' ?% t$ H( |
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]1 Q" M4 R& b3 [( ?& a
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]
    5 c' ~  {6 I' E2 o/ h
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C]9 m: u  e' p( C: k7 v  ^, G
  13. .text:004512CB 51                                         push    ecx             ; y/ D% f, T9 ]% X8 d& s( o
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]
    6 ~9 C& _, H1 ]
  15. .text:004512CF 52                                         push    edx             ; int# m& C/ r" ?5 z
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码
& t' i- x3 g; Q, C$ N' X
chatGPT整理过之后,如下
- P% Q6 z( R3 l- V3 j. s/ h' ?. [+ x* C% s5 Q  E  F
  1. void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
    1 N( d) l3 k/ p+ f  @; E+ E
  2. {
    ! }/ {% q" X! l. t  ]
  3.   GLvoid *textData;         // 存储字符数据的指针
    4 Z% W4 ^2 c" X. W$ ~9 i
  4.   GLsizei textLength;       // 字符数据的长度
    1 G/ s) R; N2 o" |
  5.   int lineIndex;            // 行索引
    8 C  |( c# s9 {9 `3 z0 c( V6 _7 d9 E
  6.   char formattedText[5];    // 存储格式化后的字符数据, |) E6 B$ M! r5 t( J/ G0 w
  7.   GLvoid *currentLine;      // 当前行的字符数据指针
    " \- S! {' {4 F: a
  8.   char buffer[5];           // 字符数据缓冲区# J2 v" E: u/ u
  9.   va_list args;             // 变长参数列表9 n1 I" A( j' M( v) G: V) R: a
  10. 7 d' }* y/ j9 G7 i4 Z' G
  11.   va_start(args, text);     // 初始化变长参数列表" I4 f3 @" I2 J
  12.   lineIndex = 1;            // 初始化行索引为1
    ' ]/ b- B. Z' f# v4 Y! b5 ]$ |
  13. ; H' K+ Y2 S( m, c9 ?
  14.   if (text)                 // 如果文本不为空
    ) c. D$ q! z( ^# S5 o/ V+ e( ]
  15.   {) K& e% N& _8 D$ b- n3 H' V; L
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中$ b1 E: V+ R. L" ~
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态# t* _5 Y4 E- P, }, y
  18.     glListBase(displayListBase);          // 设置显示列表的基础值
    ! M3 u( B8 [0 `) _+ `: I$ W- O
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置. F1 l0 q% G$ g# r* b0 M  i4 @

  20. 7 C  b2 y7 H8 q! Z. A2 H5 w
  21.     do' }: \/ S8 D* u; N3 _- K
  22.     {- l5 p+ l, m. E5 j% c4 |& r! A' _# f) _
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素' V9 c: }+ K$ U( e4 r
  24. & X# W) t  Q$ {8 Q" z" ^
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束4 Q3 M2 Z1 ]* a& P3 S
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素
    , N% o6 }) ^$ A2 o' b/ T/ N$ ?

  27. 2 f9 m: y3 l2 W2 B5 g6 o7 p  x
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素
    / _- Y% d& r8 Q2 O8 }# g' y3 S3 v
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符
    & U: |- O4 O6 g' H0 _

  30. , w5 V5 w+ n! ]0 ?
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
    ' A$ ?! d& n* K" A; m% O4 R# Q5 Z
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符
    7 U& Z6 _: T% S: D; T

  33. : |# O% l# p# U+ j4 A1 b8 I
  34.       yOffset -= lineHeight;                // 更新y坐标  c( _! P% p# C' [2 ?7 C0 v, A
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置% h0 z+ T  \2 c$ Y6 I+ H
  36.       textData = currentLine;              // 将textData指向currentLine$ x0 ]$ ~; A. m; _  v% R( A
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    # @) t2 A6 F8 m4 U% O9 w1 R9 S
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表
    8 s1 m# [0 h, ]
  39. * X/ o; J# D1 E) @0 w( Q9 }. g
  40.       if (lineIndex < numLines)9 E* a. V# [2 I* S- H# k- T6 u
  41.         lineOffset += 4;                   // 更新lineOffset0 U9 R8 ?. C/ i3 K+ n1 Z
  42.       ++lineIndex;                         // 递增行索引
    9 l! f0 D7 W4 x  |
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据
    . Q" S! C! t% r( B5 }  }# p
  44.     }; M! M9 Z. Y9 F
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环
      l; ]$ p. g5 Q7 ~% E; ?$ N% \, y4 }
  46.     glPopAttrib();                          // 恢复OpenGL属性状态
    . J0 e( n% i8 L9 M
  47.   }- h& W: H7 f+ Z/ W* y( }0 s+ J2 V
  48. }
    / ]  ?+ k4 p/ F& U  m
复制代码

( q9 X/ i3 J. h) R4 _; j含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前: m# F: X+ ]% |9 M) B* s

, a, W# H6 S' R3 w% {4 o7 s# Wint xOffset,      字幕的x坐标/ G+ V8 _5 C, V1 `: N
GLint yOffset,    字幕的y坐标
7 |7 @. _1 L: f% Uint numLines,     字幕的行数(较长的字幕为2,一般为1)+ M/ E9 N+ G5 W, e! S
int lineOffset,   这个需要再研究+ M1 c1 s1 l9 Z9 ^6 t
int lineHeight,   字体高度(或行高)& I4 Y( k  I2 }* W  A1 c& P
GLuint displayListBase, 这个字体对应的base值
! ^5 c( f: k+ _3 T7 y' hchar *text, ...         字符串' G; k# r! E  ?; `6 N
* [8 k) o' L! z! ~4 \- f

作者: shane007    时间: 2023-9-4 18:53
顶上来,顶上来% R0 M, H& b; ?! C' s% M5 G





欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/) Powered by Discuz! X3.2