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

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

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

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

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

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

本帖最后由 shane007 于 2023-9-5 16:49 编辑 / C% L! I! e2 z, m$ f/ d. e, e

' Z- E' S! Z: I8 v" I! O这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎9 l" F0 N6 ], N8 q9 M
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。" P4 M3 V- _) ]4 |/ E8 v
https://www.chinaavg.com/forum.php?mod=viewthread&tid=1540812 L5 Y' m6 a0 Z9 o6 A
第1处
) A4 _& `6 X4 ^; L0 ?
  1. void sub_451474(char *a1, ...)
    6 O6 _1 b' e/ _2 S' V1 d/ _
  2. {( ^' U/ \, z- f( _9 z. v# u: X
  3.   GLsizei v1; // eax
    9 y" E, A# i6 k  k$ P2 Q- A
  4.   char lists; // [esp+4h] [ebp-800h]! z$ Q7 k; h! w* ]3 t; o) H7 ^. F4 I
  5.   va_list va; // [esp+810h] [ebp+Ch]
    2 X8 {$ U) z+ T% m9 ?! l5 B
  6.   R7 X$ o6 |  E$ F& `  u
  7.   va_start(va, a1);9 i9 ^+ m9 d# r# n" f- m5 u
  8.   if ( a1 )3 K& b  w. H4 {
  9.   {( O, H( H' t, W; ~( X# L
  10.     vsprintf(&lists, a1, va);. {* Q& c& d1 p+ p& H
  11.     glPushAttrib(0x20000u);
    ' ?. o: Y2 W. s% A  b
  12.     glListBase(base);( `" C  i" B/ ]; @: Y9 Z3 ^
  13.     v1 = strlen(&lists);4 E* n# c. [7 ?. j  D$ u
  14.     glCallLists(v1, 0x1401u, &lists);
    - `8 |# ^, I* F7 _3 x5 P, J
  15.     glPopAttrib();, ?! g( n3 T- }! ?# I
  16.   }
    , D" a" O6 R" o8 k
  17. }
复制代码
: \6 a- R/ y2 x

7 l$ Z* J. t5 U
3 a* C# t0 g( y& M3 H3 e; o第2处
) x- Q( `9 Q# D5 D; E7 P
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
    ) @! b+ J$ D+ \) U
  2. {
    1 [+ n2 p: f$ K6 a* @
  3.   int v4; // eax# ^8 X( z% M% w- m) z8 C( @# D# g0 B
  4.   GLsizei v5; // eax5 D! k- F& z0 |2 p3 @) p8 ]% o
  5.   char lists; // [esp+4h] [ebp-800h]
    $ H4 i2 K# D4 s3 y
  6.   va_list va; // [esp+81Ch] [ebp+18h]# B; P+ k9 }; h$ g. x8 b9 z0 i
  7. & P1 a) S# N, @7 l, M  z
  8.   va_start(va, a4);8 {5 ~$ A' |. b8 U+ [  G
  9.   if ( a4 )& s% `% v. Y0 x- w, b% d* T$ i) m
  10.   {5 d7 k6 U  `. t/ ~1 P! w( l& A
  11.     sub_44F8A0(a3);
    % g! q. x( o% d- e3 s
  12.     v4 = sub_40BB44();
    $ _6 P1 ]: Z' u) D: C; H- {
  13.     glRasterPos2i(x, v4 - a2);, v7 o0 }. H$ Z, z* S8 N
  14.     vsprintf(&lists, a4, va);
    ) K3 g% t8 x% j
  15.     glPushAttrib(0x20000u);
    $ @6 l5 b9 T+ d6 m
  16.     glListBase(base);
    . B9 y+ s5 S4 Q. d
  17.     v5 = strlen(&lists);
    # R) ?# o1 N* ~7 t) k" c! G8 G
  18.     glCallLists(v5, 0x1401u, &lists);( F: u$ ~6 P8 t% a3 |
  19.     glPopAttrib();: i% o2 X" [0 X: P0 ]! F
  20.   }5 B  Y' ^1 O3 ~6 F
  21. }
复制代码
# \  ~6 U9 `- M- T

; K% ?$ _9 r/ J  m/ ?3 G
5 h( Y" T, Q& E( A" u第3处. k8 H0 x9 I# G7 g2 J8 J

  1. , u0 u2 ^) A1 W7 o7 n. ~( c, ~5 z3 V
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)/ }* H: m0 A( A4 E$ W# m
  3. {( z/ Y1 h! Y9 r
  4.   GLvoid *v7; // ST08_4% s4 a. _  j# M( m
  5.   GLsizei v8; // eax
    $ k' F- u7 i1 d3 o  U
  6.   int v9; // [esp+0h] [ebp-1018h]
    2 ?# p. Q0 x6 F+ i
  7.   char v10; // [esp+8h] [ebp-1010h]4 q- a2 X3 p/ d! h" D
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]
    1 E7 c1 H4 v! ]- x
  9.   char v12[5]; // [esp+1013h] [ebp-5h], g0 }3 g! W5 T1 c: o; V  u5 l
  10.   va_list va; // [esp+103Ch] [ebp+24h]
    ( Y) U4 n' f' g

  11. - V+ [1 J9 w* h1 H7 l
  12.   va_start(va, a7);1 L; o8 H! c3 H0 Z# f
  13.   v9 = 1;7 `* Z* X: ~; h
  14.   if ( a7 )# t5 B+ c9 C5 E" ~3 d) z& j
  15.   {
    2 w% i, ?( @3 L5 w
  16.     vsprintf(&v10, a7, va);
    5 e4 z( R1 h$ ?* \% C- {
  17.     glPushAttrib(0x20000u);
    : O# N' I0 Z% y1 F! ?
  18.     glListBase(base);
    ; n" q. N- P# ^* Z* h3 @7 q  Q* o
  19.     lists = &v10;
    ; g6 u/ L) m. r2 `2 s$ C+ ~
  20.     do
    " n  d- T/ b7 F% }. c: J# G; p4 b
  21.     {
    ( m/ X9 f; s  f! [
  22.       *(_DWORD *)&v12[1] = lists;
    2 P. i& X1 k& _3 f% b/ w, [
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )2 F/ I6 L5 |" P
  24.         ++*(_DWORD *)&v12[1];" a  p; {' \+ L# V" M6 C5 J
  25.       v12[0] = **(_BYTE **)&v12[1];
    * A, U7 q7 y/ M# s6 A2 `% q
  26.       **(_BYTE **)&v12[1] = 0;" l1 F' |8 C. t6 G
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )  x- [+ D  J4 S. t
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
    " i" s8 V4 J) k) {
  29.       y -= a5;
    : k3 \3 _9 s0 g# {; b
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);) T3 A% ^9 U9 H
  31.       v7 = lists;
    ' t; g! {9 t( J( V* x0 _
  32.       v8 = strlen((const char *)lists);4 Z8 Z2 l* C5 l# }
  33.       glCallLists(v8, 0x1401u, v7);
    - A# r$ [) B+ N! b- \4 k& N: K
  34.       if ( v9 < a3 )
    % A! W4 d! Q2 j
  35.         a4 += 4;, ?$ s1 u( {) o
  36.       ++v9;0 T0 [' \$ p& C; h4 U
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
    ! ~; T) @. ^+ ?5 a# n# A
  38.     }, e. _+ v, G% i5 ~5 @/ t1 E
  39.     while ( v12[0] );
    " M8 w1 \+ Q! ^+ V+ ?6 N6 M
  40.     glPopAttrib();
    - F: r0 v6 q: A, `
  41.   }
    ! R8 ?; S- B; a2 s0 D$ D
  42. }) K" S3 d/ E7 P, v3 A
复制代码
# h2 m3 {8 s" e; x4 I) {2 ?2 H4 L% a
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810, o# f* v2 g% e) P! v1 D$ \3 f

4 ?0 u) ?$ v/ p! E5 J2 L% l+ M* R
  1. .text:004512B1 52                                         push    edx             ; char *% |  ^: T( h( E8 Z( x+ J
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]
    2 }! ^2 H1 C4 @. k9 S7 f1 S9 R
  3. .text:004512B5 50                                         push    eax             ; base) z8 ~8 T0 Y: q) E
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]
    ! M$ u$ _- ]) r% |
  5. .text:004512B9 51                                         push    ecx             ; int
    $ u; g; N4 U, n0 T/ J  c
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]- t- v$ F7 z  b0 I
  7. .text:004512BD 52                                         push    edx             ; int9 e8 w% r- v1 X# q1 X) c6 U% i2 K9 q
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]0 E1 s; J7 h; y- f8 @6 W
  9. .text:004512C1 50                                         push    eax             ; int
    + e9 Q. S5 G' w
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]
    + E/ w1 S' }  E
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]
    : S: Q, d: A9 t
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C], v2 w+ I* y9 ^3 k' c/ m* P; a
  13. .text:004512CB 51                                         push    ecx             ; y
    7 b$ f+ W7 G, S' i& M1 ]+ h: G6 Q
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]
    8 |' M! W8 R* U
  15. .text:004512CF 52                                         push    edx             ; int- l% ?& N1 Z! E
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码

9 \- @2 Y$ ~* H, c& A) Q& J& \5 ]$ @chatGPT整理过之后,如下
9 k! D8 }0 A  D" u. [# v" `# s- Q" D/ U
  1. void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
    1 c, ~0 R6 u3 x5 c/ g. A
  2. {
    6 d; n( m0 M9 ]! B; v- U; Q
  3.   GLvoid *textData;         // 存储字符数据的指针
    + w( n) i+ A2 [( ^9 p
  4.   GLsizei textLength;       // 字符数据的长度: m5 o2 o+ ?7 w5 I: |6 n
  5.   int lineIndex;            // 行索引
    $ j' c( i( P' L/ d7 }2 G$ @$ ^
  6.   char formattedText[5];    // 存储格式化后的字符数据
    ! Y9 B7 F9 W  X1 I8 |" _
  7.   GLvoid *currentLine;      // 当前行的字符数据指针
    & Z. C# T: t1 n9 X& r; e) T% z
  8.   char buffer[5];           // 字符数据缓冲区! P! w' t" r3 n9 y
  9.   va_list args;             // 变长参数列表" x1 Z- {. E# a1 w* K2 }  p& W
  10. 3 f: q. W* ~( }) B: @
  11.   va_start(args, text);     // 初始化变长参数列表, n! o+ V0 g- p4 b7 z
  12.   lineIndex = 1;            // 初始化行索引为19 h( p- s8 J  |! K+ `, i

  13. ) {0 W3 ]1 t5 S/ T- l2 b
  14.   if (text)                 // 如果文本不为空8 d! s4 m. S! l
  15.   {; `9 P% y. g: P0 Q3 v/ X( f" V, R/ q
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中( f- U8 J8 U4 o: w& {
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态
    - x( y0 h) O0 c, r8 }- T
  18.     glListBase(displayListBase);          // 设置显示列表的基础值
    # \, H1 p" @/ B# h+ Q# T8 w
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置
    5 \' R# E: v* x- J

  20. " g* K) U7 n5 u, C, H
  21.     do
    & d2 t% \( H) ^4 c- y* S3 g7 H, l
  22.     {' R" [+ x- G% [" `
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素
    : I/ p: T! n, |$ I( N3 f( r& B

  24. ' ^  `4 Y) x/ y
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束; f1 J2 l  i. B; W- b/ f, L+ R! G( e
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素8 a; e7 T' N: J$ H

  27. ( s3 t9 c* f( w1 q% S% u% @% V
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素/ B* S9 k3 B! i3 M# o
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符6 `5 c: I& J8 e8 y* L  b9 X. w6 S
  30. 1 P3 s& C; f0 r( r6 s8 {9 K3 b( L4 f
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
    0 j0 C. O% G: }& y2 m" g
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符
    / }7 a4 ^, x0 M0 C& D
  33. 9 M% w: Z- u0 p  A6 f
  34.       yOffset -= lineHeight;                // 更新y坐标
    - _; w$ Y  ], w
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置1 _" U0 l5 |  e% L4 Y& Z
  36.       textData = currentLine;              // 将textData指向currentLine
    1 v- r& y% p# w% d3 K
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    . M- O& N1 o( T0 G) x& N
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表
    ' f% }% L5 D* m' \0 S3 l/ ?

  39. : u8 P, p) ?# a; L, \( q- I) N
  40.       if (lineIndex < numLines)
    : O# |# R, r- w3 l5 G
  41.         lineOffset += 4;                   // 更新lineOffset
    : m5 R; Z+ i% U$ M% [/ }  ]5 N
  42.       ++lineIndex;                         // 递增行索引& [7 k( f. O8 r' C: I- |
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据
    ) X  b0 p( f7 N8 {1 p5 v8 j+ ?
  44.     }
    3 k& |1 y4 T! y: w6 ~7 u
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环0 k* m% Z) f7 R
  46.     glPopAttrib();                          // 恢复OpenGL属性状态
    1 [5 T, @1 K* ]2 C( V+ E
  47.   }
    " U6 t/ I- f! C8 {. ?
  48. }
    4 |8 W4 {1 d5 q6 e" J
复制代码
& a! V# I% R1 {/ L8 j3 C3 I8 p( N+ P! A
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
" l% A' ~0 n1 o& S2 F, x( z# n, p, N/ p9 a! E
int xOffset,      字幕的x坐标
' E+ x3 C; K$ Z  f4 UGLint yOffset,    字幕的y坐标
8 \4 r: D% m" T9 X- Y) `$ L1 J3 i. [. Yint numLines,     字幕的行数(较长的字幕为2,一般为1)
0 Q5 z" Y4 V/ ~1 I, Mint lineOffset,   这个需要再研究
3 ?/ `1 X$ \% C0 }/ G6 {6 N  O- wint lineHeight,   字体高度(或行高)
" C" Z7 b: p9 s! yGLuint displayListBase, 这个字体对应的base值
' a6 {) O" d; w$ P& mchar *text, ...         字符串6 s' I9 c% m+ {, h" C1 d4 |

& Q" A( M: s& l7 D
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

沙发
 楼主| 发表于 2023-9-4 18:53 | 只看该作者
顶上来,顶上来
6 m% j/ b9 K$ Z% d$ Q
回复 支持 反对

使用道具 举报

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

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