本帖最后由 shane007 于 2023-9-5 16:49 编辑
, S8 j) c! K' s1 [2 k( G* x3 q% X
9 l+ \) @& b, ~) X0 J+ ^这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎+ W; l/ [- t" K' V
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。& ?) k2 r* ^2 w+ G9 {
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081 _5 ~3 S$ r6 W. w5 Y0 a! k
第1处$ u; c2 K; k1 S; ?
- void sub_451474(char *a1, ...)
. V3 y! z2 K- u, y - {
H4 L7 e- p# U; D$ u$ t9 u - GLsizei v1; // eax* J; }4 b" Z- o* J+ |& P
- char lists; // [esp+4h] [ebp-800h]6 V3 Z" I) g& f I# x
- va_list va; // [esp+810h] [ebp+Ch]1 ^; l. A( e* N1 z7 R$ s
h, c6 Z2 a# t4 O% l' H, j R- va_start(va, a1);9 d* X1 h# l7 G) R
- if ( a1 )" D4 l2 }, {6 V# v5 R
- {
! C" |, g# R. C) y( L* M H; | - vsprintf(&lists, a1, va);
2 K; i: O1 w% b& n - glPushAttrib(0x20000u);
- e2 k2 ]( q$ T' [4 N" Q5 H: Z - glListBase(base);
7 Z/ [- @4 ?6 a8 e3 g2 w; ~ - v1 = strlen(&lists);8 N2 [$ z4 J4 q! ]8 x4 ?& k
- glCallLists(v1, 0x1401u, &lists);. H6 x7 d- m9 ]8 H2 j: ]
- glPopAttrib();8 p# C% u+ t" }4 ?/ T# Q
- }
' t o N u8 m - }
复制代码 * }8 C8 J$ G! p2 f
+ p+ l, _3 W( F/ f
) z$ @' k0 |3 d1 \( n( Q6 N" ~第2处; b0 d @: A! O7 G' F; g& [
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
( O% G, |* S7 |2 p, m/ J6 e1 L - {: ]+ I: g% o7 t
- int v4; // eax" n0 {/ e, c; D0 p, v4 E7 o; V
- GLsizei v5; // eax/ b" j" F& x8 y; M+ B
- char lists; // [esp+4h] [ebp-800h]
0 U$ x( e; Z/ E+ e' U; { - va_list va; // [esp+81Ch] [ebp+18h]6 H4 s# s& \. F; b; \2 }
- # O" `3 r( g+ H0 M9 s
- va_start(va, a4);
+ F# _6 D e: b# `( L: C! _# X - if ( a4 )# k) f. z' ^, }. n- k1 J; M
- {# `* i% O# y+ |2 P( ^+ U: U* X
- sub_44F8A0(a3);" ?: |- W* s+ |/ R, u
- v4 = sub_40BB44();' a) X. L. r- j1 V1 z
- glRasterPos2i(x, v4 - a2);
7 B# a# R. y% e3 D% U( w* l - vsprintf(&lists, a4, va);
5 t1 W4 K3 Z% G4 P - glPushAttrib(0x20000u);4 p" k7 Q9 O- W* V7 g! j9 _' Q
- glListBase(base);
! I, J" C4 f% v1 F7 ^4 G9 h6 d' g) Q; i9 I - v5 = strlen(&lists);
y+ p5 j; N2 o, j9 y3 S& x% x5 D0 E - glCallLists(v5, 0x1401u, &lists);
$ k% ]$ [" e7 I7 j5 u) ] - glPopAttrib();
* E: m5 Q" P9 t. }1 H - }
! K0 p8 c% w. L- ?2 C - }
复制代码 2 P( z# h5 M1 m ]. r
: Q/ ~# {( X& W4 S2 b2 s# Z, O/ V4 [% W `, X, ^
第3处1 V; N; b- i/ ?5 z" M
8 t( e; @4 ~9 b- \$ _0 |7 K- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)3 B9 D% \1 D, T, V0 P5 j
- {
+ X' M$ N# V) R' e. l2 Q# q3 E/ t5 N - GLvoid *v7; // ST08_4
% s1 U/ i# o6 A! o - GLsizei v8; // eax2 J- F4 d; m8 w1 C5 V: W
- int v9; // [esp+0h] [ebp-1018h]
4 x7 p( [0 p4 ]1 O- p6 H: }7 g2 | - char v10; // [esp+8h] [ebp-1010h]
1 F W' V; i+ |: [. K2 h( w - GLvoid *lists; // [esp+100Ch] [ebp-Ch]3 O/ @; A1 B- K$ r( _9 N0 l
- char v12[5]; // [esp+1013h] [ebp-5h]& L# L7 X* z& }! N. ~
- va_list va; // [esp+103Ch] [ebp+24h]
5 ^9 Z1 {9 [* k& |1 i# C - ( a( l# q! y& g5 c. y
- va_start(va, a7);
# K, X a$ F5 V - v9 = 1;
! D( I7 f# E; Q) @" |4 X - if ( a7 )
# ?# o5 |+ j8 C/ x" K1 A - {
1 q" |5 K3 y% Z: Z" u+ t - vsprintf(&v10, a7, va);9 x9 N. d4 [- w+ k
- glPushAttrib(0x20000u);/ G* i2 M( x* h- p% @* l" x
- glListBase(base);
6 ]! @) J. r2 G' Y3 r: k - lists = &v10;) t# X( l" C. N' ]9 G
- do
8 F$ p) j: }6 \# l - {$ W2 R, f6 N7 O0 s; V, f
- *(_DWORD *)&v12[1] = lists;
1 u: P$ C8 L; [, |1 x2 ]" b - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
& L4 ]2 m0 t* n, X2 x; I/ @) ?0 Q - ++*(_DWORD *)&v12[1];
0 b8 B* p) K0 r' v+ Y8 G+ F - v12[0] = **(_BYTE **)&v12[1];' e% W& s# A0 c2 T) C* P
- **(_BYTE **)&v12[1] = 0;
) [: G$ Y4 z) D' m4 U0 I' j - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 ) B/ n1 O: w9 ^' x3 ?
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
, c3 B0 e/ Q$ L/ Y - y -= a5;
/ V+ o8 n) m9 t: L - glRasterPos2i(*(_DWORD *)a4 + a1, y);
0 j' y, P% ]9 r5 `* p1 L! u" D - v7 = lists;
7 Y# G3 P$ w& l2 c! r2 j% _: f+ {) c - v8 = strlen((const char *)lists);
4 x" [$ A' j+ Y3 L' V% M' ]$ r - glCallLists(v8, 0x1401u, v7);7 o& I/ i4 D7 ?# ?
- if ( v9 < a3 )
6 A, r, L# k/ f/ k+ \: C9 E - a4 += 4;
6 s6 ?- L6 `: ~ - ++v9;
5 Y' r. U" j, O/ ~; Z, |: v - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);- ~, y7 o/ C+ v" A l& e5 C
- }
! Y3 D. P: h2 I; I - while ( v12[0] );
+ K) G$ y* c- c: i7 q |8 @/ A - glPopAttrib();
) S6 g* q+ B' e6 @* b' @ - }* v' I- y( j' I; g
- }
2 @. G9 h+ Y) e
复制代码 * N) W! I2 C P# W. M
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
6 z+ f5 s' k! M D9 `* k) Z; E6 B- A0 g7 p
- .text:004512B1 52 push edx ; char *( J% p/ F) J$ r: _
- .text:004512B2 8B 45 30 mov eax, [ebp+base]" H( m9 A8 m2 [5 h1 M8 Z
- .text:004512B5 50 push eax ; base
D3 M* F) y" ~, ^7 u - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
' e, R( j) D) M. V- X. B7 x3 ` - .text:004512B9 51 push ecx ; int5 e: \9 S$ Z8 a9 ~4 @, @
- .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
$ ~: `# `+ Z3 @ - .text:004512BD 52 push edx ; int
4 Z% x u2 t; v, a3 b - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
+ H. P' t3 P& v3 J; q+ ` - .text:004512C1 50 push eax ; int
; Z8 T- k9 v( e5 A! T: E9 F4 ~ - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]- B0 h( l" R& V# W& e1 e- G1 b! N
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
* P7 \# C. X, {! C+ b - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
) N u+ b' p- Y' M. J4 k6 l5 R* u - .text:004512CB 51 push ecx ; y
5 X( N! E& L3 T( x3 L5 S: `! J3 ` - .text:004512CC 8B 55 08 mov edx, [ebp+x]
! b8 M4 }% E2 P& {8 n3 T& i - .text:004512CF 52 push edx ; int& ^7 j6 m, ^" j2 J) Y$ n4 V+ A7 X
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 . O9 L+ X; V0 [- s4 {0 n
chatGPT整理过之后,如下
& O8 A6 S0 E$ y n
3 ]4 X( R0 k' ?$ d- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)( d, G: m) e4 G6 L
- {& D6 V( g' i2 T4 k1 i `% ?
- GLvoid *textData; // 存储字符数据的指针/ T& Q' W* l6 w2 s
- GLsizei textLength; // 字符数据的长度. v2 m4 S1 e2 N2 O& s
- int lineIndex; // 行索引0 g. D3 d, R2 X3 Y9 O/ ^2 J
- char formattedText[5]; // 存储格式化后的字符数据8 q! U2 D% O9 Q
- GLvoid *currentLine; // 当前行的字符数据指针
' C( d8 }9 p& L) l5 t3 e! g - char buffer[5]; // 字符数据缓冲区
0 d8 C% t8 V; l# Q. E+ L& e - va_list args; // 变长参数列表$ [- I: q/ \: |
- & l) F: d9 V5 S
- va_start(args, text); // 初始化变长参数列表
1 o. N' E. v% T! C' U! l - lineIndex = 1; // 初始化行索引为1
$ g' s' X- V* n- @+ R
6 }6 L% d4 B4 k, e. s q- if (text) // 如果文本不为空: v6 j) o2 J5 w: Z+ Q/ g
- {
0 [: H- Y U* Z2 U- u - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中9 z6 @4 ~ ~7 D; K+ n4 X
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
}$ ` H) A( L9 S2 v6 l6 X$ O - glListBase(displayListBase); // 设置显示列表的基础值
: b2 p- A) i" @ - currentLine = formattedText; // 将currentLine指向formattedText的内存位置* \3 J' i$ G) q
. K+ m# y; S0 x w: {* r- do
i# j9 d6 z$ Y/ G5 @( s - {
4 U D$ A3 u6 C) ~7 f" B( W2 K: w" o - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素5 ?! |$ e: P, A2 c5 Q
7 B' Z' x& o1 ~( r5 y- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束 x: J. |% `/ R! x, h& u
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素9 w6 W- W0 H/ V" `* {! B, _, e
?1 h! D0 b% X/ B: O4 X% b- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
9 Y0 u4 f8 W9 G t - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
5 s O; Q% Q7 U( B
5 t& o T3 J% A- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)" G* T" y5 r8 @$ j0 i
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符4 R8 N' I. }3 F
- ! t! V% @! A7 R0 e+ P- D# Z% [
- yOffset -= lineHeight; // 更新y坐标
8 d* h! `# h& F* f+ L5 K - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置/ R4 N) |! [/ p2 L
- textData = currentLine; // 将textData指向currentLine# W+ [) Z( H, d% t
- textLength = strlen((const char *)textData); // 计算字符数据的长度9 A; q/ x& x2 g
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表8 [: \5 p, o" ~1 X) i* ], Z
/ f! ]# w! x: G! t% O5 T- if (lineIndex < numLines)
! _8 u3 y) U2 e3 p& L- Z - lineOffset += 4; // 更新lineOffset. q4 Y2 u7 l, I
- ++lineIndex; // 递增行索引
& P" h! [7 R% h: @ - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
, V* G7 ?5 G6 [. I - }9 k$ r1 V! h0 `/ v9 b; t
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
# E3 S1 G' a7 \4 t/ |% \# [ - glPopAttrib(); // 恢复OpenGL属性状态4 c; R; p. b! k! j0 a
- }1 Y. l% K W: H3 g, H/ z
- }
' V" ^' A8 H7 u7 c" i
复制代码 / b. K; q/ J% B
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
% \# I# d( Y8 }2 |; r( u6 a2 t8 C# N( R3 g/ S7 i0 j
int xOffset, 字幕的x坐标# y+ l- Z! d) c( ^
GLint yOffset, 字幕的y坐标
$ j5 o8 l* J( ?) Iint numLines, 字幕的行数(较长的字幕为2,一般为1)* x% l1 T& V8 S' h/ }+ T, Z
int lineOffset, 这个需要再研究1 {; ?5 O1 e5 z4 a n
int lineHeight, 字体高度(或行高)! Q/ a4 A+ U, W/ T# V* w
GLuint displayListBase, 这个字体对应的base值' F6 W/ S! k3 }+ `" E
char *text, ... 字符串
+ x" |3 |* `& N
# Y5 Q) ?7 S: r0 G |