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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-5 16:49 编辑 & s6 T; m8 K( r6 x( _0 [: @0 X1 P5 p

5 e: w) h& _% t8 U, ]这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
8 @" y* z7 M& R* D! Z5 r, F因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
1 P/ K- q+ y3 X' n# k5 xhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081' z& x# {; }/ T: l
第1处& ?- d, ?! b/ f0 L" b
  1. void sub_451474(char *a1, ...)0 D( D. C2 A* k: g& |( I
  2. {
    1 |: I  M9 U: }
  3.   GLsizei v1; // eax
    . B/ E; b: J+ |( n! a4 S
  4.   char lists; // [esp+4h] [ebp-800h]% |/ A: Y% x' C9 y9 f. E1 y% |
  5.   va_list va; // [esp+810h] [ebp+Ch]
    ( B6 j4 t6 \4 ^. i. z( N- w7 s

  6. 1 l4 Z% o$ z* w: T6 E* n+ K. I: T
  7.   va_start(va, a1);
    % c1 e* o- V+ L& u
  8.   if ( a1 )/ P/ u1 i, p2 o1 D
  9.   {: t4 ?0 B1 D1 M8 n
  10.     vsprintf(&lists, a1, va);
    5 H/ X4 ^7 b2 u! K; D1 q
  11.     glPushAttrib(0x20000u);
    ( L: O9 }5 N8 n1 Q9 B- y
  12.     glListBase(base);
    - h, U' \* n+ z1 l- [0 T
  13.     v1 = strlen(&lists);  `, A: F8 V$ s$ j
  14.     glCallLists(v1, 0x1401u, &lists);
    & v) [( G7 W1 X
  15.     glPopAttrib();' f4 g0 Q5 B1 j* L9 L
  16.   }, m  o+ ?/ R$ A' M; R/ z
  17. }
复制代码
9 O4 c* b% r% m5 p# r3 Q

4 ?8 b' D4 k% c, c7 p1 S4 ~
# o. |- G& p. K2 r第2处. E4 y3 A3 }" X( z3 ]) r  C* ?
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
    # [3 o: x* b: f* J' \
  2. {
    2 }) p& R' F4 Z5 h; @' f! W; O
  3.   int v4; // eax
    ( ~" Y& X  G6 P7 w
  4.   GLsizei v5; // eax' K5 r( k+ V5 T3 L
  5.   char lists; // [esp+4h] [ebp-800h]
    ) l7 k5 d* y2 S' b4 c
  6.   va_list va; // [esp+81Ch] [ebp+18h]* U7 o! K; K- t5 n* I) B$ @

  7. ; W0 v( U$ z2 F5 M. ~6 t- ?
  8.   va_start(va, a4);
    & G/ |: P; S3 Q7 P: c0 s' G" \
  9.   if ( a4 )
    9 T5 N1 N+ l1 z3 \$ A# ~: Z' [
  10.   {
    1 P$ {  z# k$ e9 G1 h
  11.     sub_44F8A0(a3);
    5 e1 A4 t/ {6 r9 l
  12.     v4 = sub_40BB44();
    ; W& b4 x% \* p. f4 ]" W
  13.     glRasterPos2i(x, v4 - a2);
    . I$ L3 |4 J' r) M& v
  14.     vsprintf(&lists, a4, va);. l1 L- y- t5 a$ ^9 ]2 }
  15.     glPushAttrib(0x20000u);
    ( y; }4 L  r9 x0 P' W, K& l
  16.     glListBase(base);+ \7 C  f* O- O1 t" x
  17.     v5 = strlen(&lists);
    ; h: b; U& T4 h: S+ ?8 j
  18.     glCallLists(v5, 0x1401u, &lists);* e3 J: w' R8 S6 ?' [  e& [
  19.     glPopAttrib();, S- y8 j7 F% J2 ~$ I
  20.   }5 v6 E1 |0 `( j8 y6 `( }8 q
  21. }
复制代码
" I4 V  q- z/ J4 E6 J
) z( h  d' C% l6 [% M9 y& Z
. y7 L7 s& c* L2 X: P8 @
第3处9 c: i  _* ]0 t- |

  1. # |5 o" {( y9 Z3 M0 Z& m$ e
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)  p2 S; }7 p0 J  o
  3. {9 A6 h: G5 }3 t
  4.   GLvoid *v7; // ST08_4
    * J( @' z: P- q1 E% [$ Q$ f
  5.   GLsizei v8; // eax
    / {+ K( c0 q; a5 k, Q/ |  N
  6.   int v9; // [esp+0h] [ebp-1018h]+ ?* e5 b7 _) N4 \" v
  7.   char v10; // [esp+8h] [ebp-1010h]6 w3 y* T# H- [2 y$ X" p4 j
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]
    5 c  t0 G; b3 Y) L8 s
  9.   char v12[5]; // [esp+1013h] [ebp-5h]: X  H7 F- E" J$ a: v
  10.   va_list va; // [esp+103Ch] [ebp+24h]
    1 b7 U3 d; p4 z( ~3 ?
  11. 0 |: H* \( w- Y  ^' F# H1 B
  12.   va_start(va, a7);
    0 q$ B: m* i& K: d1 z, R9 t
  13.   v9 = 1;6 z; Z- M0 U# g  _/ e1 Z
  14.   if ( a7 )& ~0 m5 F' V, _0 Z% p! Q% X! j
  15.   {. {- f# C$ y+ ^5 F6 q
  16.     vsprintf(&v10, a7, va);0 G0 ]! y2 _2 Q
  17.     glPushAttrib(0x20000u);
    5 k% b7 t) a1 t9 i) [( J
  18.     glListBase(base);
    & @- s! P0 U  t! ^5 V- [& F/ V, u: n
  19.     lists = &v10;
    * K9 n, a% k  `% F
  20.     do& Q/ c  T7 \+ O' P+ _; R3 p) B  r
  21.     {
    + @5 B6 z$ Z$ H: S9 \0 E4 X
  22.       *(_DWORD *)&v12[1] = lists;
    8 e+ G4 e' I1 h' Y8 |
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )! t6 _6 N2 x* o  d9 y8 p7 H
  24.         ++*(_DWORD *)&v12[1];
    ( n6 k" G6 G+ [8 V
  25.       v12[0] = **(_BYTE **)&v12[1];
    * t4 k7 S. q: F( ^8 s
  26.       **(_BYTE **)&v12[1] = 0;
    ( x" G* G, c8 t4 \: o' p# x
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )- n" S8 T& |  V' @4 c# n
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;4 M! x% }0 h6 j$ b! V) |
  29.       y -= a5;
    ' N% Y1 ?& e/ }" e2 R$ ~1 y# O
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);& _  b4 Y4 I! z% |) N1 {
  31.       v7 = lists;
    ; c- E1 d& f7 }! K5 O
  32.       v8 = strlen((const char *)lists);
    " O7 D9 G! u1 d" t3 l- f6 x' o
  33.       glCallLists(v8, 0x1401u, v7);
    ( w$ m3 x, v; F9 ?9 ^* j
  34.       if ( v9 < a3 )  ?( l( }* q4 m/ A) {
  35.         a4 += 4;+ T# P4 o) L! E5 [; ?
  36.       ++v9;
    3 \* k) d7 ?  J, g  V
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);/ g: ]  j3 r; N: x3 Q9 ~6 m
  38.     }9 Y; K! q' Z, P9 h
  39.     while ( v12[0] );3 `5 Z& a- L& r  y( n  y, o9 Z9 P
  40.     glPopAttrib();6 x9 }5 |  b6 B9 H% w
  41.   }# G1 ?0 P) U8 `2 L. D6 o
  42. }
    4 d2 W1 [; E. r( k
复制代码
0 p. z7 n$ g! E6 n( h2 l
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
2 S: U' {  E9 g, F, V" a3 S0 w% v1 u
" L7 ]' b( D. w( ^
  1. .text:004512B1 52                                         push    edx             ; char *
    2 x7 I$ Y, |! x0 r$ Q: Q
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]
    + ]9 R' B8 q+ J; z) c# X' _2 t$ I
  3. .text:004512B5 50                                         push    eax             ; base4 f+ M1 m. `- Z0 U
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]1 m9 ]4 K& {* k& U3 f- E% M
  5. .text:004512B9 51                                         push    ecx             ; int
    ; _9 e% E" \, u! j2 ?, S
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]
    # K9 r5 [1 a8 i" U
  7. .text:004512BD 52                                         push    edx             ; int" m2 L- @0 S# v3 k: Q) B. K
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]9 Y  [2 x" t: C# `3 a2 w
  9. .text:004512C1 50                                         push    eax             ; int/ [5 k* W% J; u" {7 Q
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]
    6 `. M5 ?9 w- Z6 Q4 @- j
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]; z0 n. z: l* `. G5 f4 d
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C]. I" C2 u' T* N2 l$ D
  13. .text:004512CB 51                                         push    ecx             ; y
    2 d* n2 M5 B3 ~- l( y8 z
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]
    6 q) E* M& y, e4 y
  15. .text:004512CF 52                                         push    edx             ; int% J, N  k# P, ^. f% r9 K. D3 u5 l" X
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码
1 q1 y5 b+ q& E, l+ G
chatGPT整理过之后,如下$ v, L6 e9 ?  o6 k
- I, m. e/ U6 O% M% w
  1. void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)" N% O/ B, `# o9 P4 a: R8 g) X
  2. {& U; r7 f& ~1 {
  3.   GLvoid *textData;         // 存储字符数据的指针! M+ b$ ~, \. F  }. a
  4.   GLsizei textLength;       // 字符数据的长度5 [, {# q. l+ i: U) P
  5.   int lineIndex;            // 行索引! l3 o4 V+ E1 Y; t) ?) V
  6.   char formattedText[5];    // 存储格式化后的字符数据" z% ~, G" C! o& p/ ?6 L5 h* D' O
  7.   GLvoid *currentLine;      // 当前行的字符数据指针1 ]- X; y6 }1 |; M0 P$ a
  8.   char buffer[5];           // 字符数据缓冲区
    " p' k/ Y2 s8 Y5 j0 e% O$ U
  9.   va_list args;             // 变长参数列表$ A1 C( {( d0 u; b* m5 X2 K' K/ n
  10. 8 d& F0 ?" z, l$ Q
  11.   va_start(args, text);     // 初始化变长参数列表
    " B* ]4 @2 j1 ]
  12.   lineIndex = 1;            // 初始化行索引为1
    6 V4 D8 Q: q) S$ P& B

  13.   k  B  c1 N! }5 B% M* Q" i. n: d' S
  14.   if (text)                 // 如果文本不为空! z. p6 l+ }. A
  15.   {* z" E/ i! J/ u+ d1 t; ]
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中/ n) w# Z; S: R7 q4 h& B/ p9 B
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态9 L& t9 k8 k5 ^* K# o4 {
  18.     glListBase(displayListBase);          // 设置显示列表的基础值& W. v2 i. {& B4 R1 Q+ y, Z
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置. j) _  H& D& ?; r- L
  20. + p- ]1 m2 S  Q5 D: ?& h: c! X4 j
  21.     do; c+ o- i5 t, \3 t$ X/ d/ G
  22.     {
    $ V0 A, I3 Q; ]5 T& D
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素
    # w( T: g- G% p

  24. 4 ~- {/ W8 J" X/ N
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束
    " r. A' N9 ?; p8 y
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素
    + t3 Q: e3 v  ?+ L6 u0 g& ]

  27. + S; f$ s0 K% N$ F
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素: ?8 P5 u0 c  n- C) `
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符
    ! ]8 y+ x* R3 B. m$ g" W" @

  30. * \' [% v! l; C9 v$ V" L# v
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)! _. L7 ^2 Z5 J! g- L
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符6 L: [2 l$ N0 f( ^+ X( V
  33. ; ?. E+ J+ I" F! ^7 t2 J
  34.       yOffset -= lineHeight;                // 更新y坐标
    4 T5 O: r* p9 p  P4 a( R- L0 v: O
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置  }) F! }$ M+ J+ ^- p$ i
  36.       textData = currentLine;              // 将textData指向currentLine
    7 o# I1 K+ x; r: Z+ U
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    4 [! Z# c8 w) }8 S/ c
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表
    ' ~# T$ O1 Y. N2 P3 Z, m; O2 s( y7 w

  39. ) w+ z5 O5 O) F. a: t4 r8 K
  40.       if (lineIndex < numLines)/ F! e% p0 q! h+ a; G* ]$ x
  41.         lineOffset += 4;                   // 更新lineOffset
    # Y8 [4 y5 |3 }4 U: h; ?. W
  42.       ++lineIndex;                         // 递增行索引) N9 R$ C5 n  X/ E- }1 S3 J
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据
    ; `9 Y) \- ^0 p% q
  44.     }* [# W9 E! D: q! ?
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环, |. p7 _4 ?. }  N/ Y1 ?
  46.     glPopAttrib();                          // 恢复OpenGL属性状态. _, ^5 ]  W# I
  47.   }
    ; K& {) g3 g, b. }% C; Q' u, ~& `
  48. }
    ; k' J& F- ]- }" P' W
复制代码

9 E# Q2 |$ \  E0 N含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
% l: f" W% Y/ \. I
/ V) [6 [/ E6 y: u) \- j4 z4 hint xOffset,      字幕的x坐标
/ }2 t* S' e+ ?- s4 v& [GLint yOffset,    字幕的y坐标
) I  j4 k: A/ `6 i0 D8 \- ]# D4 j5 |, jint numLines,     字幕的行数(较长的字幕为2,一般为1): g# t% Y% W7 l! ^4 i
int lineOffset,   这个需要再研究
. e2 z( p. X" W/ ~& p. uint lineHeight,   字体高度(或行高)
  {: O0 q1 O" p; F! |/ jGLuint displayListBase, 这个字体对应的base值7 [$ d7 i& I) n9 ^
char *text, ...         字符串; ]9 Z) ]# t6 v# e. n8 `7 j7 w
: c! N* _1 i& j, [' }! S  R
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
 楼主| 发表于 2023-9-4 18:53 | 只看该作者
顶上来,顶上来
/ N# B" N8 j) Q5 H% I/ X+ o: }& J
回复 支持 反对

使用道具 举报

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

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