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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-5 16:49 编辑
: }9 c7 ]  M6 ]
* g5 U$ l) ^; o4 u8 Z这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎. p' {$ T( Q3 j! y! R2 J3 S' M
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
+ I4 v7 X$ G' s+ }$ Ghttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
% `- f+ W' R. T* l( W# _- A: S第1处
% X7 \  K7 y$ {
  1. void sub_451474(char *a1, ...)
    # b$ Z! P3 b2 P2 C8 f7 _: v9 O# `
  2. {. p! Q3 b" I7 ~
  3.   GLsizei v1; // eax1 q  P+ c$ ]1 m$ }! {" G
  4.   char lists; // [esp+4h] [ebp-800h]
    2 `# |* o, D* T
  5.   va_list va; // [esp+810h] [ebp+Ch]
    ; N, S0 U; q# Z+ I9 f- ?( b/ {" a

  6. + w# [$ I, w* }3 o  l- T
  7.   va_start(va, a1);
    % ^) I+ s- |7 u: {$ I6 r
  8.   if ( a1 )
    7 K( ~& J3 u; _8 h( M* F
  9.   {9 a& \8 a: \" @9 l0 o1 @* @; v
  10.     vsprintf(&lists, a1, va);
    8 U* _) S9 j: Q/ \) w$ Q4 p
  11.     glPushAttrib(0x20000u);, h) w6 l- f! Z7 w- P
  12.     glListBase(base);
    5 i1 m9 h/ D- X3 {: X/ h
  13.     v1 = strlen(&lists);' O" A$ r' s6 _' a: }2 h% {( j
  14.     glCallLists(v1, 0x1401u, &lists);8 Z* V, `, w/ G
  15.     glPopAttrib();& F% l3 P$ F# c$ H1 w
  16.   }
    5 P9 M" k- q2 n; k
  17. }
复制代码
0 d, d6 I6 |! z7 r$ k' n

