本帖最后由 shane007 于 2023-9-5 16:49 编辑 0 b1 t5 l, J/ V( y0 f3 }, B
: T; a$ q" ]) _ s+ i0 ~; b' I
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
4 d- a4 H* @9 N% K5 m# \因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
0 N/ k9 I7 C1 d9 G7 P+ rhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081( x8 `( s' C2 _" U
第1处
# L' h! \9 G. f2 w+ U' ?" M- void sub_451474(char *a1, ...)
' c* n) G" U+ m* i" B; g0 J - {
% R; |. i" }1 ]& b6 f9 U - GLsizei v1; // eax
9 h# M' `- i, ]& q7 v" o1 j4 f0 X4 T - char lists; // [esp+4h] [ebp-800h]2 L+ k. D2 Z% y, }6 h8 f2 }) b
- va_list va; // [esp+810h] [ebp+Ch]2 y5 ?# @% o5 `+ t% o. C
- % v. o: }+ {$ {' m
- va_start(va, a1);
* ?" L( [, W; W; I6 \ - if ( a1 )
9 i; S9 ]9 A0 L2 R! a) p* @ C - {% g' J3 M L7 J3 J5 g. C
- vsprintf(&lists, a1, va);3 w. @1 v4 ?+ |; I" A$ S2 Y1 q4 X
- glPushAttrib(0x20000u);4 o( s4 E* P6 }1 r3 c& l4 p# j% q
- glListBase(base);
% g7 K, R, F$ D* ^ - v1 = strlen(&lists);
1 P. P5 u* U& q8 l - glCallLists(v1, 0x1401u, &lists);2 w# o- `: z* ^0 |2 |, U' |
- glPopAttrib();
7 d# k/ z3 G( n, c - }6 l. Y8 j: S# t; r/ m
- }
复制代码
) y; y3 L' s4 v0 ^3 M( G
& ^, G! Q0 m' ^' R0 ]; ]* t
; X& T U3 }# L" M; L第2处
: O$ f4 w' u+ r3 \( Q) c, T& X- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...), e9 Z7 _$ u& r: b" D! p$ A
- { @( R0 P+ `) j# e* _
- int v4; // eax$ X( Q. f7 l9 r" E
- GLsizei v5; // eax
5 I M* u1 @ Q: k+ G6 G R - char lists; // [esp+4h] [ebp-800h]
p# y; U+ p6 j& X - va_list va; // [esp+81Ch] [ebp+18h]; O% l" ?& f ?0 r7 I% U; e% T
- / F s% Y1 {9 y
- va_start(va, a4);
* S S# F5 f7 d* K7 J+ g2 O - if ( a4 )
! ~/ Q- A8 H/ B - {) O( f+ a! `1 [0 J* a( Q( Y m$ E
- sub_44F8A0(a3);% @* i, l, R1 k9 G( {# j% e
- v4 = sub_40BB44();
2 u) s; \1 n6 n4 j! U - glRasterPos2i(x, v4 - a2);0 E3 H+ |+ i' u1 K2 G) B+ T
- vsprintf(&lists, a4, va);0 W* N i# V; H }
- glPushAttrib(0x20000u);
* j5 X5 Z+ r& e" P - glListBase(base);
- s) j7 L# n, O - v5 = strlen(&lists);$ v, x! y1 j+ c9 Z( h& R- y' k- b& p
- glCallLists(v5, 0x1401u, &lists);
; ~* y! U3 Q# w2 G5 g - glPopAttrib();
O8 e0 H& i/ P1 ^ - }3 g5 l7 \& a* ?
- }
复制代码
2 ]2 [+ w5 W; S6 i1 ]& _
6 L/ U3 h! P$ S7 M( A: n# A1 h% U: A) H- F
第3处
6 h1 B$ I" G2 r# ~6 N
- l+ V5 c* T' m0 Q- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
4 R9 i z3 M2 q2 z" }: Z5 p - {
% H7 U* p: C: \9 [' B - GLvoid *v7; // ST08_4
5 j5 \4 y3 D' c! I - GLsizei v8; // eax- J' F8 e: Z9 C! o+ b
- int v9; // [esp+0h] [ebp-1018h]
4 v# G' y- V2 V+ y5 t% T - char v10; // [esp+8h] [ebp-1010h]; t9 G- ~8 o( w; d u9 @, D
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]
z& h8 T0 G, C& r, I. Y( o" r - char v12[5]; // [esp+1013h] [ebp-5h]
/ f5 F7 B3 R0 |1 ~1 K9 L1 _$ [ - va_list va; // [esp+103Ch] [ebp+24h]
. P7 N8 `6 T6 e
, b/ ~; z$ d5 O# t, A0 M3 N; m* l5 h- va_start(va, a7);
' ]- F) {0 X ` B/ x( _ - v9 = 1;
6 i, w# W) `5 `3 S! O$ z - if ( a7 )
/ X( F- p0 U; N - {
: C5 `7 o8 P. ~) | - vsprintf(&v10, a7, va);
7 t6 v+ |' R- S! `0 y( D/ c+ F - glPushAttrib(0x20000u);) E% h( h3 ^+ P J3 R) U4 r
- glListBase(base);% Z. S' _# i/ c7 n
- lists = &v10;
$ l, F/ {" i7 s- G2 K4 g - do
& H" a/ c1 J/ T9 e. E - {
& p; `; V9 s! Z" a( F( c3 B - *(_DWORD *)&v12[1] = lists;5 o; N, k. ]3 R' @
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
, t, f4 J9 k! p% c) N$ C - ++*(_DWORD *)&v12[1];- T2 }2 Q( |% s0 n8 l& O
- v12[0] = **(_BYTE **)&v12[1];
5 v$ w9 A$ l1 D5 L; ~3 A - **(_BYTE **)&v12[1] = 0;3 O2 _1 U" d' p/ P
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )% Q) m) D3 B. T; w1 o3 S
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;* x* E: ^+ f$ Q% @
- y -= a5;
5 V% e9 n9 U8 D1 _ Q& o - glRasterPos2i(*(_DWORD *)a4 + a1, y);
/ e, j1 v( o+ L1 i - v7 = lists;
/ P3 t' b6 `% ] - v8 = strlen((const char *)lists);' q Y2 Z+ ~) e X9 O2 b: {
- glCallLists(v8, 0x1401u, v7);' m) A. E7 H$ X4 j' T! E$ O
- if ( v9 < a3 )- }7 d9 o7 {" P3 K
- a4 += 4;
4 }/ T: Y; a% ~) \1 e3 z0 r, A - ++v9;% s: x6 d' d) } C2 p
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
6 ~, n6 V! H4 N5 k - }
9 F( x, L1 C/ b" _ - while ( v12[0] );+ f* I0 E5 D r& y
- glPopAttrib();
+ r0 T/ I2 a7 d# }+ Y - }
& O$ t& q% A7 {0 S2 P - }! Y+ L8 p" |$ Y F H7 l7 z6 a
复制代码 7 s2 M2 \1 j i3 Z0 w3 @
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
# i2 x& ^9 j0 O3 h* C2 Z3 h; V6 e& e5 Y1 h
- .text:004512B1 52 push edx ; char *9 ^: D3 i) m$ E8 }
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
2 ^" O. `% _5 F. c) h4 c - .text:004512B5 50 push eax ; base
; p" U( R3 H8 J; x& F% |5 E3 P! @ - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]7 N. B9 u/ f9 `6 R g0 o* D J# ?7 m
- .text:004512B9 51 push ecx ; int
; L& E6 K( Y6 O! S7 @* S2 ] - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
6 }/ `, h5 F7 S! h3 h - .text:004512BD 52 push edx ; int
- @( Y5 G) \, e, k' d4 P. h - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
7 }- P6 [' f- d T" Q3 m6 ] - .text:004512C1 50 push eax ; int6 J( [- F4 k6 z0 X" L
- .text:004512C2 8B 4D 0C mov ecx, [ebp+y]) f v }# k% u, \7 h+ \3 r
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]% ^- h1 ?! ?+ L; ~; J; c& }% N
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]% q$ t* Z. F' q! B* m
- .text:004512CB 51 push ecx ; y, c" o% E0 _5 L0 Y. s
- .text:004512CC 8B 55 08 mov edx, [ebp+x]
) ~3 m* X2 @" Z' Q - .text:004512CF 52 push edx ; int
; P( `7 B1 u! h - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 ; F9 I2 m0 r, f
chatGPT整理过之后,如下
: v5 s% y: b5 L8 _6 ?! `0 T
5 n3 k$ d. z. f8 \- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
) p" B8 x! p7 S( d( s. J - {
2 y5 h ], k& ]! d s5 |; p+ O; N - GLvoid *textData; // 存储字符数据的指针
( F$ h. u3 \, s3 ] - GLsizei textLength; // 字符数据的长度3 p8 {3 U3 D/ }* z7 e4 K( t% y
- int lineIndex; // 行索引
+ B! e6 Q' j5 b% b1 _8 |9 J - char formattedText[5]; // 存储格式化后的字符数据
! I z1 S0 j3 A' z) {/ ~' f - GLvoid *currentLine; // 当前行的字符数据指针2 M. M* X# m9 ]- y5 F
- char buffer[5]; // 字符数据缓冲区
2 x$ o2 ^% u$ [" {, I - va_list args; // 变长参数列表
* S4 C' W/ ^; Q
, M7 p l: k( n* P2 e6 o- va_start(args, text); // 初始化变长参数列表
& t# h8 P1 c: |6 F2 S - lineIndex = 1; // 初始化行索引为11 \" i1 P7 }2 x- n+ y$ R
- ) V& Z" Z* f) S' o# T6 ^
- if (text) // 如果文本不为空6 S# j! n9 R s. R' }5 Y+ h
- {
) g# n' u9 f( I, ~5 b9 ~9 d! R; G - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中% N C; D S* M
- glPushAttrib(0x20000u); // 推送OpenGL属性状态& j Z7 q1 E9 e' p. C o3 k Q% j" J
- glListBase(displayListBase); // 设置显示列表的基础值
* b: F9 d- C/ c# \# B - currentLine = formattedText; // 将currentLine指向formattedText的内存位置. d7 l8 p5 R+ w5 b; f
- 0 _1 h5 V: Z* C6 V r! q* X7 u/ f
- do
$ i: G/ B3 K' g( {) B - {7 L; r8 q: \" h" e
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
& A, u' c8 q" {! l* |% f( J - * K" ?$ f, F# z4 q$ r) j& |
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
3 l }' U1 N( k# f8 W) ?& { ] - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素 N7 J: P! C8 A, E' U: I0 `
- $ C! N) C C* B, `; H
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素; W1 U0 b, J2 r6 [4 M
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符, @ A, g% J8 Q/ y X; X4 G
- 2 e2 D0 x9 H4 C0 w% R
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)6 E( u7 l4 E" k0 z, c1 P
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符$ T+ M8 V0 w( h, v; ~
/ u, @5 |6 N: d: U/ r' q- yOffset -= lineHeight; // 更新y坐标/ p2 x- p8 D; H L C4 V
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置5 w; h% g) k5 b
- textData = currentLine; // 将textData指向currentLine
' A9 h* O8 G6 K7 m J7 @1 g: z2 ? - textLength = strlen((const char *)textData); // 计算字符数据的长度
! P2 ~8 i8 R3 }% e! k; ?7 h, U - glCallLists(textLength, 0x1401u, textData); // 调用显示列表- [: v& c1 h) ?3 j
- ; a! k) _$ j2 B+ X/ l& n
- if (lineIndex < numLines) k9 y/ v( |- _, L1 v% `+ @3 k
- lineOffset += 4; // 更新lineOffset
- U$ B; z2 [# L9 T9 j - ++lineIndex; // 递增行索引# D$ `% J$ s; k' x4 A4 r
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
/ s1 H/ y3 k; z! _% M - }
; n/ F+ ~. N" ~) W: F# H4 k - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环; p$ r& U$ E% f
- glPopAttrib(); // 恢复OpenGL属性状态
+ V! E: i! C8 S0 w. b" g4 [: \1 s - }
% k1 t2 V- n. r6 F; P - }
5 t: j& e* n1 B
复制代码
/ m1 b F( f% _/ D含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
8 w3 O$ u1 P/ Q0 U' T4 k8 T/ c7 v$ _4 V; q) @5 }& b3 k
int xOffset, 字幕的x坐标
) M+ ]5 ?, k( }! T3 nGLint yOffset, 字幕的y坐标
) c }. b1 q: [% C, m3 iint numLines, 字幕的行数(较长的字幕为2,一般为1)0 P. e' b) q: ~' }
int lineOffset, 这个需要再研究( M- P- r" l4 @- v
int lineHeight, 字体高度(或行高)
. N1 p, V4 {: mGLuint displayListBase, 这个字体对应的base值1 R$ L' u% J t" |7 l9 c, v
char *text, ... 字符串
7 Q) L) m( F7 V3 N0 }; o
" w' m) l7 A% W7 @1 g |