设为首页收藏本站官方微博

建议 【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数

[复制链接]
查看: 397|回复: 1
打印 上一主题 下一主题

[建议] 【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数

跳转到指定楼层
楼主
发表于 2023-8-27 13:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数

本帖最后由 shane007 于 2023-9-5 16:49 编辑 0 b1 t5 l, J/ V( y0 f3 }, B
: T; a$ q" ]) _  s+ i0 ~; b' I
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
4 d- a4 H* @9 N% K5 m# \因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
0 N/ k9 I7 C1 d9 G7 P+ rhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081( x8 `( s' C2 _" U
第1处
# L' h! \9 G. f2 w+ U' ?" M
  1. void sub_451474(char *a1, ...)
    ' c* n) G" U+ m* i" B; g0 J
  2. {
    % R; |. i" }1 ]& b6 f9 U
  3.   GLsizei v1; // eax
    9 h# M' `- i, ]& q7 v" o1 j4 f0 X4 T
  4.   char lists; // [esp+4h] [ebp-800h]2 L+ k. D2 Z% y, }6 h8 f2 }) b
  5.   va_list va; // [esp+810h] [ebp+Ch]2 y5 ?# @% o5 `+ t% o. C
  6. % v. o: }+ {$ {' m
  7.   va_start(va, a1);
    * ?" L( [, W; W; I6 \
  8.   if ( a1 )
    9 i; S9 ]9 A0 L2 R! a) p* @  C
  9.   {% g' J3 M  L7 J3 J5 g. C
  10.     vsprintf(&lists, a1, va);3 w. @1 v4 ?+ |; I" A$ S2 Y1 q4 X
  11.     glPushAttrib(0x20000u);4 o( s4 E* P6 }1 r3 c& l4 p# j% q
  12.     glListBase(base);
    % g7 K, R, F$ D* ^
  13.     v1 = strlen(&lists);
    1 P. P5 u* U& q8 l
  14.     glCallLists(v1, 0x1401u, &lists);2 w# o- `: z* ^0 |2 |, U' |
  15.     glPopAttrib();
    7 d# k/ z3 G( n, c
  16.   }6 l. Y8 j: S# t; r/ m
  17. }
