本帖最后由 shane007 于 2023-9-5 16:49 编辑
. @$ l" ^" s! A E" l2 z' i8 ~/ h! p9 N! N1 _* G+ C/ s8 E
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
; S% `+ q1 A$ U; [因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。( F. ~5 } `$ L2 ]
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
5 [9 R% E0 [" ?$ c第1处% o1 f" h0 `8 M5 ^: r" q/ ~+ Q
- void sub_451474(char *a1, ...)+ V9 J+ Y( J- H
- {
# b$ X% Z" N- K5 v - GLsizei v1; // eax/ Z, Y9 @+ U- J+ {9 e8 U
- char lists; // [esp+4h] [ebp-800h]; R0 e0 k/ z) p' ~' b- B( v3 X+ \& x& b
- va_list va; // [esp+810h] [ebp+Ch]
# g* c k6 L+ ^2 a6 ~' s - ( x" i0 O4 o* F& E
- va_start(va, a1);
5 v+ B7 W5 a2 a5 c - if ( a1 )
$ ~7 v9 a$ ~3 L) j9 W# H8 \: U - {
" l7 j' s0 i' |9 ^$ \2 A' { D% f5 M4 c - vsprintf(&lists, a1, va);' {/ ]& T' `. g7 v, S( V9 X
- glPushAttrib(0x20000u);! B9 u8 _- g9 e$ p
- glListBase(base);/ T1 | [# W0 x- b4 e; C1 H
- v1 = strlen(&lists);
& n& D; q- m$ c1 q% q - glCallLists(v1, 0x1401u, &lists);5 s, R7 n3 \5 J
- glPopAttrib();
8 t- O5 w9 B2 X" {* q+ d& P- M) ~' e - }
2 q2 x b% `7 E' X. M, ~ - }
复制代码 ; n2 G h6 N- q0 @
* n5 ?5 Z4 ^* i# B% ?' v' Y
/ q7 a" s8 a) e/ N第2处9 V# l, p" @0 _/ Y; x; K2 G
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
& o9 c+ C; l" E - {
4 [; L3 o# L$ [) M+ l' [' {* X1 W; E- C - int v4; // eax( |0 f0 W7 P0 U) s8 `$ s
- GLsizei v5; // eax q# ~& c" L$ S& F8 x1 a* M3 O
- char lists; // [esp+4h] [ebp-800h]$ v2 m+ e- q3 D9 g0 d! E4 o
- va_list va; // [esp+81Ch] [ebp+18h]8 ?2 Y: i0 D4 g7 M+ e$ T
- ( G$ \+ {; k/ q/ }" k
- va_start(va, a4);( S! N7 x; Y7 Y
- if ( a4 )& ?2 f$ `5 \3 t3 X% M( S: H( d: @
- {
1 Z- a! u1 A6 }$ K% ?$ F$ i - sub_44F8A0(a3);
; {* `# ]/ h' a - v4 = sub_40BB44();8 D0 x: A$ ^5 J" E* h, ]
- glRasterPos2i(x, v4 - a2);
) l9 u6 \( i7 k3 ] - vsprintf(&lists, a4, va);
" a6 H& ]2 F7 ~" v& e* c6 n - glPushAttrib(0x20000u);3 q! d. M* P' {1 H2 e. m
- glListBase(base);
0 E& U9 d5 |" l+ n( O" q - v5 = strlen(&lists);4 ?6 z: N: ~7 {
- glCallLists(v5, 0x1401u, &lists);9 G, r/ p$ i2 U5 A" E( l* u
- glPopAttrib();. k% z# |2 \+ F( n
- }$ U" q& f% g% T4 v$ R
- }
复制代码 % t5 r$ O3 f! {% J; i
2 g5 q# A$ k- G' J, k' i) E
% \* H6 `: N' [& d6 ~- k
第3处
+ B3 j2 x; O/ U4 n/ [ z
3 ?7 A( i2 y1 ?/ b; m- B: k- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)9 n) D$ e! \( C
- {; N/ U8 `5 h% Y& }0 [# @- h! _
- GLvoid *v7; // ST08_4& h" G# M2 G0 T; s) C: x& a
- GLsizei v8; // eax% ]7 Y2 y( u- [% V8 p. D
- int v9; // [esp+0h] [ebp-1018h]
/ r+ [+ U1 q% n8 m# r+ C: v1 p2 n+ x - char v10; // [esp+8h] [ebp-1010h]0 |& h$ @" s) j& `
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]9 m3 f' _! D' S
- char v12[5]; // [esp+1013h] [ebp-5h]
9 W. o2 Q$ x( z0 u; N' r' I - va_list va; // [esp+103Ch] [ebp+24h]% H+ j6 H) i" @, i
- 5 [" H$ `7 @0 R A6 @8 v z$ `
- va_start(va, a7);" n! h& b0 z# N, p, `, `0 ^5 L4 \" k- [
- v9 = 1;3 C$ U; L% `' d% P5 L' U9 j# N2 z
- if ( a7 )( E) u0 q/ Z0 b9 S/ F& y5 U! N
- {: k/ z$ a( O( ~. \" j
- vsprintf(&v10, a7, va);+ L, w/ z7 k% L7 `3 _) z: F# p
- glPushAttrib(0x20000u);# b+ v1 C( I* N* \, g1 z/ Q+ i
- glListBase(base);
+ e' F' Q; g; S, P" C - lists = &v10; x; D% d! ~5 B
- do
. p5 e' j0 V, B: Z4 Z3 P - {
: b/ b6 O, f% f, C$ E+ r& r n - *(_DWORD *)&v12[1] = lists;2 U& S: w( N. ]3 x
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
) s) r, \% q0 U. [4 v - ++*(_DWORD *)&v12[1]; W# ^+ q7 X" S% c
- v12[0] = **(_BYTE **)&v12[1];
, z0 Q3 Y" m* v) Q: _ - **(_BYTE **)&v12[1] = 0;3 p. D. F0 y3 g7 `7 \$ J
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
U# {- ?0 a q, f& ?2 @ - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
/ l q7 D0 O% b - y -= a5;/ P5 @& H! Z/ z0 N1 |1 P) j
- glRasterPos2i(*(_DWORD *)a4 + a1, y);
# Q( R& s7 e4 ~ - v7 = lists;6 t( r l1 s& `( h! i% n: I+ Q" m
- v8 = strlen((const char *)lists);8 r3 u2 @+ r7 q% Q, G9 F
- glCallLists(v8, 0x1401u, v7);- b" ~5 {* e/ G5 a3 d6 o
- if ( v9 < a3 )4 ^! H4 T g3 @$ s& y9 t/ C
- a4 += 4;
5 C: y) Z, e* q4 l9 \ - ++v9;
R3 I8 r. o! ?4 x/ j - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);7 z6 N0 e# d5 y/ |
- } y: p) y4 @0 F2 f4 m" Y& e" K% y
- while ( v12[0] );' [8 [+ P; w6 k* X5 F, l2 ^0 U
- glPopAttrib();
# G( Y4 I2 ~9 K" d9 E - }# U1 U' u& C" |
- }
) h7 w" c2 T) q; O9 I n9 C
复制代码 " V. Q$ e7 A2 D& t
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
9 p. y( S+ ~( u; j. {8 A
# h: H1 G( e4 ]5 M& L4 g- .text:004512B1 52 push edx ; char *
* o8 A: x" _/ g: t7 f - .text:004512B2 8B 45 30 mov eax, [ebp+base]# V/ K# m6 t2 r. K8 a
- .text:004512B5 50 push eax ; base
4 G1 Z+ t8 ]6 t, d+ Y7 I - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]# `. O j" j3 i$ _9 U
- .text:004512B9 51 push ecx ; int% U' a# x7 c; Z) B5 |9 @
- .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]; u. U6 _$ ]+ T) K8 p4 {( v. A
- .text:004512BD 52 push edx ; int( D( f* }6 B6 h
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
+ _( a0 K* n6 Q6 Q. S - .text:004512C1 50 push eax ; int
z8 E9 A$ u/ V) N" i4 N: ] - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
6 L% w; q- F8 H( Z# T* ]9 c - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
- Z- z# M9 u Z$ i. F% Y# p - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]5 g* ` Q% j. s: l$ j V
- .text:004512CB 51 push ecx ; y5 o8 Z+ `0 B* {: ?9 |8 W
- .text:004512CC 8B 55 08 mov edx, [ebp+x]& ?, g2 D4 G- d; N
- .text:004512CF 52 push edx ; int
& Z2 [4 b3 h3 Q! ` - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 ( a; R( ]$ C7 H1 |
chatGPT整理过之后,如下( N8 t, @& Z6 Z' Z! z
( l! g8 \' V7 k: B) j. j7 v. f6 ^# E
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
; L |$ _# d% L7 z1 l - {5 a- K; @7 e% }; g
- GLvoid *textData; // 存储字符数据的指针+ a6 K7 l; g$ } F: v9 Q
- GLsizei textLength; // 字符数据的长度
: M8 P' i$ G6 T T+ g - int lineIndex; // 行索引
2 o m) e+ c8 p; e0 v0 h - char formattedText[5]; // 存储格式化后的字符数据
! u, m- U/ _* Y+ V - GLvoid *currentLine; // 当前行的字符数据指针
5 G8 E8 }" ~6 Z/ z2 X) ?0 d* F - char buffer[5]; // 字符数据缓冲区+ {5 f) p# M- z0 s. m7 l
- va_list args; // 变长参数列表
- o" O, f8 j! I4 \% \+ T! {/ g: ? j
1 P# r; e! F$ ?' Z# r. i- va_start(args, text); // 初始化变长参数列表
! D& w; A% V, `( J5 l$ @: k% t: N - lineIndex = 1; // 初始化行索引为1
, f0 d5 D2 M: a* ]! P) p H% |1 n# w
- K: x4 i2 M3 W+ l1 u- if (text) // 如果文本不为空
1 A2 Z. k0 r& @ - {9 F. \" E' r$ m0 M9 v3 S
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中+ i$ l8 z! `) H+ v; \ B; F- A9 C) Q
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
/ n; u l, x; _6 r: Y# v - glListBase(displayListBase); // 设置显示列表的基础值
# }7 p4 V7 t3 C9 u - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
! L7 D: v: @* m \. k - 5 x, f2 Z4 @+ l+ v3 J d% _/ \
- do
0 C- y: @: d$ ^' {$ W - {
1 V7 J: v, v# \3 C% B( B5 M2 R - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
1 _ J& q1 q/ b( _. Z; ] - 0 y, S4 c+ i( @4 W1 O( A$ ]
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束4 z: ?8 G; g9 g/ ~5 [3 g% @) S
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素: H' q* I% d: W' h8 ~# G+ e
- $ Q% ?5 ]( W4 S! H
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素, i8 |8 G* c8 R3 n+ [: w
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符' J; @7 A- F' L+ y9 w" O
, n# b6 B: v; {9 _- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
4 k" |, u# m/ H! c% N$ L+ ~ - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
: P/ u/ D3 N, u* ~
2 f( t2 U! w1 x. [+ c& L- yOffset -= lineHeight; // 更新y坐标( y# G# e+ ~" m% |
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置2 b1 L3 s- b+ U
- textData = currentLine; // 将textData指向currentLine
* e6 j; E/ q+ }! } - textLength = strlen((const char *)textData); // 计算字符数据的长度
$ t0 l( Z6 _) Y, S" M9 G - glCallLists(textLength, 0x1401u, textData); // 调用显示列表1 a7 X2 x/ W2 E9 v, g& K; @; V
: v, x7 {0 @/ k$ j# R6 x9 e) ~- if (lineIndex < numLines)
3 k+ K$ F& [! `1 ?9 Y, ?& H' B; q - lineOffset += 4; // 更新lineOffset: m2 W5 x k$ M3 t/ x, u" g
- ++lineIndex; // 递增行索引" B# h a7 A& V2 p \& [' Q
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据. |# @" p: { H( J0 Y# r3 r
- }
6 l2 t0 ]2 U' t; S - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
7 i4 B2 L5 {" y4 M6 V - glPopAttrib(); // 恢复OpenGL属性状态
2 P$ H. O) L' u5 M+ P1 l - }
; J9 H/ K) Z# }/ t- g - }' m1 ^) y; I; A4 w4 Y
复制代码 & i8 F$ D( K* P
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
7 w2 h; u6 K! ?7 J; C) r% G/ \! Q8 h, w
int xOffset, 字幕的x坐标
6 {) |! P5 u3 P4 ~9 _2 E. }. n+ qGLint yOffset, 字幕的y坐标
) \% ^* l3 d" Cint numLines, 字幕的行数(较长的字幕为2,一般为1)
Z6 v& g1 `2 x) aint lineOffset, 这个需要再研究
% |$ w; |8 C: z) Bint lineHeight, 字体高度(或行高)* O/ b6 U) O* V1 \' d( b5 f; h
GLuint displayListBase, 这个字体对应的base值
( Z' M7 L7 ^' X! j$ \* V' Lchar *text, ... 字符串
: v1 x! P0 d2 L( `7 ~' a0 z1 F1 ]- N( n3 H
|