3 z* M4 r$ ^. P1 g' n
+ w, T9 {) ~+ i6 L, A# n( Z) W! R, b第2处. T8 c# _- Y; P: Q! ]3 U
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
    + M* F3 O- L; d! i
  2. {
    . ~+ _* j) {4 {# y; M7 _# g+ d
  3.   int v4; // eax
      v. `7 I4 N' q
  4.   GLsizei v5; // eax
    2 p  ]) A- |- `& a. C
  5.   char lists; // [esp+4h] [ebp-800h]5 `3 W6 l2 P' f  k& `& ?
  6.   va_list va; // [esp+81Ch] [ebp+18h]6 }5 A" p, H% ^' q4 b+ {
  7. - Y4 t: h' q% P4 Z; a* v  U
  8.   va_start(va, a4);
    5 x4 I7 [% u$ {7 [8 a
  9.   if ( a4 )2 P1 i  V. S- p: ]
  10.   {
    4 g. W7 y/ v; I, ^
  11.     sub_44F8A0(a3);" l' I2 G9 ~& W" m* c( l
  12.     v4 = sub_40BB44();+ w% V0 |; p; c1 l
  13.     glRasterPos2i(x, v4 - a2);
    4 u) a2 Y4 Z3 \
  14.     vsprintf(&lists, a4, va);
    - O1 m; ]# u# Z. |. \2 \  h  c4 i1 V, ]
  15.     glPushAttrib(0x20000u);: Y7 `$ o: @; G# F% A5 M9 c1 d. j$ v
  16.     glListBase(base);3 p5 G8 C: n' z. n# Y2 l9 k
  17.     v5 = strlen(&lists);! H2 v8 n- j. Y$ J3 f' ~- I$ d
  18.     glCallLists(v5, 0x1401u, &lists);
    $ D  ]# m+ E9 l" [
  19.     glPopAttrib();0 d( @9 o: a/ _! k
  20.   }
    - g( q' d* ]8 E' @/ `6 p3 T
  21. }
复制代码

% }- V; ]2 \6 I
$ s0 j, a4 U2 x! Q# p+ d, S+ z4 e' }2 _" Z/ r. m
第3处* y/ Z% a1 U5 ?% @; h
  1. , C" j0 H7 X- y5 c( ^2 O
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)5 }. x6 _) O# d* c4 G, f
  3. {7 A; z. Z+ W2 D4 l4 _! Z
  4.   GLvoid *v7; // ST08_43 k: W' ]% R/ |2 I/ c
  5.   GLsizei v8; // eax5 K" m0 C. G8 _) O7 O) I9 y
  6.   int v9; // [esp+0h] [ebp-1018h]& e; l& y% T5 V1 v, N/ H
  7.   char v10; // [esp+8h] [ebp-1010h]
    ! z) W% U  M0 d
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]
    ; i. `+ T- A3 i2 a  h1 _, \6 l: ?0 q
  9.   char v12[5]; // [esp+1013h] [ebp-5h]
    1 P6 a7 L; X9 p6 S& h! t5 _
  10.   va_list va; // [esp+103Ch] [ebp+24h]) n) i: F! n0 t2 Y

  11. " @) f! f$ h2 d! r/ [* x* Y
  12.   va_start(va, a7);
    8 ?4 J1 i3 `4 m& G
  13.   v9 = 1;
    ( S- w) J0 V9 |! L$ W
  14.   if ( a7 )# e; r, _& J6 @, w
  15.   {
    " C% c0 k, R. S9 A& o  ?: T3 Q! y
  16.     vsprintf(&v10, a7, va);* N# A' m- q) v( l3 v( q9 H
  17.     glPushAttrib(0x20000u);
    $ ~# k& Q/ ]5 ]4 I, n5 O
  18.     glListBase(base);0 X4 L8 s9 i  [
  19.     lists = &v10;8 t* g# z: T5 ]2 J$ m- ^2 \: g
  20.     do" i* {6 j9 G) I$ Y! F1 Q8 p& N- V
  21.     {
    8 Q9 `0 o) b- h" G$ n
  22.       *(_DWORD *)&v12[1] = lists;
    / q/ U4 R6 X+ D& i; Y" L5 E
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
    ! l! C$ ]9 R5 K0 Z4 L! a: p
  24.         ++*(_DWORD *)&v12[1];) x3 m' }, j  g/ z! {
  25.       v12[0] = **(_BYTE **)&v12[1];1 `! j( _7 U/ Q) P8 _
  26.       **(_BYTE **)&v12[1] = 0;
    $ `' v8 }: O& z' q, [5 v7 @' c
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 ), h0 ~' I. q& I( v7 V3 S
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
    0 c! V- W4 m1 S8 r. r* _
  29.       y -= a5;
    - i) Q# m. {9 t: V; E& \
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);
    7 z1 E2 |; j) o. W/ h
  31.       v7 = lists;
    6 `6 Q! Q6 k# K) x; P$ f3 _" o
  32.       v8 = strlen((const char *)lists);+ z, C2 t$ K$ u) j5 |2 v# M7 |
  33.       glCallLists(v8, 0x1401u, v7);
    % b0 y; |8 q  |, l
  34.       if ( v9 < a3 )
    2 y8 r# O! T: _, ^9 i9 e. ^% w2 O
  35.         a4 += 4;
    , w+ O4 L( ^/ u7 G( p
  36.       ++v9;9 F3 A, C% V7 d$ H# `& [  |
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);; A8 {" E* N* e9 H6 k1 m. X: m8 k
  38.     }7 m5 K# a( q7 I8 g/ @  j0 c5 q
  39.     while ( v12[0] );# }* m# F' m9 f$ l
  40.     glPopAttrib();$ m' o' B& N# X- y5 ?
  41.   }( a+ O  V8 G* ?. k1 t6 g+ H
  42. }5 o, _. ^! F! z6 n# j3 y# w
复制代码

, C3 b' m8 D; l* |9 d. k; w调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
  a! T0 |" _/ n$ a' Y. a# Z9 b/ p/ L5 m4 b/ z% E
  1. .text:004512B1 52                                         push    edx             ; char *
    6 f; n1 L4 L. Y, J. |) b( |
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]
    5 A9 t3 L( i: ?0 O" a1 g8 a3 ^
  3. .text:004512B5 50                                         push    eax             ; base' v  V5 H: \3 c- \! j0 O
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]
    . d; P0 f+ U& p( r( H$ q
  5. .text:004512B9 51                                         push    ecx             ; int
    * ?' c0 ]( W* g3 X9 L0 J
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]+ d3 P% N9 {% {: A
  7. .text:004512BD 52                                         push    edx             ; int8 q9 s, z# Y! W0 v9 o" K( G/ J
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]
    2 r4 t1 U$ B8 O, K! e) B0 u6 i
  9. .text:004512C1 50                                         push    eax             ; int" W% n9 g- E' a
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]
    & C* }* q! v" K2 i6 @
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]; a( \- C" C: [2 r) c4 R( B# x- O
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C]2 t& K, k! m3 ?* C% X
  13. .text:004512CB 51                                         push    ecx             ; y
    " q+ n! X5 L1 l' D; B
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]8 r) d; r6 X8 }- `
  15. .text:004512CF 52                                         push    edx             ; int9 t( F: |8 T+ \2 E7 }2 w0 B3 s
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码
8 [4 S) B* k  r& r
chatGPT整理过之后,如下: n  p" w9 g2 r3 }9 j" _
  l6 k' S6 ?& Q7 b9 w/ G; o7 t! W
  1. void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...). D* I1 C- V0 e; w
  2. {
    - q8 D. s8 S: l; s9 f4 f/ s% M
  3.   GLvoid *textData;         // 存储字符数据的指针
    6 y9 s/ s$ j0 h0 a2 S/ h  D
  4.   GLsizei textLength;       // 字符数据的长度
    # q7 }+ g0 W) A2 w. T+ ]% `
  5.   int lineIndex;            // 行索引
    ( ]3 C+ H0 j# ]! o, B( f, |# p7 ~! O
  6.   char formattedText[5];    // 存储格式化后的字符数据
      Q  U- {$ A$ q+ n' j% c% i
  7.   GLvoid *currentLine;      // 当前行的字符数据指针2 Y) [7 H" E8 ?. [$ O
  8.   char buffer[5];           // 字符数据缓冲区
    3 l6 l7 P0 z7 {6 a% x8 T
  9.   va_list args;             // 变长参数列表# x2 {$ y# k8 Y( U8 i; N
  10. : g. ]8 X# z9 @: k- ]% M3 Y" k! x
  11.   va_start(args, text);     // 初始化变长参数列表5 M* {2 V& t* r+ w1 I/ {& y' W
  12.   lineIndex = 1;            // 初始化行索引为1
    ( C7 j, h. ?2 s* ~

  13. . O5 ~6 _0 \/ @( l1 R
  14.   if (text)                 // 如果文本不为空; M0 Q& t8 R1 b4 b5 W* v
  15.   {' h. ]9 q4 _4 i  f! p
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中4 j% Y! P; v6 G4 o/ A
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态7 ~  r1 [1 a2 a) c+ e
  18.     glListBase(displayListBase);          // 设置显示列表的基础值
    8 V: M: v- r. o# k2 L/ B% d8 w7 `
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置
    7 R1 m6 z: c, h( E9 Y, o$ {6 u

  20. 0 H2 {; y! f  L- `/ t! J( R; ?/ C8 C
  21.     do
    ) ]0 F" v1 g9 }) l
  22.     {
      K8 |7 Z3 M2 g4 ^* W5 M
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素
    8 f  T* l0 t8 ]& `( F0 X4 l" r
  24. % |* o4 ~/ x1 i
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束
    % n! t: r9 x9 [+ p) u! y: Y# i
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素
    ) u: h) n2 [+ ~! t6 b. n
  27. 8 K& }5 Z9 a, R: ^  U
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素9 K7 z5 Y4 m2 F! o9 Q
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符
    + t) G: N! a" o0 Z5 c; O7 P
  30. ! I. g( H" ~) r$ q" a! w
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)/ G6 e8 F- Z$ m' ?% t: }, f" n/ A
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符6 O5 Z" t0 x4 Z

  33. 0 f9 n5 B* H0 I% a4 A
  34.       yOffset -= lineHeight;                // 更新y坐标( |$ N+ w( O* l- S
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置. S- i: _& W# p/ W/ c- z6 Q6 {6 H
  36.       textData = currentLine;              // 将textData指向currentLine4 O# ]5 R: F6 J% l+ t2 b9 U9 S
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    5 c/ d9 Q) ?! f& y/ a+ y
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表) S4 i2 u8 P- E/ ~  I3 [! z, M
  39. # \' G8 {1 j% J  k) L
  40.       if (lineIndex < numLines)
    7 X0 w6 I) e+ i$ P& V' @
  41.         lineOffset += 4;                   // 更新lineOffset4 @% u5 J  U3 k7 c- S1 Q+ f
  42.       ++lineIndex;                         // 递增行索引
    0 ?- I4 p& \( Z8 ?5 l# \  P
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据9 ^5 D: @. l2 M
  44.     }6 `4 J# H- R6 V7 q/ E+ N5 o8 g
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环) ^$ o) `9 n0 h  l& Y
  46.     glPopAttrib();                          // 恢复OpenGL属性状态8 C' h( Z1 V* |0 U: g4 s
  47.   }5 I! H6 t7 t6 l# G
  48. }
    * t8 J1 l9 h( \! L% k9 r) A$ Z
复制代码

) s/ N% o: H/ J3 }! y含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
( g# ~2 h: F% o5 j$ a
. x# B5 k7 I4 ^& A! ^* yint xOffset,      字幕的x坐标" l: K- |9 [% {6 s1 Y9 X8 w5 }$ \
GLint yOffset,    字幕的y坐标
/ j' g7 T3 e( _8 }- W1 v' Iint numLines,     字幕的行数(较长的字幕为2,一般为1)
3 W1 S3 K( D1 nint lineOffset,   这个需要再研究2 r5 p3 P2 K9 n4 K9 G
int lineHeight,   字体高度(或行高)7 Y8 s) ~, T8 {! v* Z7 P
GLuint displayListBase, 这个字体对应的base值
. S/ d7 L' _# d8 |$ w% W  _" nchar *text, ...         字符串5 X1 t3 e9 o$ M! m5 h
, N' n$ P6 R7 u$ v& T4 ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
 楼主| 发表于 2023-9-4 18:53 | 只看该作者
顶上来,顶上来) b6 {+ M7 S* j# ^) q# V
回复 支持 反对

使用道具 举报

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

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