复制代码

) y; y3 L' s4 v0 ^3 M( G
& ^, G! Q0 m' ^' R0 ]; ]* t
; X& T  U3 }# L" M; L第2处
: O$ f4 w' u+ r3 \( Q) c, T& X
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...), e9 Z7 _$ u& r: b" D! p$ A
  2. {  @( R0 P+ `) j# e* _
  3.   int v4; // eax$ X( Q. f7 l9 r" E
  4.   GLsizei v5; // eax
    5 I  M* u1 @  Q: k+ G6 G  R
  5.   char lists; // [esp+4h] [ebp-800h]
      p# y; U+ p6 j& X
  6.   va_list va; // [esp+81Ch] [ebp+18h]; O% l" ?& f  ?0 r7 I% U; e% T
  7. / F  s% Y1 {9 y
  8.   va_start(va, a4);
    * S  S# F5 f7 d* K7 J+ g2 O
  9.   if ( a4 )
    ! ~/ Q- A8 H/ B
  10.   {) O( f+ a! `1 [0 J* a( Q( Y  m$ E
  11.     sub_44F8A0(a3);% @* i, l, R1 k9 G( {# j% e
  12.     v4 = sub_40BB44();
    2 u) s; \1 n6 n4 j! U
  13.     glRasterPos2i(x, v4 - a2);0 E3 H+ |+ i' u1 K2 G) B+ T
  14.     vsprintf(&lists, a4, va);0 W* N  i# V; H  }
  15.     glPushAttrib(0x20000u);
    * j5 X5 Z+ r& e" P
  16.     glListBase(base);
    - s) j7 L# n, O
  17.     v5 = strlen(&lists);$ v, x! y1 j+ c9 Z( h& R- y' k- b& p
  18.     glCallLists(v5, 0x1401u, &lists);
    ; ~* y! U3 Q# w2 G5 g
  19.     glPopAttrib();
      O8 e0 H& i/ P1 ^
  20.   }3 g5 l7 \& a* ?
  21. }
复制代码

2 ]2 [+ w5 W; S6 i1 ]& _
6 L/ U3 h! P$ S7 M( A: n# A1 h% U: A) H- F
第3处
6 h1 B$ I" G2 r# ~6 N

  1. - l+ V5 c* T' m0 Q
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
    4 R9 i  z3 M2 q2 z" }: Z5 p
  3. {
    % H7 U* p: C: \9 [' B
  4.   GLvoid *v7; // ST08_4
    5 j5 \4 y3 D' c! I
  5.   GLsizei v8; // eax- J' F8 e: Z9 C! o+ b
  6.   int v9; // [esp+0h] [ebp-1018h]
    4 v# G' y- V2 V+ y5 t% T
  7.   char v10; // [esp+8h] [ebp-1010h]; t9 G- ~8 o( w; d  u9 @, D
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]
      z& h8 T0 G, C& r, I. Y( o" r
  9.   char v12[5]; // [esp+1013h] [ebp-5h]
    / f5 F7 B3 R0 |1 ~1 K9 L1 _$ [
  10.   va_list va; // [esp+103Ch] [ebp+24h]
    . P7 N8 `6 T6 e

  11. , b/ ~; z$ d5 O# t, A0 M3 N; m* l5 h
  12.   va_start(va, a7);
    ' ]- F) {0 X  `  B/ x( _
  13.   v9 = 1;
    6 i, w# W) `5 `3 S! O$ z
  14.   if ( a7 )
    / X( F- p0 U; N
  15.   {
    : C5 `7 o8 P. ~) |
  16.     vsprintf(&v10, a7, va);
    7 t6 v+ |' R- S! `0 y( D/ c+ F
  17.     glPushAttrib(0x20000u);) E% h( h3 ^+ P  J3 R) U4 r
  18.     glListBase(base);% Z. S' _# i/ c7 n
  19.     lists = &v10;
    $ l, F/ {" i7 s- G2 K4 g
  20.     do
    & H" a/ c1 J/ T9 e. E
  21.     {
    & p; `; V9 s! Z" a( F( c3 B
  22.       *(_DWORD *)&v12[1] = lists;5 o; N, k. ]3 R' @
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
    , t, f4 J9 k! p% c) N$ C
  24.         ++*(_DWORD *)&v12[1];- T2 }2 Q( |% s0 n8 l& O
  25.       v12[0] = **(_BYTE **)&v12[1];
    5 v$ w9 A$ l1 D5 L; ~3 A
  26.       **(_BYTE **)&v12[1] = 0;3 O2 _1 U" d' p/ P
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )% Q) m) D3 B. T; w1 o3 S
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;* x* E: ^+ f$ Q% @
  29.       y -= a5;
    5 V% e9 n9 U8 D1 _  Q& o
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);
    / e, j1 v( o+ L1 i
  31.       v7 = lists;
    / P3 t' b6 `% ]
  32.       v8 = strlen((const char *)lists);' q  Y2 Z+ ~) e  X9 O2 b: {
  33.       glCallLists(v8, 0x1401u, v7);' m) A. E7 H$ X4 j' T! E$ O
  34.       if ( v9 < a3 )- }7 d9 o7 {" P3 K
  35.         a4 += 4;
    4 }/ T: Y; a% ~) \1 e3 z0 r, A
  36.       ++v9;% s: x6 d' d) }  C2 p
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
    6 ~, n6 V! H4 N5 k
  38.     }
    9 F( x, L1 C/ b" _
  39.     while ( v12[0] );+ f* I0 E5 D  r& y
  40.     glPopAttrib();
    + r0 T/ I2 a7 d# }+ Y
  41.   }
    & O$ t& q% A7 {0 S2 P
  42. }! Y+ L8 p" |$ Y  F  H7 l7 z6 a
复制代码
7 s2 M2 \1 j  i3 Z0 w3 @
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
# i2 x& ^9 j0 O3 h* C2 Z3 h; V6 e& e5 Y1 h
  1. .text:004512B1 52                                         push    edx             ; char *9 ^: D3 i) m$ E8 }
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]
    2 ^" O. `% _5 F. c) h4 c
  3. .text:004512B5 50                                         push    eax             ; base
    ; p" U( R3 H8 J; x& F% |5 E3 P! @
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]7 N. B9 u/ f9 `6 R  g0 o* D  J# ?7 m
  5. .text:004512B9 51                                         push    ecx             ; int
    ; L& E6 K( Y6 O! S7 @* S2 ]
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]
    6 }/ `, h5 F7 S! h3 h
  7. .text:004512BD 52                                         push    edx             ; int
    - @( Y5 G) \, e, k' d4 P. h
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]
    7 }- P6 [' f- d  T" Q3 m6 ]
  9. .text:004512C1 50                                         push    eax             ; int6 J( [- F4 k6 z0 X" L
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]) f  v  }# k% u, \7 h+ \3 r
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]% ^- h1 ?! ?+ L; ~; J; c& }% N
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C]% q$ t* Z. F' q! B* m
  13. .text:004512CB 51                                         push    ecx             ; y, c" o% E0 _5 L0 Y. s
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]
    ) ~3 m* X2 @" Z' Q
  15. .text:004512CF 52                                         push    edx             ; int
    ; P( `7 B1 u! h
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码
; F9 I2 m0 r, f
chatGPT整理过之后,如下
: v5 s% y: b5 L8 _6 ?! `0 T
5 n3 k$ d. z. f8 \
  1. void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
    ) p" B8 x! p7 S( d( s. J
  2. {
    2 y5 h  ], k& ]! d  s5 |; p+ O; N
  3.   GLvoid *textData;         // 存储字符数据的指针
    ( F$ h. u3 \, s3 ]
  4.   GLsizei textLength;       // 字符数据的长度3 p8 {3 U3 D/ }* z7 e4 K( t% y
  5.   int lineIndex;            // 行索引
    + B! e6 Q' j5 b% b1 _8 |9 J
  6.   char formattedText[5];    // 存储格式化后的字符数据
    ! I  z1 S0 j3 A' z) {/ ~' f
  7.   GLvoid *currentLine;      // 当前行的字符数据指针2 M. M* X# m9 ]- y5 F
  8.   char buffer[5];           // 字符数据缓冲区
    2 x$ o2 ^% u$ [" {, I
  9.   va_list args;             // 变长参数列表
    * S4 C' W/ ^; Q

  10. , M7 p  l: k( n* P2 e6 o
  11.   va_start(args, text);     // 初始化变长参数列表
    & t# h8 P1 c: |6 F2 S
  12.   lineIndex = 1;            // 初始化行索引为11 \" i1 P7 }2 x- n+ y$ R
  13. ) V& Z" Z* f) S' o# T6 ^
  14.   if (text)                 // 如果文本不为空6 S# j! n9 R  s. R' }5 Y+ h
  15.   {
    ) g# n' u9 f( I, ~5 b9 ~9 d! R; G
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中% N  C; D  S* M
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态& j  Z7 q1 E9 e' p. C  o3 k  Q% j" J
  18.     glListBase(displayListBase);          // 设置显示列表的基础值
    * b: F9 d- C/ c# \# B
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置. d7 l8 p5 R+ w5 b; f
  20. 0 _1 h5 V: Z* C6 V  r! q* X7 u/ f
  21.     do
    $ i: G/ B3 K' g( {) B
  22.     {7 L; r8 q: \" h" e
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素
    & A, u' c8 q" {! l* |% f( J
  24. * K" ?$ f, F# z4 q$ r) j& |
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束
    3 l  }' U1 N( k# f8 W) ?& {  ]
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素  N7 J: P! C8 A, E' U: I0 `
  27. $ C! N) C  C* B, `; H
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素; W1 U0 b, J2 r6 [4 M
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符, @  A, g% J8 Q/ y  X; X4 G
  30. 2 e2 D0 x9 H4 C0 w% R
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)6 E( u7 l4 E" k0 z, c1 P
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符$ T+ M8 V0 w( h, v; ~

  33. / u, @5 |6 N: d: U/ r' q
  34.       yOffset -= lineHeight;                // 更新y坐标/ p2 x- p8 D; H  L  C4 V
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置5 w; h% g) k5 b
  36.       textData = currentLine;              // 将textData指向currentLine
    ' A9 h* O8 G6 K7 m  J7 @1 g: z2 ?
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    ! P2 ~8 i8 R3 }% e! k; ?7 h, U
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表- [: v& c1 h) ?3 j
  39. ; a! k) _$ j2 B+ X/ l& n
  40.       if (lineIndex < numLines)  k9 y/ v( |- _, L1 v% `+ @3 k
  41.         lineOffset += 4;                   // 更新lineOffset
    - U$ B; z2 [# L9 T9 j
  42.       ++lineIndex;                         // 递增行索引# D$ `% J$ s; k' x4 A4 r
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据
    / s1 H/ y3 k; z! _% M
  44.     }
    ; n/ F+ ~. N" ~) W: F# H4 k
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环; p$ r& U$ E% f
  46.     glPopAttrib();                          // 恢复OpenGL属性状态
    + V! E: i! C8 S0 w. b" g4 [: \1 s
  47.   }
    % k1 t2 V- n. r6 F; P
  48. }
    5 t: j& e* n1 B
