冒险解谜游戏中文网 ChinaAVG

标题: 【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数 [打印本页]

作者: shane007    时间: 2023-8-27 13:49
标题: 【Opengl游戏汉化 #5】 尼比鲁:秘密年代 (NiBiRu)字幕显示函数
本帖最后由 shane007 于 2023-9-5 16:49 编辑
) A3 f9 n& W+ H# m
; M: w; h! m1 b这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
& o) ]0 C" H, F: I: U& z  p因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。. @5 ?9 T/ {/ x$ w* j7 I( v; W* B
https://www.chinaavg.com/forum.php?mod=viewthread&tid=1540812 V1 f% _7 D: C2 M
第1处. u* v- c5 s/ [- e2 P! m) O. D/ l
  1. void sub_451474(char *a1, ...)
    / B3 i' g, Y+ y# A8 U+ G  W1 N
  2. {/ O+ }+ S0 K+ |$ d) y
  3.   GLsizei v1; // eax
    : x' w' u- Q( v' @! P
  4.   char lists; // [esp+4h] [ebp-800h]
    ) E+ N- j  a: ^# H3 q+ c0 U$ @1 D
  5.   va_list va; // [esp+810h] [ebp+Ch]
    7 |8 Q% C. G$ A' D4 m& V$ H

  6. " I! z& E) f% Z9 s4 e: x  S/ g
  7.   va_start(va, a1);
    , r& ~8 ?5 `, l
  8.   if ( a1 ), n3 w. ]  X5 S( x% a3 E
  9.   {$ u1 ?: v1 _( B. \0 T
  10.     vsprintf(&lists, a1, va);
    4 X+ G0 N) N  Q4 B/ \
  11.     glPushAttrib(0x20000u);' `, @0 ?) ?3 ]$ a2 r
  12.     glListBase(base);
    & W! z* ^& D0 _* N$ V* `6 G
  13.     v1 = strlen(&lists);" W% D* {; j4 r' d! h) R% H8 h  l
  14.     glCallLists(v1, 0x1401u, &lists);
    + K! m2 n/ ~& \( Z0 s; I" @4 r- j
  15.     glPopAttrib();9 {( K/ y: M3 I
  16.   }
      f: O2 s3 i1 o. E8 i0 b
  17. }
复制代码

0 ]4 `+ b8 a6 C" L1 `- t& n1 J) i- u% M; z& Q

0 C% T* @; @: b& w7 N/ M1 b第2处
; m% C& Z0 G' n4 L+ f3 P# _8 _
  1. void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)! @$ K$ P2 b  ?
  2. {% |8 P# c+ }- G6 i% g! F
  3.   int v4; // eax
    & f1 j6 ~, y3 }) F) T1 o% t
  4.   GLsizei v5; // eax& M( Y$ U  u$ G' O
  5.   char lists; // [esp+4h] [ebp-800h]
    & k! F7 b, D/ V3 o% [
  6.   va_list va; // [esp+81Ch] [ebp+18h], c* s& y* a2 Y; [

  7. 4 u# a( S3 d3 }) N, i* W8 P; a
  8.   va_start(va, a4);0 z4 a) p" o; M3 U6 {, f  e
  9.   if ( a4 )+ V# n( c& d9 Q& Q
  10.   {# k  ?% I; V% l7 g- y& q; `
  11.     sub_44F8A0(a3);
    ' _% I* ^# O( K- x
  12.     v4 = sub_40BB44();/ ?( u' U, O" l1 e
  13.     glRasterPos2i(x, v4 - a2);4 k+ C8 N/ a$ ?4 }$ w% I* N
  14.     vsprintf(&lists, a4, va);- C) i: _- R: a* ^
  15.     glPushAttrib(0x20000u);
    1 S' `; @% h: X
  16.     glListBase(base);/ g  A; _( T8 L8 a
  17.     v5 = strlen(&lists);
    ! H0 m4 L) E. f
  18.     glCallLists(v5, 0x1401u, &lists);
      I4 r2 v2 Z# ~* I
  19.     glPopAttrib();
    0 g5 S+ B* r0 R
  20.   }$ q: E5 l; P. U3 b5 I
  21. }
