本帖最后由 shane007 于 2023-9-5 16:49 编辑
$ u, h$ W. P$ j( v1 ^; G% R1 x% d( u2 N
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎8 r# A8 b; K' J* k$ a' [7 W$ t
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
9 L" b2 r$ W/ t# r6 I3 K* [https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081" ~9 m5 {2 f2 z+ A
第1处8 r" g9 _% I( B/ W& G6 }) ^
- void sub_451474(char *a1, ...)$ P/ X) l+ g" H' Y2 z9 }
- {
3 _- Z% ^, p \ - GLsizei v1; // eax
: V* B a: Y$ v) R - char lists; // [esp+4h] [ebp-800h]
( l* J, B) F& ?5 Z& G+ D4 R ~ - va_list va; // [esp+810h] [ebp+Ch]( o/ U* [, \9 S
7 Y+ P# b. G8 s1 S4 `, O- i- va_start(va, a1);3 N$ d7 _, M; \' l; \
- if ( a1 )( I" x! L! ^3 E0 ~7 K
- {
: m5 K. a! m1 [- C( f2 H$ D. i* z - vsprintf(&lists, a1, va);
2 R2 i) ]6 I9 U4 y - glPushAttrib(0x20000u);
; A6 q1 h6 T* h: O - glListBase(base);
' S- ?5 y! a" T - v1 = strlen(&lists);) k4 X8 C! l8 F# w5 x, h4 Z; u
- glCallLists(v1, 0x1401u, &lists);9 I* x# W' T( E$ r" C! \% O
- glPopAttrib();
; v) `" M6 A4 S% E - }, u+ d5 ]2 v) a# D1 P+ b2 {
- }
复制代码 7 W: A- F( H3 E( p( j
* W# g5 C; Q3 Q1 F/ Q# Q F1 y; A) G% z& b
第2处
1 j% G, S( l- Q& C- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
5 p4 M" F' ^( M - {
?6 p% u- |, Q( }% x/ Y - int v4; // eax5 ^+ ?5 N2 L' z/ j8 ]1 W) M
- GLsizei v5; // eax
: Y: P. J& o3 p: Z# t& t6 \ - char lists; // [esp+4h] [ebp-800h] j# J7 f. F' ?/ D: ?
- va_list va; // [esp+81Ch] [ebp+18h]- v) j4 R& P7 A% }. l5 P# c' m; ~
- ' e* f6 J8 Y. C/ v/ x! J6 ~3 s! G/ x$ D
- va_start(va, a4);
. O/ n- v3 P1 B7 C7 t" w - if ( a4 )
/ k w+ z \: H/ F$ T# M/ f - {) {# i ?/ @; k0 J2 r
- sub_44F8A0(a3);
. a8 Y8 _; N/ F: Z: v2 E2 t% E - v4 = sub_40BB44();4 ^; i' K0 m& D1 I* R7 V
- glRasterPos2i(x, v4 - a2);
+ Y! t" s4 j2 L" {' O - vsprintf(&lists, a4, va);; K8 Z1 E; _" Z
- glPushAttrib(0x20000u);
/ N/ n/ w; g. ~) a. x: ?5 F" h - glListBase(base);
+ ?( x9 u5 B1 N/ A - v5 = strlen(&lists);+ L" g: J. u: p
- glCallLists(v5, 0x1401u, &lists);
2 b2 ]4 m, v+ A0 }& E2 @7 g - glPopAttrib();' f& x% t; s* H
- }6 _( @! ~6 q4 o* w1 X0 A
- }
复制代码 0 J7 d" m7 ^+ M6 K9 g& Z
# N! ^: D: V8 p& s
% _% ?, S9 R' F" d第3处$ D, Z, A; }8 Q1 {/ b2 ]
1 ~" X: q9 q/ o# g9 K) K! J1 u+ d9 @ a- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)# @1 N. g; g d
- {3 l) u2 ~9 Q1 t$ x5 @* \1 ?1 G4 g
- GLvoid *v7; // ST08_41 d* j$ x3 j4 t6 r! i
- GLsizei v8; // eax
$ ?: o, H6 I" ?4 x9 @ - int v9; // [esp+0h] [ebp-1018h]! ?! a3 e1 @3 `" l! P2 y# ^
- char v10; // [esp+8h] [ebp-1010h]+ b1 S! r4 K# ?
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]1 u* A9 Y5 c: r
- char v12[5]; // [esp+1013h] [ebp-5h]
" o* Y# E+ R1 E+ E8 a! [; d' \ - va_list va; // [esp+103Ch] [ebp+24h]6 h1 N9 K0 J# {9 H; s, G6 T: v9 Z* [
- 7 X9 M8 e( f% s7 h
- va_start(va, a7);" ^) m( P2 W0 I& S: T. w& U
- v9 = 1;
6 r' [6 R# q0 J - if ( a7 )
. B8 c8 g$ K; _" ^! q7 r - {
7 d% R7 T( x2 T1 S" J - vsprintf(&v10, a7, va);
9 p' d5 J# Y8 H - glPushAttrib(0x20000u);; M$ n3 J/ b5 u! w
- glListBase(base);6 \- F) S- h- y" t
- lists = &v10;3 d% e" X7 ~: e# s3 \ R- G% ~
- do! _, p, o; X2 [9 M- J$ X C
- {
8 U5 V( h" s2 s1 W$ M - *(_DWORD *)&v12[1] = lists;
. A5 ]% c7 u w) i0 H$ u/ R - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )( G, Z* W( m# d) w6 B
- ++*(_DWORD *)&v12[1];
p1 y% {/ g" O - v12[0] = **(_BYTE **)&v12[1];" u" l+ j1 [& _
- **(_BYTE **)&v12[1] = 0; s- M* o8 X$ y/ X0 g/ G
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )# N) k+ c, I, y% u7 A( e- n* @
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
6 I2 P4 r+ P9 K; M - y -= a5;
5 d* ?0 M3 s0 K8 S( l. d - glRasterPos2i(*(_DWORD *)a4 + a1, y);9 h# n% C7 ^3 T% S' t2 L
- v7 = lists;
$ D2 W& ]3 P* O& K/ g - v8 = strlen((const char *)lists);
, Z# b! n$ g/ P! n - glCallLists(v8, 0x1401u, v7);
- l/ a# T- p% N ]3 _ - if ( v9 < a3 )9 x) w" b4 n" D" T
- a4 += 4;
7 L1 n" _! d3 m; [) o$ F9 s - ++v9;
2 E; \4 r% e7 A+ z4 _9 } - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);2 R1 k/ p( D( v. U' ?* n" u
- }. g2 ]. n4 \* u9 o0 F. C6 k7 i6 H
- while ( v12[0] );
' v& m* n4 t! R$ g6 v T) G2 d - glPopAttrib();5 M% K8 P- m/ q6 b1 v
- }
. n5 U' u, f# ~ a- ? - }' u4 K- D# L3 [, F! W5 |
复制代码
, H' ^) j, j! D/ J4 _# F调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_4518101 ~2 c0 l: U" w
# g: Z# u7 l% k1 Q8 m- .text:004512B1 52 push edx ; char *
+ O9 w& ?2 x; o4 k( x( a8 [ - .text:004512B2 8B 45 30 mov eax, [ebp+base]
# ^, {0 `/ ^) s! X! j - .text:004512B5 50 push eax ; base
2 Q+ B6 F* \2 V! n( _* P" [9 b - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
5 k1 A, h. m" O- m/ \ - .text:004512B9 51 push ecx ; int
, Q8 f% d u+ c4 Z' T) E& a+ { - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]: e) n' ?: }9 X& L4 \2 I: l3 I+ p
- .text:004512BD 52 push edx ; int
0 L# e: P9 D6 }# x. T/ E6 y - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
; q1 \ K3 L7 i5 { - .text:004512C1 50 push eax ; int
' b- ^5 w! p+ M" u - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
1 f q7 J; a ?3 P( C - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
# \4 W: i' W D7 {( L - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
" ~+ D6 f G7 I6 _$ z - .text:004512CB 51 push ecx ; y
( ?* f) B5 f, E5 R2 G - .text:004512CC 8B 55 08 mov edx, [ebp+x]
: B3 n! R& s% A" K8 V - .text:004512CF 52 push edx ; int
! ]! e( I- J, [6 s0 U7 _/ G - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 0 g0 y/ a+ e! M1 c$ |5 m8 x
chatGPT整理过之后,如下 P& b0 b8 v$ {2 L4 D- `
% g4 c# f) [" g8 E' I! O
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)% W$ G- v" W, V. K1 }
- {( l' u7 A3 c- ^8 m" A4 R O- ]
- GLvoid *textData; // 存储字符数据的指针
' Q7 b/ a5 I# G' u1 O7 i1 Z4 U - GLsizei textLength; // 字符数据的长度+ u8 V0 ^( a9 ^5 k1 z
- int lineIndex; // 行索引
5 Z9 G9 V9 p* y$ q% a - char formattedText[5]; // 存储格式化后的字符数据/ W4 a. _ a2 Y5 Y9 y
- GLvoid *currentLine; // 当前行的字符数据指针% C5 S7 I5 V4 X/ h7 G9 N p
- char buffer[5]; // 字符数据缓冲区8 l8 G9 s! h( d- ~/ }7 f0 W2 P
- va_list args; // 变长参数列表
* o0 z% M& @8 I# c% |: V
{) G6 x) R3 |3 j; a5 J6 R; M/ ?- va_start(args, text); // 初始化变长参数列表; u& K, v9 r2 Y D8 _
- lineIndex = 1; // 初始化行索引为1
" @7 Z* U- g1 |$ s* f$ \: t& D
( x% b2 h6 P% J! j! D$ o- if (text) // 如果文本不为空+ V$ N4 w) S7 ?. ]
- {
/ [& W% o8 X& Q - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中& Y) s" {# w g" A7 P$ Z2 ^
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
/ b9 d( \8 L. \9 m3 A2 z9 k* B - glListBase(displayListBase); // 设置显示列表的基础值
' ~+ E. |7 T3 K - currentLine = formattedText; // 将currentLine指向formattedText的内存位置, \4 T. T$ f/ P, T9 Y% ~# Y! d
$ ?$ [9 I$ e3 [- do
5 V1 z1 g! L- D$ l) J7 u - {
+ O$ `- A( n( G$ C% N - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素- t6 r( [0 s q; R! F8 g2 @; \! {
- , ]0 R9 n4 U$ n- N
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
6 y0 w+ h1 [( Y5 Z1 `/ Q. o - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素 H) n/ V' x9 h' ]. T3 A
- ( z6 m G! X' z P
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
9 b( a5 d2 ?% E. e" i3 F2 N4 g) @ - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
+ |5 I6 y/ q; }1 b
" R! H; T) m. L7 O" I0 W- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)& t4 m/ s L+ M# E. |8 {
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符0 L' I Y! A+ C( I* [2 m
2 p4 d4 m( p# L* ^, m* ^- yOffset -= lineHeight; // 更新y坐标/ F" Q1 d6 k2 X7 t. N. F! P+ Q" b) S
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置3 F, {' F; ^+ i- ?3 k
- textData = currentLine; // 将textData指向currentLine6 d* b) n5 X- d* O" t
- textLength = strlen((const char *)textData); // 计算字符数据的长度( ?' F T; [% x! [# e' e! s8 S
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
. b9 Y# W4 H) |/ v& w1 u& B& A
2 W/ j# u! }* a& w- Y( I' r- if (lineIndex < numLines)
1 A: [& x! t6 R - lineOffset += 4; // 更新lineOffset3 u! `& H/ u# t; x
- ++lineIndex; // 递增行索引# y, T6 B5 e8 ]6 }9 _8 Z' |
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
& v, h( d4 ~* L. N8 o) y - }
0 G" T& g! i8 Y - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
]/ A& Q0 V6 N& o - glPopAttrib(); // 恢复OpenGL属性状态8 E& ]' Q" p! s6 @! }( {0 [
- }0 {9 D/ m5 y1 H% }; u& f7 e
- }
( p, G/ b. }+ x
复制代码 " d0 l8 v' ]+ p1 A$ g1 y2 e
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
0 _# N+ _. i( S! J9 R e
4 l- y K/ P) Zint xOffset, 字幕的x坐标
/ a8 v ?6 `+ ]GLint yOffset, 字幕的y坐标
2 H( z/ m; T! \int numLines, 字幕的行数(较长的字幕为2,一般为1)2 n7 T A1 j6 w/ T/ C
int lineOffset, 这个需要再研究
* o! ]* D( o: h" D; f$ l& qint lineHeight, 字体高度(或行高)8 e4 l: T! \# X& |- ]
GLuint displayListBase, 这个字体对应的base值( P! Y. z" H' Y7 v
char *text, ... 字符串
8 \* [$ g/ U& T
. _, o [9 K9 H# ~: V |