复制代码

/ m1 b  F( f% _/ D含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
8 w3 O$ u1 P/ Q0 U' T4 k8 T/ c7 v$ _4 V; q) @5 }& b3 k
int xOffset,      字幕的x坐标
) M+ ]5 ?, k( }! T3 nGLint yOffset,    字幕的y坐标
) c  }. b1 q: [% C, m3 iint numLines,     字幕的行数(较长的字幕为2,一般为1)0 P. e' b) q: ~' }
int lineOffset,   这个需要再研究( M- P- r" l4 @- v
int lineHeight,   字体高度(或行高)
. N1 p, V4 {: mGLuint displayListBase, 这个字体对应的base值1 R$ L' u% J  t" |7 l9 c, v
char *text, ...         字符串
7 Q) L) m( F7 V3 N0 }; o
" w' m) l7 A% W7 @1 g
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
 楼主| 发表于 2023-9-4 18:53 | 只看该作者
顶上来,顶上来
7 h5 F, d  b$ r. `6 O
回复 支持 反对

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies

本版积分规则

冒险解谜游戏中文网 ChinaAVG

官方微博官方微信号小黑屋 微信玩家群  

(C) ChinaAVG 2004 - 2019 All Right Reserved. Powered by Discuz! X3.2
辽ICP备11008827号 | 桂公网安备 45010702000051号

冒险,与你同在。 冒险解谜游戏中文网ChinaAVG诞生于2004年9月9日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

快速回复 返回顶部 返回列表