复制代码
) @5 B9 Q& W# p- p/ g* T

+ f! R# x) A2 T8 e2 J" T, \* K) H; Q+ B* Z
第3处% c! I( S2 s8 c+ p. I4 z
  1. , l% F5 }* G9 @+ E, H( ]3 I( j
  2. void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
    $ Z# m% w, w/ a* ^0 }) w: p7 f
  3. {
    . z* Q9 q- J4 i, w, W' P+ A
  4.   GLvoid *v7; // ST08_40 e! P" S! p- S1 x  I7 D5 A
  5.   GLsizei v8; // eax
    2 X9 X: _& w2 f# x; K; c# R# n
  6.   int v9; // [esp+0h] [ebp-1018h]
    ! {& C& K; f5 [2 o! P
  7.   char v10; // [esp+8h] [ebp-1010h]
    $ P6 `% x6 f+ \2 Q- @9 R% I' }# `/ C
  8.   GLvoid *lists; // [esp+100Ch] [ebp-Ch]
      ]) q7 \$ k7 z! q
  9.   char v12[5]; // [esp+1013h] [ebp-5h]* G6 _. q) i: y5 X1 o
  10.   va_list va; // [esp+103Ch] [ebp+24h]7 E" c- Y( s# {3 m' N9 n. d
  11. 2 n3 X. i+ ^* R5 a% O* W3 h% y0 G
  12.   va_start(va, a7);
    4 |& G" f- B+ p6 K' g
  13.   v9 = 1;! ^4 i0 y! p7 J5 Z  m8 {
  14.   if ( a7 )# q; N: n( H) q: Z5 f8 Q- @
  15.   {
    ; h% a' s& O: X
  16.     vsprintf(&v10, a7, va);" T% K8 f4 P7 |5 M
  17.     glPushAttrib(0x20000u);4 J5 x! I/ P$ J% r5 J
  18.     glListBase(base);) y/ \; _1 A3 m4 p& R
  19.     lists = &v10;( `) {1 Q) Q. q1 ?9 c) k# p
  20.     do
    0 Z' Z5 h5 ?' T8 ?# [, O
  21.     {/ i. A  B# e& p( c( K$ f
  22.       *(_DWORD *)&v12[1] = lists;& n+ t. i: B; o  y! h8 O1 G
  23.       while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
    9 H1 @/ e+ A, [. K( i0 G* N' I  R
  24.         ++*(_DWORD *)&v12[1];2 W( {9 G' x1 c2 h1 x
  25.       v12[0] = **(_BYTE **)&v12[1];
    - U+ Z) @; \0 L3 q) l/ p
  26.       **(_BYTE **)&v12[1] = 0;
    1 j; M- y8 a  D: @" Y% U1 m
  27.       if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )+ v0 @! }$ ~$ v/ F: ?
  28.         *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;! b4 u* M( a7 h% ?8 G/ Q" s; B# m
  29.       y -= a5;
    ) ~( p! j$ u9 B$ {. U1 n2 X
  30.       glRasterPos2i(*(_DWORD *)a4 + a1, y);
    . I) \; e8 ?! X% y& `. N! W  Y% t
  31.       v7 = lists;
    4 ^& r+ C2 I" {  X% w
  32.       v8 = strlen((const char *)lists);+ F5 ?" ~4 r8 l  \
  33.       glCallLists(v8, 0x1401u, v7);0 `& f& {3 L5 a' Z% r- f7 g
  34.       if ( v9 < a3 )0 [3 r3 J4 C9 y( M
  35.         a4 += 4;
    1 i& w1 A2 ~: z6 |/ Z! ]
  36.       ++v9;% G/ w* _# g) _. H( X* A
  37.       lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);8 w9 s( @1 M/ }+ p* D; S% ^' c
  38.     }
    ! h5 W2 j) @6 |" D. u% q
  39.     while ( v12[0] );' v0 }2 p% D) U8 c( p  w' C' t
  40.     glPopAttrib();0 k+ L. v9 }0 }
  41.   }
    . o+ M" I' o7 e7 y* ?  c
  42. }5 ?5 J  H; E" ]5 [! s& a; t
