本帖最后由 shane007 于 2023-9-5 16:49 编辑
( R6 Z5 Q8 N/ d/ g/ T, x8 j
: z% x* x3 D9 |. d6 E6 M: m! U这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
, a9 k+ A4 O5 x5 t7 f因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。' W* G4 w% M- }5 g2 ?
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081& ]# B% C0 |# Y
第1处3 n7 K, O* |4 x9 A% c4 Y
- void sub_451474(char *a1, ...)
) [- u+ v& D9 q+ I - {1 {: x6 M& s; Q/ {" W7 _8 C
- GLsizei v1; // eax
' b Y- S5 ?; r( m - char lists; // [esp+4h] [ebp-800h]- k/ M1 b; ?3 x0 N. s3 y, V
- va_list va; // [esp+810h] [ebp+Ch]
: K" [0 c3 r$ Z2 h, g, \
4 A" C5 |% q8 z* {( Q& z- va_start(va, a1);
1 Q: k0 ~4 |7 M8 L; Y1 e$ _ - if ( a1 )
& w4 x3 l& y; E. } - {
+ ~4 `( i1 Z v# ` - vsprintf(&lists, a1, va);
( \8 I+ b( _! @8 v, w - glPushAttrib(0x20000u);& I# a0 D. d+ r' E/ ?6 w
- glListBase(base);+ v# B$ e8 ?# P5 o/ O# H: Z0 n U
- v1 = strlen(&lists);+ T6 d% L6 k: t, o n2 [6 H' z# {
- glCallLists(v1, 0x1401u, &lists);
) a+ Q, _& m" M( c0 p7 A- f - glPopAttrib();' O) G- D( H! x& R' I
- }
- K4 _# d7 s% M( V# M a ? - }
复制代码
+ ~( R/ q4 L6 Y7 ?0 k, f, [; M
+ q# L- z0 E; V& s, o" B第2处. `! [' I1 B9 l0 R* h/ Y7 k" F
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
3 ^" c2 z0 U' |0 |; p* { - {. D! ^. `0 b) @& |
- int v4; // eax1 o& M* M# j2 I9 T$ B
- GLsizei v5; // eax% @( ^8 b+ s. v( v9 o+ u6 d
- char lists; // [esp+4h] [ebp-800h]
* N$ e" _# W% v- K f - va_list va; // [esp+81Ch] [ebp+18h]6 c/ k# z) P: q$ t" a
# f( }. {; _ K% ~; Z6 u. G# a- va_start(va, a4);( `% l- f" P# b9 e1 C2 R3 N( j) n
- if ( a4 )0 d4 Z6 T4 m6 X; N. U" a8 G
- {' }; Y3 C7 p- M" c
- sub_44F8A0(a3);
9 G4 t* I* x8 l, d - v4 = sub_40BB44();5 T( D- e3 W' c; \
- glRasterPos2i(x, v4 - a2);5 ~6 n: v" G0 }; k
- vsprintf(&lists, a4, va);9 r1 y- Z8 u8 @! C
- glPushAttrib(0x20000u);
* `% E/ i, H1 E U6 f - glListBase(base);
- H+ }5 E+ O$ \4 r - v5 = strlen(&lists);4 X4 w+ L6 l2 u; K) `
- glCallLists(v5, 0x1401u, &lists);2 i Q. B0 n5 }- r
- glPopAttrib();! ^6 e, j+ @8 X C6 X. v
- }
C# V( n; m; B+ o - }
复制代码 . `, [& x f& D% @! b1 e; w
; R) C! ~2 K' \
7 k: f8 v1 P, R% E第3处
( Z8 ?8 R: y( c U- - @+ F: q+ F8 ^) Z) Z* h
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)* L* N8 Z: j: _ T
- {
( v1 J o( J6 X4 ~' b3 _9 | S. F; v1 y - GLvoid *v7; // ST08_43 x* y y( S, H6 V' \, d* l. c
- GLsizei v8; // eax
) [9 ?2 M. f+ }! F - int v9; // [esp+0h] [ebp-1018h]' r& E2 l! N. X2 V
- char v10; // [esp+8h] [ebp-1010h]% I. c$ j( N- V0 s; l
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]" G. e9 B$ @: J4 Q; A$ z1 I. l% p
- char v12[5]; // [esp+1013h] [ebp-5h]! `: l- F, r; | m5 U8 H, m5 v
- va_list va; // [esp+103Ch] [ebp+24h]. x; B, ?# T, N+ P6 o0 ?
- 5 M* ^5 n0 }: ^& N c
- va_start(va, a7);
* F3 Q- d( @, f. j r9 d - v9 = 1;
/ N( ~0 h5 K; c/ }' W& B" A4 |- } - if ( a7 ), j, n7 d& z! m
- {
& B* N; p2 D0 F2 ]: G4 ?: T1 l& M - vsprintf(&v10, a7, va);5 {' H, q9 V2 G1 T" A4 K
- glPushAttrib(0x20000u);
4 J1 c ]- L1 `6 B9 s - glListBase(base);
3 b& k$ O9 i" m0 v/ \% c' X# z - lists = &v10;( S* a2 k, ^% a$ G7 e& q
- do3 J ]5 P) W5 _" [. E$ e1 o! c6 _
- {
: \! Q. i4 S- x/ ?- r3 i - *(_DWORD *)&v12[1] = lists;( j0 U8 d5 F' t8 D
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )1 x$ I4 u8 H# q/ k. D% W( |! n' ^+ Q
- ++*(_DWORD *)&v12[1];" D. X: N1 P7 q- D6 A
- v12[0] = **(_BYTE **)&v12[1];
3 I6 L. ]" {# W0 O A) O - **(_BYTE **)&v12[1] = 0;
; z- p7 x3 b/ ~7 \( L4 f5 O' W - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )' k& r4 G" _/ Q% [- \* Q" F
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;$ s; u. w" e+ B0 m5 J5 r, V) m
- y -= a5;
8 b" W& H$ V& Q4 v( K* y - glRasterPos2i(*(_DWORD *)a4 + a1, y);6 m7 C6 |7 K8 |2 F
- v7 = lists;$ a8 M2 o. I6 O, i
- v8 = strlen((const char *)lists);: _$ n7 X+ P4 U& D
- glCallLists(v8, 0x1401u, v7);
/ h5 e: D, |( u - if ( v9 < a3 )2 D a, Z6 H ?' V- Z5 f' S5 l
- a4 += 4;/ D; g3 O0 k7 v6 p! y" A' f4 x
- ++v9;
! w/ \5 F4 t2 u9 A; h% j9 f" |+ { - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);. I% ?) k" G& {2 t
- } q1 O$ t2 w% p, z- a
- while ( v12[0] );9 _7 B, L0 B; N1 G" x3 w7 _
- glPopAttrib();; M+ O( i9 h" ^& I* [; v
- }
" x! C2 A* l. m2 q K4 T i8 c' V( A5 Q - }0 H2 X& E: W2 C A9 U0 ]4 D
复制代码
! L( T( V8 s* N3 `* b调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810' j! o8 t* s1 z$ e- Q
; V( F9 f w1 y
- .text:004512B1 52 push edx ; char *
5 O$ c) j/ \' r7 E: q( w) A: J - .text:004512B2 8B 45 30 mov eax, [ebp+base]
$ v0 }7 d, c$ A0 M! Z/ S" X2 `7 V4 z - .text:004512B5 50 push eax ; base: T$ V1 q: m( B5 J5 @+ }
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
$ z; E! c7 L4 x3 w5 _4 K9 _4 \ - .text:004512B9 51 push ecx ; int
' ? J$ {0 y) d' _' J - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
5 t0 [( B4 ?0 ~/ X7 u1 s - .text:004512BD 52 push edx ; int7 w8 g q6 o: ^4 n* t
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]: o( K+ b6 s2 ?' R8 L$ h
- .text:004512C1 50 push eax ; int
6 s: ~& y. Z" E - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]' f5 s) N" }' i' x3 ~. y
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
$ X z, f, `2 R. u( R - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]4 F4 W& I! ^# {6 }! r$ @. ^' Z
- .text:004512CB 51 push ecx ; y
) e% X) p4 s% }* Y# B- Z7 p \ - .text:004512CC 8B 55 08 mov edx, [ebp+x]) U; i l7 c: W8 T- {
- .text:004512CF 52 push edx ; int
5 t+ v7 M1 Z( H: c& N - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
) e3 e8 v z/ bchatGPT整理过之后,如下- M& M+ r2 u$ G9 C0 u6 i' V; V5 w
. g) I0 [, b! T
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
]) k) l3 C" r, ^ - {
) }+ C' I7 S. {, C M/ i) v - GLvoid *textData; // 存储字符数据的指针
6 x. F" C4 k. d1 p5 { - GLsizei textLength; // 字符数据的长度. L* O7 T3 f a% x t3 h' x. D
- int lineIndex; // 行索引0 `" @* c" D" {1 }
- char formattedText[5]; // 存储格式化后的字符数据
2 {+ r7 s5 Z# B9 M0 z - GLvoid *currentLine; // 当前行的字符数据指针" L4 `6 Z+ [5 [/ g
- char buffer[5]; // 字符数据缓冲区! A& T; Y1 _5 [9 e
- va_list args; // 变长参数列表
6 ~$ c t4 z' n/ b3 q) D8 d - % f9 Z0 ^% n/ ]$ w( Q' U( A6 ]
- va_start(args, text); // 初始化变长参数列表
( n, D8 [0 D/ e0 Z3 W* m - lineIndex = 1; // 初始化行索引为1; Y. t/ e9 ^ Q2 J% q- [* d+ z. h
- 7 a! W o$ L% _' i/ V# Z
- if (text) // 如果文本不为空- S. E5 Q& \. f5 R: R5 @6 b8 k- p
- {
% x8 d0 }; O! j7 |2 W J - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
0 a+ V" j0 u. U9 t - glPushAttrib(0x20000u); // 推送OpenGL属性状态3 x7 N L# ?6 u; i
- glListBase(displayListBase); // 设置显示列表的基础值+ Y( Z3 h- }- Z* W* E- K6 }4 v
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置
) u7 t4 K$ ]6 }; u0 C2 ? J - 6 Q" t( a, r) r. J4 F7 K+ D
- do
1 o- B z7 D% d, {0 a- ~2 ?- L4 d - {
; v3 e. v0 z9 t4 U5 m - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素4 |5 ?0 _9 }. G; B) c
# C" V5 I! q. d- ~- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束. L# r# l& M4 ~
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
! r7 t# D, K! d - 8 W. P2 G* U- d$ K9 @
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素( E# T8 q% ?( A, z. v8 p+ Q, Q
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符; @% h* I$ a/ i
- 4 H$ S* a# Y$ P M$ c
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13) E) [$ b- u! b6 J
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符& S; p1 C) w# o3 G# N1 D/ N! {3 ?
- . J' M* \* H I( X' R
- yOffset -= lineHeight; // 更新y坐标# a, \( y0 e4 w: p; |% ?' R- Z7 `
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
: a8 P+ z3 T- Z9 v - textData = currentLine; // 将textData指向currentLine
6 [% x4 O5 T. u" `2 Z5 G6 Q - textLength = strlen((const char *)textData); // 计算字符数据的长度0 H. \! }! S' Z2 G9 w& ]
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表( f6 `; t7 _+ D R8 J& G
- . a9 G4 _) Z& w9 S& Z _1 a
- if (lineIndex < numLines)2 |( T, ]- A% a2 g
- lineOffset += 4; // 更新lineOffset, L3 d* L8 Y. p$ V3 f7 G0 y: G
- ++lineIndex; // 递增行索引
! D( I; x! c7 h" f& s' C4 {9 ?% u. G - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
# B8 \" e8 E. o1 ]. l% p - }& {7 d8 y6 s) e6 n+ R. o
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
6 C7 P" e0 Y0 j% k2 u1 @ - glPopAttrib(); // 恢复OpenGL属性状态
1 ^$ J6 L# n8 J1 }7 S - }7 @8 E w* ]" d" N' u
- }
3 L7 I1 ~1 w3 Z8 ?/ a( a
复制代码 ) R% G% w+ L5 o4 T2 K7 U
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
1 m& q/ c) X1 T6 _8 B2 S% r
1 A4 v) d) s$ @int xOffset, 字幕的x坐标& [- {9 g/ ?' P6 E9 Z7 }, _
GLint yOffset, 字幕的y坐标
* p+ T5 n; i2 k! h: `int numLines, 字幕的行数(较长的字幕为2,一般为1)6 \8 a4 g; _0 m6 i+ O
int lineOffset, 这个需要再研究
4 U* i+ A' h4 \& D# D& A/ w9 c3 Uint lineHeight, 字体高度(或行高)3 a8 i" P! [$ N. h) r
GLuint displayListBase, 这个字体对应的base值
* m0 A V& T+ u7 S2 K, ochar *text, ... 字符串
4 Q- D P0 `9 R# v3 j5 t
% n* _# [* l3 i |