本帖最后由 shane007 于 2023-9-5 16:49 编辑
/ {3 E# a! _5 S! I, V
* v1 ?( F2 |9 @ W! E n5 X这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎' J/ L& {3 D2 ]. S
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
- D( ^! X3 ]% Uhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
$ P* _# k1 A F6 `7 ~第1处. x1 S% u( z$ B
- void sub_451474(char *a1, ...)7 V% l4 E% P7 g& K$ j3 X1 m* y
- {
" S: f3 R, {2 P+ `/ V - GLsizei v1; // eax
( E+ @+ d% _% { m- \2 h. s5 c. e0 d - char lists; // [esp+4h] [ebp-800h]( D5 x5 O% E" a( D8 ~. G+ `; E8 t
- va_list va; // [esp+810h] [ebp+Ch]8 I( x2 r/ t4 }1 F: p' d
( d0 c! `8 n! q: w/ ?7 b- va_start(va, a1);
% D5 z: v8 e7 P- ]9 \. T* w - if ( a1 ); ^ d: I- e' j& G7 n0 B6 w$ I
- {- x( Y7 {/ L3 X: E5 k
- vsprintf(&lists, a1, va);
# c. }2 ?7 B, e- _8 L7 ~6 P - glPushAttrib(0x20000u);
* }/ M% ~( I$ e- f! P; K/ S+ |2 ?' }4 A - glListBase(base);
- c A* K4 n! ~/ ] c1 @5 M - v1 = strlen(&lists); ?4 q1 b( c+ f$ r, }( N
- glCallLists(v1, 0x1401u, &lists);
, s/ G: F, }( n4 f( P$ m9 ^' s9 e/ I- ] - glPopAttrib();/ W: V1 G% b3 D! e# |
- }
$ v4 q) q8 {2 ?, ? - }
复制代码
) k3 y2 a' Z3 i- C6 v- b. I( C8 l$ P% t/ ], B6 u
5 }; c: q7 {) e
第2处
8 [: i* X# p1 U5 U7 `- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
2 T2 ?: F) r) D# M8 {; j$ r" s* \0 g - {
# o9 `2 ~0 {& {; H9 N8 \ - int v4; // eax
# n. h- y4 p; D4 ~" h - GLsizei v5; // eax
' g5 b/ q% ~# n$ v3 O/ j) X1 M( }! H - char lists; // [esp+4h] [ebp-800h]
7 w0 ]0 V; R& G- b5 y* k2 ^. }0 X$ | - va_list va; // [esp+81Ch] [ebp+18h]2 [8 \! |1 R$ o1 z' c
1 B. r2 [ [2 Y- B* [1 q E( Y- va_start(va, a4);
4 E! J# y! @% y! O9 J - if ( a4 )
( X; \4 g) `# F/ v. c$ E - {
, @! ^! ?1 [9 S8 p v& h - sub_44F8A0(a3);
+ P. r3 b& q6 t9 M8 s - v4 = sub_40BB44();
" c* K( k3 r, {. m8 p - glRasterPos2i(x, v4 - a2);0 S2 z% K& L# `/ F v G$ c6 L
- vsprintf(&lists, a4, va);; c; C( y; E) v) {1 y) g/ r% v4 }
- glPushAttrib(0x20000u);5 s# L3 N% T5 |' H0 _
- glListBase(base);- s0 q% W; n% ^8 Z) f# o% v
- v5 = strlen(&lists);
% ~; O- a z% g- R8 | - glCallLists(v5, 0x1401u, &lists);
, M7 w V: w0 K1 i2 D+ |( M6 [- | - glPopAttrib();0 I! V# ^& }% R: E2 D$ N
- }
& A# d( w* m2 b% v - }
复制代码 % I: i; }% s# B
! @5 }1 j# U+ s. ]
9 m# w$ H+ S3 r
第3处
& }2 p m% Y( l8 y
r4 @; E$ C6 }9 Y) s3 [ V$ f' y- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
( g# c7 ~/ W- {5 [% ]# C' K - {
( {! W, d E% e0 e; W3 R - GLvoid *v7; // ST08_4+ J; x" g4 m( v0 A( f8 M
- GLsizei v8; // eax8 O3 f2 e9 ^! n" ~) K/ z5 a% ]2 o
- int v9; // [esp+0h] [ebp-1018h]
& t9 f ~: V( ]0 v) ]8 ] - char v10; // [esp+8h] [ebp-1010h]9 `+ F) ]; c6 g G8 _
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]
: D2 Q+ y& V9 H* X - char v12[5]; // [esp+1013h] [ebp-5h]* W2 m, _$ d8 \5 U9 G
- va_list va; // [esp+103Ch] [ebp+24h]5 X& t4 I; f7 K* W$ G* d' U. ?
. \% Q# u& J/ ~- C* L* L) \( f4 H7 H- va_start(va, a7);" \; z" z, f& k" u& u0 U: }: t
- v9 = 1;$ p) T0 P; [. U: S
- if ( a7 ): ^7 d5 q" q3 G+ _8 M$ i. y) A
- {
e, Y- J, ~0 _: k! r - vsprintf(&v10, a7, va);! D6 L) q9 H7 f+ ~: E
- glPushAttrib(0x20000u);6 \1 W/ h: {: k& k0 c Q% ~
- glListBase(base);7 y1 P4 @6 x0 U+ X4 P" F, [
- lists = &v10;
. m; T* X% p/ d) _# h h3 C1 ` - do
9 {" M n8 V" Q0 H0 P* }8 n - {
' ^! r6 z! t0 v - *(_DWORD *)&v12[1] = lists;6 t7 w u& x. k" q5 R# K) d
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
, d# N; \ i4 o" h - ++*(_DWORD *)&v12[1];9 p! j7 k! N4 y, a L4 C
- v12[0] = **(_BYTE **)&v12[1];
$ N3 R) K1 f* H. Q2 R7 J - **(_BYTE **)&v12[1] = 0;- w+ N( a, I9 X9 ^: `# P7 C2 d/ U
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )5 ~2 d6 H" H1 W5 x2 Z; q
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
' W5 @8 i1 ]" r% ~$ c1 x( @ - y -= a5;% Y4 @5 }4 A* r& w9 o
- glRasterPos2i(*(_DWORD *)a4 + a1, y);
1 r7 G: L0 Q! ~6 [* ] - v7 = lists;# j: l/ g- X6 r- k Y& @
- v8 = strlen((const char *)lists); X2 i7 o5 N# ^; b" ]2 t
- glCallLists(v8, 0x1401u, v7);. c2 p2 F6 ]6 E4 L
- if ( v9 < a3 )2 p2 p# K/ K7 B0 u* s
- a4 += 4;
; F' {: j6 n, P: {% S/ |% c$ X9 I - ++v9;
; X. o/ ^, i. f+ O# _7 P1 W - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);7 Z/ K& E" P% o: r% o2 A# L
- }
9 D9 D6 y/ [5 [ - while ( v12[0] );/ u V+ q4 v, m6 y2 M
- glPopAttrib();
8 q+ B c8 {+ N! w& v! u0 p5 S - }% j$ z4 r8 q. }$ q9 _* V; t2 w
- }, X3 p( R0 b Q3 i m0 R3 Z
复制代码
3 z1 i# [7 w T0 r5 Q0 M8 P调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810: W$ Q8 o1 T1 ?$ n6 K7 {2 z
9 e9 Y( j& X! p6 k# A8 d
- .text:004512B1 52 push edx ; char *
$ i$ ?9 C6 }: A, D3 k/ E; q+ I - .text:004512B2 8B 45 30 mov eax, [ebp+base]: U% z/ j% \3 {3 S3 d4 ^( Q, Z
- .text:004512B5 50 push eax ; base* O5 \) E- U* ?3 W, T
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
8 B; N# N5 s) L6 m( Y3 m; ] - .text:004512B9 51 push ecx ; int/ x# K. {3 U7 a: H6 A$ H5 `
- .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
* A' e/ r1 y9 N6 b% }9 \$ z- Z h! N - .text:004512BD 52 push edx ; int
1 j, B c) |3 G' q& ?9 L8 _1 e. x - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
3 K: H& D y& A9 V" A+ |0 Z& o3 K - .text:004512C1 50 push eax ; int; s: J' @& u }% U
- .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
6 p0 g3 G" a7 Y- J4 r/ G7 Z - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
% i9 ^4 i' Z4 B - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]3 M1 _* j0 V7 ~$ i
- .text:004512CB 51 push ecx ; y; p6 f8 b- h9 a+ i6 s
- .text:004512CC 8B 55 08 mov edx, [ebp+x]* U7 y6 e+ |# X: ?2 ` U
- .text:004512CF 52 push edx ; int8 ^1 [8 R+ L, @- E0 |9 ^ l
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
4 Y- D) p( g; wchatGPT整理过之后,如下# M( d7 K( U5 [2 U9 z$ r' p0 T
* {" k, M4 f2 B. X" L% {/ L- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)( \/ @5 a9 F% s0 d* g) C0 a8 T9 d
- {
! _2 X4 F; U: b, D - GLvoid *textData; // 存储字符数据的指针
7 Z+ h& _6 s' v: i% y( A$ Q! N - GLsizei textLength; // 字符数据的长度
; o1 D' j. f8 p# X S, H$ S+ C: s - int lineIndex; // 行索引
9 n- i( c8 d. t% } - char formattedText[5]; // 存储格式化后的字符数据( c9 `. D7 U( O3 d
- GLvoid *currentLine; // 当前行的字符数据指针
( j3 _7 Y0 j% K/ a& g% @ - char buffer[5]; // 字符数据缓冲区
|' L+ {2 m9 i - va_list args; // 变长参数列表
k0 a! K9 w5 n, x1 ^" }3 S
* r) a8 N) D* Y" v4 ^7 D- va_start(args, text); // 初始化变长参数列表9 c+ b9 Q; `1 s2 n# [# g0 j) g" A+ {
- lineIndex = 1; // 初始化行索引为1
. A( Q' ^& J+ s. |5 s! z
" K/ f2 @* h$ h: M- if (text) // 如果文本不为空
& q) }1 R/ y; w9 T/ o F, T - {
7 s9 A+ @$ q4 w6 k2 \# I2 ~ - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
/ h7 @8 \ ], N3 v! Q. d( l; a# y6 T - glPushAttrib(0x20000u); // 推送OpenGL属性状态* O2 X* A! E% H7 I
- glListBase(displayListBase); // 设置显示列表的基础值
( [1 i! a \# Y0 O! Y9 j$ ] - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
& Q. i! O E% Q4 Q
, V# [) _5 O. P# u) z/ ?- do: e! U" T# k9 I3 l* f
- {
8 }# m( r0 a8 q- r - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
) y; T/ N0 C$ q, Y, F
# p" o! ]9 n O6 G& J- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束+ i% l* t+ T8 s7 f, s
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素& W2 f1 }( G. t! M9 {6 I9 y, o5 G
- 7 ^* g: s2 ]2 B0 g( i; O, h+ y! }
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
f* t/ o( N) W3 G' b' U - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符8 h$ w5 l; G# e o, c
1 v" j- |7 e6 A; q8 F4 s4 `- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)6 e6 H& O6 }* P
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
/ ^. N' a9 ^0 Q - $ i- Z& {# z. q$ s/ m8 j1 U: C; ^, n1 o
- yOffset -= lineHeight; // 更新y坐标
! {6 ?1 k! r1 h5 M# k6 N9 Y% t - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
1 h5 O! }6 U4 c" @ - textData = currentLine; // 将textData指向currentLine
" x7 [; j! X" \/ a: L3 Y8 q! F, P - textLength = strlen((const char *)textData); // 计算字符数据的长度
+ E8 o% `; l% S' q. y# D - glCallLists(textLength, 0x1401u, textData); // 调用显示列表
5 z, @0 v5 T1 W' X3 T$ s - 6 i8 v0 Z/ w/ j) N: K
- if (lineIndex < numLines)4 T" j/ C: S6 V- B4 u
- lineOffset += 4; // 更新lineOffset& g$ { q) x3 E! J
- ++lineIndex; // 递增行索引
$ m& ]& O. P& m0 O - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据1 o- i1 e' M! {# ]9 i
- }
! f4 _$ B. B& \ { - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
9 ^: C( o0 u. W7 b5 ~; X - glPopAttrib(); // 恢复OpenGL属性状态
( s5 m# t) T E( c, `& ^" Y, u - }
5 w u. | Z1 |! R& s+ Q/ E - }
5 W) [2 _# e' x3 n$ ?9 s% }
复制代码 - z* H6 Q8 l+ c: `
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
6 A; y4 `: c. K, F6 L
* w, m# R V. Pint xOffset, 字幕的x坐标& O8 E9 P( ~3 J+ y! P# B a
GLint yOffset, 字幕的y坐标: j1 V4 n# J, x$ S, \* z6 o
int numLines, 字幕的行数(较长的字幕为2,一般为1)
+ Z0 D3 o$ `4 \int lineOffset, 这个需要再研究
2 O+ n6 }5 [; a5 \ P1 @int lineHeight, 字体高度(或行高)4 H* t) x0 `; D" l4 R
GLuint displayListBase, 这个字体对应的base值
" E* X/ x1 W; V2 Y/ Hchar *text, ... 字符串
. Z/ w1 J( ~+ J" y/ z4 }6 P
k1 U1 O+ s( K$ ^5 o% t |