复制代码
# q, e2 K& Z% l: z
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
# i9 R5 `* r2 E" G# P' F! B) h0 Q: Q4 {
  1. .text:004512B1 52                                         push    edx             ; char *
    " S8 O7 N; I9 y
  2. .text:004512B2 8B 45 30                                   mov     eax, [ebp+base]
    ! [) F4 }2 H8 o0 a
  3. .text:004512B5 50                                         push    eax             ; base) v0 G/ Q2 _% L6 A# f* s
  4. .text:004512B6 8B 4D 20                                   mov     ecx, [ebp+arg_18]: \* W6 k# p2 Y/ N  l
  5. .text:004512B9 51                                         push    ecx             ; int
    ' @* |' z' f9 Q# V# q7 w: b- _- G# d
  6. .text:004512BA 8B 55 1C                                   mov     edx, [ebp+arg_14]  \, y  @5 M. f8 Z; o0 W; O
  7. .text:004512BD 52                                         push    edx             ; int
    2 K+ t. k0 i& g- C% z3 q: r
  8. .text:004512BE 8B 45 18                                   mov     eax, [ebp+arg_10]9 l# c! v9 g5 ^0 _7 \
  9. .text:004512C1 50                                         push    eax             ; int7 B8 O( V; B( f6 f$ }& k3 |
  10. .text:004512C2 8B 4D 0C                                   mov     ecx, [ebp+y]' e" z. y) \) a
  11. .text:004512C5 03 4D 14                                   add     ecx, [ebp+arg_C]
    & ^; p. _9 r. R+ J% v/ {# X
  12. .text:004512C8 03 4D 24                                   add     ecx, [ebp+arg_1C]" A& I9 t4 K. j4 v7 X* C- y
  13. .text:004512CB 51                                         push    ecx             ; y
    , u: w3 ^, [5 ?* `9 c7 c) x& B
  14. .text:004512CC 8B 55 08                                   mov     edx, [ebp+x]
    6 ^. m/ E, _0 ^
  15. .text:004512CF 52                                         push    edx             ; int2 L7 U+ ?% ^3 R# N, w  E
  16. .text:004512D0 E8 3B 05 00 00                             call    sub_451810
复制代码

; J1 i6 l! t2 t, ]chatGPT整理过之后,如下; W9 X% I/ ]3 h# D" f' q  B

6 v0 M# Q+ A3 a" F+ z
  1. void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)% ~' D6 }- t7 }8 q! Z1 a
  2. {: ^$ g5 w8 [3 T3 @
  3.   GLvoid *textData;         // 存储字符数据的指针" M" E8 Q+ Z+ h; g( C& f; y& N4 E
  4.   GLsizei textLength;       // 字符数据的长度
    , o* d' O: }0 E* p
  5.   int lineIndex;            // 行索引
    # `$ R8 A2 X5 }% g6 N5 D# l* H" S
  6.   char formattedText[5];    // 存储格式化后的字符数据% @# t9 N' v) H* N! ~
  7.   GLvoid *currentLine;      // 当前行的字符数据指针5 o# b) X/ E6 B. _0 _2 t: y
  8.   char buffer[5];           // 字符数据缓冲区' Q! e+ Q- T! v: K8 w
  9.   va_list args;             // 变长参数列表2 i/ P0 x& V8 y- v/ T
  10. ! v8 y5 b  j. o/ n
  11.   va_start(args, text);     // 初始化变长参数列表
    2 r5 J0 c* i# e
  12.   lineIndex = 1;            // 初始化行索引为1! }% c3 f) a& Z# {
  13. / V- x2 E' `, P7 x$ e
  14.   if (text)                 // 如果文本不为空! T3 S; W4 J' X6 r; Z# U, O/ L1 M
  15.   {
    , x4 E( ^+ f- I4 t% V
  16.     vsprintf(formattedText, text, args);   // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
    ( w) J% J& Z) K1 e* ]7 Z. e
  17.     glPushAttrib(0x20000u);               // 推送OpenGL属性状态! H: o( Z2 L2 c( T  F4 `) d
  18.     glListBase(displayListBase);          // 设置显示列表的基础值
    : C4 U7 @, e5 g2 A0 [" S9 W- {
  19.     currentLine = formattedText;          // 将currentLine指向formattedText的内存位置
    9 F7 D, J0 U1 ~
  20. 0 X$ b4 U. O6 {2 W
  21.     do; y0 V! \; f, Y. p# Y0 ~& O
  22.     {5 @: h9 A+ k$ W
  23.       *(_DWORD *)&buffer[1] = currentLine;   // 将currentLine的内存地址存储到buffer数组的第二个元素
    . L1 _+ E% a% \$ c. J. h* M
  24. 2 U7 p  J/ ?9 n
  25.       while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10)   // 循环直到遇到换行符或字符串结束
    3 z; P8 [: ]0 Y# @
  26.         ++*(_DWORD *)&buffer[1];   // 递增buffer数组的第二个元素
    6 t. G  r0 t9 ?+ ?
  27. ( S: l: j+ a# ?" R1 d& f
  28.       buffer[0] = **(_BYTE **)&buffer[1];   // 将换行符存储到buffer数组的第一个元素
    , G' v  ^7 p# ~& i; a8 g8 |0 w
  29.       **(_BYTE **)&buffer[1] = 0;           // 将换行符替换为字符串结束符
    8 X% N- b+ W3 Q. v4 j

  30. 7 D' s0 c# P: a
  31.       if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)  q& _* G; E  t& k8 Q* R
  32.         *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0;   // 处理换行符和回车符
    4 j9 E$ u3 W8 I* r4 u0 m4 ]
  33. 6 S" v- \% ]8 F" |
  34.       yOffset -= lineHeight;                // 更新y坐标
    6 T8 T! @% t) T+ J% h+ X5 ]  r4 O
  35.       glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset);   // 设置光栅化位置/ F) i! H; a( U8 G5 q+ t
  36.       textData = currentLine;              // 将textData指向currentLine
    / y/ B' f$ h  q, X. L3 E1 I
  37.       textLength = strlen((const char *)textData);   // 计算字符数据的长度
    ; a; G( e" ?' l4 G( Y
  38.       glCallLists(textLength, 0x1401u, textData);    // 调用显示列表
    $ u; X. W4 b1 N( K

  39. 5 ]6 n9 v) a  _' C/ V7 p
  40.       if (lineIndex < numLines)
    ) H2 |0 l2 B& |  v
  41.         lineOffset += 4;                   // 更新lineOffset. L* o2 Q; v( C
  42.       ++lineIndex;                         // 递增行索引4 [" t0 q" d, E7 K
  43.       currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1);   // 更新currentLine指向下一个字符数据) E) c6 H* Z- B; I5 l/ ]5 F5 v
  44.     }& W+ D* r. w! y! ^4 ~
  45.     while (buffer[0]);                     // 当字符数组buffer的第一个元素不为0时继续循环
    & p9 T) l. e( `* f0 u1 U% _
  46.     glPopAttrib();                          // 恢复OpenGL属性状态' A# H1 q1 w) P6 h* W+ A" e
  47.   }1 ~  R! X  n- F! N4 H
  48. }5 B4 z  J6 h% N) L5 H% J
复制代码
) M/ I; g% g* g, B& c
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
% P8 e# j1 g( Z; q7 m& [
; p- N0 x; S+ c* R  u0 lint xOffset,      字幕的x坐标3 M$ a$ K% Y8 ^  {+ X* y- D
GLint yOffset,    字幕的y坐标
- K6 V. T3 W3 A% y' Nint numLines,     字幕的行数(较长的字幕为2,一般为1)3 p9 U  Y( b  U- a
int lineOffset,   这个需要再研究
' e6 B% b2 W8 Q- u( Eint lineHeight,   字体高度(或行高)
% W' r, A5 A" g2 b: c+ GGLuint displayListBase, 这个字体对应的base值3 c. a3 e! h, E4 X% o1 P6 ?
char *text, ...         字符串8 l! e' g+ M  G( `# t: q

" a" ~) v- c) x# C3 q9 o
作者: shane007    时间: 2023-9-4 18:53
顶上来,顶上来* j- I) ^- d5 J$ _





欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/) Powered by Discuz! X3.2