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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-5 16:49 编辑
/ {3 E# a! _5 S! I, V
* v1 ?( F2 |9 @  W! E  n5 X这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎' J/ L& {3 D2 ]. S
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
- D( ^! X3 ]% Uhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
$ P* _# k1 A  F6 `7 ~第1处. x1 S% u( z$ B
  1. void sub_451474(char *a1, ...)7 V% l4 E% P7 g& K$ j3 X1 m* y
  2. {
    " S: f3 R, {2 P+ `/ V
  3.   GLsizei v1; // eax
    ( E+ @+ d% _% {  m- \2 h. s5 c. e0 d
  4.   char lists; // [esp+4h] [ebp-800h]( D5 x5 O% E" a( D8 ~. G+ `; E8 t
  5.   va_list va; // [esp+810h] [ebp+Ch]8 I( x2 r/ t4 }1 F: p' d

  6. ( d0 c! `8 n! q: w/ ?7 b
  7.   va_start(va, a1);
    % D5 z: v8 e7 P- ]9 \. T* w
  8.   if ( a1 ); ^  d: I- e' j& G7 n0 B6 w$ I
  9.   {- x( Y7 {/ L3 X: E5 k
  10.     vsprintf(&lists, a1, va);
    # c. }2 ?7 B, e- _8 L7 ~6 P
  11.     glPushAttrib(0x20000u);
    * }/ M% ~( I$ e- f! P; K/ S+ |2 ?' }4 A
  12.     glListBase(base);
    - c  A* K4 n! ~/ ]  c1 @5 M
  13.     v1 = strlen(&lists);  ?4 q1 b( c+ f$ r, }( N
  14.     glCallLists(v1, 0x1401u, &lists);
    , s/ G: F, }( n4 f( P$ m9 ^' s9 e/ I- ]
  15.     glPopAttrib();/ W: V1 G% b3 D! e# |
  16.   }
    $ v4 q) q8 {2 ?, ?
  17. }
复制代码

) k3 y2 a' Z3 i- C6 v- b. I( C8 l$ P% t/ ], B6 u
5 }; c: q7 {) e
第2处
8 [: i* X# p1 U5 U7 `
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
    2 T2 ?: F) r) D# M8 {; j$ r" s* \0 g
  2. {
    # o9 `2 ~0 {& {; H9 N8 \
  3.   int v4; // eax
    # n. h- y4 p; D4 ~" h
  4.   GLsizei v5; // eax
    ' g5 b/ q% ~# n$ v3 O/ j) X1 M( }! H
  5.   char lists; // [esp+4h] [ebp-800h]
    7 w0 ]0 V; R& G- b5 y* k2 ^. }0 X$ |
  6.   va_list va; // [esp+81Ch] [ebp+18h]2 [8 \! |1 R$ o1 z' c

  7. 1 B. r2 [  [2 Y- B* [1 q  E( Y
  8.   va_start(va, a4);
    4 E! J# y! @% y! O9 J
  9.   if ( a4 )
    ( X; \4 g) `# F/ v. c$ E
  10.   {
    , @! ^! ?1 [9 S8 p  v& h
  11.     sub_44F8A0(a3);
    + P. r3 b& q6 t9 M8 s
  12.     v4 = sub_40BB44();
    " c* K( k3 r, {. m8 p
  13.     glRasterPos2i(x, v4 - a2);0 S2 z% K& L# `/ F  v  G$ c6 L
  14.     vsprintf(&lists, a4, va);; c; C( y; E) v) {1 y) g/ r% v4 }
  15.     glPushAttrib(0x20000u);5 s# L3 N% T5 |' H0 _
  16.     glListBase(base);- s0 q% W; n% ^8 Z) f# o% v
  17.     v5 = strlen(&lists);
    % ~; O- a  z% g- R8 |
  18.     glCallLists(v5, 0x1401u, &lists);
    , M7 w  V: w0 K1 i2 D+ |( M6 [- |
  19.     glPopAttrib();0 I! V# ^& }% R: E2 D$ N
  20.   }
    & A# d( w* m2 b% v
  21. }
复制代码
% I: i; }% s# B
! @5 }1 j# U+ s. ]
9 m# w$ H+ S3 r
第3处
& }2 p  m% Y( l8 y

  1.   r4 @; E$ C6 }9 Y) s3 [  V$ f' y
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
    ( g# c7 ~/ W- {5 [% ]# C' K
  3. {
    ( {! W, d  E% e0 e; W3 R
  4.   GLvoid *v7; // ST08_4+ J; x" g4 m( v0 A( f8 M
  5.   GLsizei v8; // eax8 O3 f2 e9 ^! n" ~) K/ z5 a% ]2 o
  6.   int v9; // [esp+0h] [ebp-1018h]
    & t9 f  ~: V( ]0 v) ]8 ]
  7.   char v10; // [esp+8h] [ebp-1010h]9 `+ F) ]; c6 g  G8 _
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]
    : D2 Q+ y& V9 H* X
  9.   char v12[5]; // [esp+1013h] [ebp-5h]* W2 m, _$ d8 \5 U9 G
  10.   va_list va; // [esp+103Ch] [ebp+24h]5 X& t4 I; f7 K* W$ G* d' U. ?

  11. . \% Q# u& J/ ~- C* L* L) \( f4 H7 H
  12.   va_start(va, a7);" \; z" z, f& k" u& u0 U: }: t
  13.   v9 = 1;$ p) T0 P; [. U: S
  14.   if ( a7 ): ^7 d5 q" q3 G+ _8 M$ i. y) A
  15.   {
      e, Y- J, ~0 _: k! r
  16.     vsprintf(&v10, a7, va);! D6 L) q9 H7 f+ ~: E
  17.     glPushAttrib(0x20000u);6 \1 W/ h: {: k& k0 c  Q% ~
  18.     glListBase(base);7 y1 P4 @6 x0 U+ X4 P" F, [
  19.     lists = &v10;
    . m; T* X% p/ d) _# h  h3 C1 `
  20.     do
    9 {" M  n8 V" Q0 H0 P* }8 n
  21.     {
    ' ^! r6 z! t0 v
  22.       *(_DWORD *)&v12[1] = lists;6 t7 w  u& x. k" q5 R# K) d
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
    , d# N; \  i4 o" h
  24.         ++*(_DWORD *)&v12[1];9 p! j7 k! N4 y, a  L4 C
  25.       v12[0] = **(_BYTE **)&v12[1];
    $ N3 R) K1 f* H. Q2 R7 J
  26.       **(_BYTE **)&v12[1] = 0;- w+ N( a, I9 X9 ^: `# P7 C2 d/ U
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )5 ~2 d6 H" H1 W5 x2 Z; q
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
    ' W5 @8 i1 ]" r% ~$ c1 x( @
  29.       y -= a5;% Y4 @5 }4 A* r& w9 o
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);
    1 r7 G: L0 Q! ~6 [* ]
  31.       v7 = lists;# j: l/ g- X6 r- k  Y& @
  32.       v8 = strlen((const char *)lists);  X2 i7 o5 N# ^; b" ]2 t
  33.       glCallLists(v8, 0x1401u, v7);. c2 p2 F6 ]6 E4 L
  34.       if ( v9 < a3 )2 p2 p# K/ K7 B0 u* s
  35.         a4 += 4;
    ; F' {: j6 n, P: {% S/ |% c$ X9 I
  36.       ++v9;
    ; X. o/ ^, i. f+ O# _7 P1 W
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);7 Z/ K& E" P% o: r% o2 A# L
  38.     }
    9 D9 D6 y/ [5 [
  39.     while ( v12[0] );/ u  V+ q4 v, m6 y2 M
  40.     glPopAttrib();
    8 q+ B  c8 {+ N! w& v! u0 p5 S
  41.   }% j$ z4 r8 q. }$ q9 _* V; t2 w
  42. }, X3 p( R0 b  Q3 i  m0 R3 Z
复制代码

3 z1 i# [7 w  T0 r5 Q0 M8 P调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810: W$ Q8 o1 T1 ?$ n6 K7 {2 z
9 e9 Y( j& X! p6 k# A8 d
  1. .text:004512B1 52                                         push    edx             ; char *
    $ i$ ?9 C6 }: A, D3 k/ E; q+ I
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]: U% z/ j% \3 {3 S3 d4 ^( Q, Z
  3. .text:004512B5 50                                         push    eax             ; base* O5 \) E- U* ?3 W, T
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]
    8 B; N# N5 s) L6 m( Y3 m; ]
  5. .text:004512B9 51                                         push    ecx             ; int/ x# K. {3 U7 a: H6 A$ H5 `
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]
    * A' e/ r1 y9 N6 b% }9 \$ z- Z  h! N
  7. .text:004512BD 52                                         push    edx             ; int
    1 j, B  c) |3 G' q& ?9 L8 _1 e. x
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]
    3 K: H& D  y& A9 V" A+ |0 Z& o3 K
  9. .text:004512C1 50                                         push    eax             ; int; s: J' @& u  }% U
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]
    6 p0 g3 G" a7 Y- J4 r/ G7 Z
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]
    % i9 ^4 i' Z4 B
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C]3 M1 _* j0 V7 ~$ i
  13. .text:004512CB 51                                         push    ecx             ; y; p6 f8 b- h9 a+ i6 s
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]* U7 y6 e+ |# X: ?2 `  U
  15. .text:004512CF 52                                         push    edx             ; int8 ^1 [8 R+ L, @- E0 |9 ^  l
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码

4 Y- D) p( g; wchatGPT整理过之后,如下# M( d7 K( U5 [2 U9 z$ r' p0 T

* {" k, M4 f2 B. X" L% {/ L
  1. void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)( \/ @5 a9 F% s0 d* g) C0 a8 T9 d
  2. {
    ! _2 X4 F; U: b, D
  3.   GLvoid *textData;         // 存储字符数据的指针
    7 Z+ h& _6 s' v: i% y( A$ Q! N
  4.   GLsizei textLength;       // 字符数据的长度
    ; o1 D' j. f8 p# X  S, H$ S+ C: s
  5.   int lineIndex;            // 行索引
    9 n- i( c8 d. t% }
  6.   char formattedText[5];    // 存储格式化后的字符数据( c9 `. D7 U( O3 d
  7.   GLvoid *currentLine;      // 当前行的字符数据指针
    ( j3 _7 Y0 j% K/ a& g% @
  8.   char buffer[5];           // 字符数据缓冲区
      |' L+ {2 m9 i
  9.   va_list args;             // 变长参数列表
      k0 a! K9 w5 n, x1 ^" }3 S

  10. * r) a8 N) D* Y" v4 ^7 D
  11.   va_start(args, text);     // 初始化变长参数列表9 c+ b9 Q; `1 s2 n# [# g0 j) g" A+ {
  12.   lineIndex = 1;            // 初始化行索引为1
    . A( Q' ^& J+ s. |5 s! z

  13. " K/ f2 @* h$ h: M
  14.   if (text)                 // 如果文本不为空
    & q) }1 R/ y; w9 T/ o  F, T
  15.   {
    7 s9 A+ @$ q4 w6 k2 \# I2 ~
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
    / h7 @8 \  ], N3 v! Q. d( l; a# y6 T
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态* O2 X* A! E% H7 I
  18.     glListBase(displayListBase);          // 设置显示列表的基础值
    ( [1 i! a  \# Y0 O! Y9 j$ ]
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置
    & Q. i! O  E% Q4 Q

  20. , V# [) _5 O. P# u) z/ ?
  21.     do: e! U" T# k9 I3 l* f
  22.     {
    8 }# m( r0 a8 q- r
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素
    ) y; T/ N0 C$ q, Y, F

  24. # p" o! ]9 n  O6 G& J
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束+ i% l* t+ T8 s7 f, s
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素& W2 f1 }( G. t! M9 {6 I9 y, o5 G
  27. 7 ^* g: s2 ]2 B0 g( i; O, h+ y! }
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素
      f* t/ o( N) W3 G' b' U
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符8 h$ w5 l; G# e  o, c

  30. 1 v" j- |7 e6 A; q8 F4 s4 `
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)6 e6 H& O6 }* P
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符
    / ^. N' a9 ^0 Q
  33. $ i- Z& {# z. q$ s/ m8 j1 U: C; ^, n1 o
  34.       yOffset -= lineHeight;                // 更新y坐标
    ! {6 ?1 k! r1 h5 M# k6 N9 Y% t
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置
    1 h5 O! }6 U4 c" @
  36.       textData = currentLine;              // 将textData指向currentLine
    " x7 [; j! X" \/ a: L3 Y8 q! F, P
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    + E8 o% `; l% S' q. y# D
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表
    5 z, @0 v5 T1 W' X3 T$ s
  39. 6 i8 v0 Z/ w/ j) N: K
  40.       if (lineIndex < numLines)4 T" j/ C: S6 V- B4 u
  41.         lineOffset += 4;                   // 更新lineOffset& g$ {  q) x3 E! J
  42.       ++lineIndex;                         // 递增行索引
    $ m& ]& O. P& m0 O
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据1 o- i1 e' M! {# ]9 i
  44.     }
    ! f4 _$ B. B& \  {
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环
    9 ^: C( o0 u. W7 b5 ~; X
  46.     glPopAttrib();                          // 恢复OpenGL属性状态
    ( s5 m# t) T  E( c, `& ^" Y, u
  47.   }
    5 w  u. |  Z1 |! R& s+ Q/ E
  48. }
    5 W) [2 _# e' x3 n$ ?9 s% }
复制代码
- z* H6 Q8 l+ c: `
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
6 A; y4 `: c. K, F6 L
* w, m# R  V. Pint xOffset,      字幕的x坐标& O8 E9 P( ~3 J+ y! P# B  a
GLint yOffset,    字幕的y坐标: j1 V4 n# J, x$ S, \* z6 o
int numLines,     字幕的行数(较长的字幕为2,一般为1)
+ Z0 D3 o$ `4 \int lineOffset,   这个需要再研究
2 O+ n6 }5 [; a5 \  P1 @int lineHeight,   字体高度(或行高)4 H* t) x0 `; D" l4 R
GLuint displayListBase, 这个字体对应的base值
" E* X/ x1 W; V2 Y/ Hchar *text, ...         字符串
. Z/ w1 J( ~+ J" y/ z4 }6 P
  k1 U1 O+ s( K$ ^5 o% t
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
 楼主| 发表于 2023-9-4 18:53 | 只看该作者
顶上来,顶上来
, R4 i9 n0 n/ Q9 Z- k% \' ]
回复 支持 反对

使用道具 举报

高级模式
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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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