本帖最后由 shane007 于 2023-9-5 16:49 编辑 + q3 B* I4 W7 S4 r/ @4 x; X
/ u/ H0 e5 v# q* C: ]这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
3 @2 Z, H1 F h/ i. ^因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。0 z7 w. X6 Y, @* }
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
1 e* Z5 W+ f2 `- } ^第1处
8 g) [8 \: x$ E! v- void sub_451474(char *a1, ...)0 U+ ^& |) W" {$ w
- {
% e' @/ Z4 w7 J. H - GLsizei v1; // eax! y3 E# v1 Q, u; Z
- char lists; // [esp+4h] [ebp-800h]5 o: }" F# d/ ^8 n( `% ]
- va_list va; // [esp+810h] [ebp+Ch]
* d0 r3 B6 w) r+ g
, N3 S8 ^" r4 L. N. G3 f6 u- va_start(va, a1);& N) B) j0 c% {
- if ( a1 )
( }/ ~* O4 \& L: [ - {# G8 c4 l( H- b, A# v6 \
- vsprintf(&lists, a1, va);8 N. S+ K# Q# M% ]: O
- glPushAttrib(0x20000u);$ |$ s) J4 T# Z" F: G/ Q
- glListBase(base);
. u0 N+ l# c. O+ d0 g# ? - v1 = strlen(&lists);
; h4 g: }6 L' [. q4 R6 X+ S" k - glCallLists(v1, 0x1401u, &lists);0 g1 c a s* a6 R# k' L
- glPopAttrib();! V6 v5 ^8 C M% Y7 l% g a. W: K
- }( Y" h5 j8 a' L! }
- }
复制代码
6 _4 B. Y. n+ S
( a6 h$ g/ N1 T$ Z% d+ n
3 ~, q( J' Q" r. V. j7 j4 H第2处+ \) S) N Y) \8 ?5 z5 V
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
" ]% Y8 t- s$ Q, z4 @8 e7 T' a/ \ - {* ]2 `0 i6 Y3 Y8 u
- int v4; // eax
! O% \; I0 @2 {$ { - GLsizei v5; // eax$ ]/ x! D" K5 Q9 i- i
- char lists; // [esp+4h] [ebp-800h]3 _. I; L, d0 B! ?; u
- va_list va; // [esp+81Ch] [ebp+18h]5 n& P8 k* g' _& m3 |7 \
- 1 ~/ p, ~+ ?/ i8 d1 N7 z
- va_start(va, a4);
$ w, w- H- ~7 b# v - if ( a4 )! i, Y+ v, x- h$ I" k$ \$ a# z' I$ ]
- {
+ u/ V. B& u# V6 l; M5 f' ?/ J - sub_44F8A0(a3);
0 k& ^6 [" t' }+ |% M - v4 = sub_40BB44(); V! F' u7 G7 n9 `9 }: m% n" X, F
- glRasterPos2i(x, v4 - a2);
! t: r+ m l1 f) x& W - vsprintf(&lists, a4, va);8 V' L( M- f8 ]1 ]! V! s$ E, S' d
- glPushAttrib(0x20000u);$ T5 [$ r* Z( h0 |; a @6 {
- glListBase(base);
/ Y2 t, V- h; Y4 P* W4 L$ T - v5 = strlen(&lists);
$ {; O0 L# R) |8 ?# y - glCallLists(v5, 0x1401u, &lists);
! m( e( }2 j; S! ^1 D& F - glPopAttrib();
' Q; Z+ {) V- I6 Y0 i# m - }) d3 r; ^6 Z: S% {% n9 }
- }
复制代码
9 X3 ^$ F \4 Y9 s; }. m) ]0 o* J- E2 S1 Y; U% {8 |- X# @
. @7 u h& R- W( s/ ]* I/ k
第3处4 Q2 j w8 D8 h" s
- 8 N/ y1 |" k4 o" e' r
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)4 Q D; o7 ?) S4 T/ j6 b0 d' s
- {
; a5 T0 f7 U( T4 o) S% m) e - GLvoid *v7; // ST08_4
8 f, T; z# w: I% \8 w - GLsizei v8; // eax
& b4 D3 d* f- R0 O% x/ ]. p* H4 u - int v9; // [esp+0h] [ebp-1018h]
& q9 S- S# V+ |* ^9 R - char v10; // [esp+8h] [ebp-1010h]
+ J U1 {& \: c8 `2 e" F) n- ?7 ~' Y4 T - GLvoid *lists; // [esp+100Ch] [ebp-Ch]( C8 h! {) q4 z, W) k, B* c! M
- char v12[5]; // [esp+1013h] [ebp-5h]
9 x( B4 z% b& {7 l' l - va_list va; // [esp+103Ch] [ebp+24h]
& ~7 m/ g) |: ]' s# B
3 u0 q! p4 k! C7 f& u4 N- va_start(va, a7);
, N+ h; B: @: F5 X) N - v9 = 1;
% j) k5 }) V' U+ T! | - if ( a7 ), t, j; Z4 U) y1 s7 ?( ~; i% q
- {% F( e D) G: g M7 r4 r* t2 a0 k/ O( S
- vsprintf(&v10, a7, va);
( m7 O, P5 ^- @3 l3 h, U - glPushAttrib(0x20000u);
+ M7 W- X4 X/ a! d& j - glListBase(base);
0 C+ |5 b; Q$ q" y. e5 H0 B, i, Z - lists = &v10; n1 Q: m' B. c. ~5 V* Q* p7 ]
- do1 a4 x% d2 f3 }5 o+ M Q+ J
- {
" {' f2 a( y/ ^* P" g - *(_DWORD *)&v12[1] = lists;
# i; w/ Y0 V( Z. S - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )6 U$ [) f! A8 e7 ~9 p( X& O
- ++*(_DWORD *)&v12[1];6 p/ r$ d& J- b$ n
- v12[0] = **(_BYTE **)&v12[1];
$ c0 N r( _0 a# y- X: B4 U( | - **(_BYTE **)&v12[1] = 0;0 e& o/ S) e$ S
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
# p0 ]: L# {' o. q5 C7 @ - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
% e6 I5 k, G! j1 }' E- t/ [# A - y -= a5;
7 O D) i" `2 `3 \* \" c - glRasterPos2i(*(_DWORD *)a4 + a1, y);& T$ ^! d' |1 \3 W E2 D
- v7 = lists;
) I& r" u' [! @: c1 P {' e - v8 = strlen((const char *)lists);
; O6 {+ e/ e* F2 Z+ ?- [$ H" O/ ?2 O - glCallLists(v8, 0x1401u, v7);: n6 y; d! O3 C
- if ( v9 < a3 )
% V) w( k4 Z3 F - a4 += 4;: ^+ q& d/ S9 t; u; V; b Y4 W. ~
- ++v9;, c- J% z7 K' u& ?
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);1 x- Q8 U* E5 j# n
- }0 p8 y# c; P6 X
- while ( v12[0] );' o/ S8 T( A5 E9 Y6 G
- glPopAttrib();
7 h6 b0 i! h% {2 G8 g- b- t# _ - }$ P- [0 u- A- E% H6 S5 ]; @9 q) B
- }1 X# y# G, Q# @4 R0 H
复制代码
% k8 V5 C! E4 W$ q! u调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
+ g1 Z9 X3 Y' u5 F$ L. T3 }% y, A' n/ x4 e! N( {+ f
- .text:004512B1 52 push edx ; char *) y* I/ U Q6 z, I5 {# _
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
& w/ j9 ^/ T# w$ Z) Z) e - .text:004512B5 50 push eax ; base
( k1 H$ @: {5 T# [7 s; X' l - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
b1 @! h* n: f- @ - .text:004512B9 51 push ecx ; int
+ z7 v7 `- m7 ]0 r6 W - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]) p$ g5 |. z7 q/ [
- .text:004512BD 52 push edx ; int
% I; t: X6 b' v' P2 a* { - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]5 ?0 R! m: i; E% `# W* r
- .text:004512C1 50 push eax ; int
7 s. F' U, r) S e - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]! u7 K* ^/ |$ F
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
) [1 l7 r" ?3 `8 m6 M* m- X - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]0 B3 E- w- x5 |
- .text:004512CB 51 push ecx ; y' m& k" K1 z6 x3 S, ^8 l+ {
- .text:004512CC 8B 55 08 mov edx, [ebp+x]( i) r/ `: I- F4 D3 _
- .text:004512CF 52 push edx ; int; r( g' ]& a% {+ N7 U6 U
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 8 E, D9 l9 O" y
chatGPT整理过之后,如下* s; E) A! D) c: M
; T- T( Y+ {9 I+ ?
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
4 M* R4 ^5 ?. c" x1 A - {, E' S4 Y, ~$ D: f6 n- G/ t
- GLvoid *textData; // 存储字符数据的指针! o3 c4 v4 d. g, }# F: j
- GLsizei textLength; // 字符数据的长度+ b. E* Y# I$ m& W
- int lineIndex; // 行索引
. F; g- y1 K8 S& ?+ J; D - char formattedText[5]; // 存储格式化后的字符数据
2 M" k- U) @5 A( a6 W - GLvoid *currentLine; // 当前行的字符数据指针- N0 L+ y# z5 i% ?1 E
- char buffer[5]; // 字符数据缓冲区) p/ u1 |. v" L! j
- va_list args; // 变长参数列表# }6 d, P# y# K, A& s+ B
- + x* V( W& ]& U
- va_start(args, text); // 初始化变长参数列表
( a& G6 b9 k% P" ~ - lineIndex = 1; // 初始化行索引为1
& S- ?3 ~6 _( W - 5 j: `$ G6 R4 u! h, J2 O# f% G
- if (text) // 如果文本不为空
. @6 N& x; z# l- V( g2 } - {
4 t6 Z4 S) i& f/ }! c9 \6 ]* S - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
( A# H" s+ Q3 [% B4 N. z - glPushAttrib(0x20000u); // 推送OpenGL属性状态* w3 n: x* Y; X2 M
- glListBase(displayListBase); // 设置显示列表的基础值
9 J1 V# D6 m; P( J o; [ B - currentLine = formattedText; // 将currentLine指向formattedText的内存位置# j4 K& A; y3 F
- 0 z) q0 F/ J" M
- do r1 D( b H) @9 F# R
- {( b; t) J. ^2 G: n5 ^
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
& V/ F- p" C! r( R$ ~+ N - 9 K3 a# | S- [/ z7 t& _7 O# A
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束* o# e( N" \+ \+ x2 j
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素! K' j/ W5 f, b% z: i6 u/ [
; w. Y1 U+ G# B7 R) R8 A1 Y# v- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
6 G0 i2 z9 J% J+ j; s6 n - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符4 x0 n6 g) H0 r
- 1 T9 a+ u; N4 T7 |* I$ @9 ?/ d$ N
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
0 S( m* [$ z& N - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符4 i6 e2 z6 ?; f ~
/ Q7 D$ q* k* h& O( j2 [4 ?- yOffset -= lineHeight; // 更新y坐标8 M7 F5 z1 B& _, @
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置" _0 s7 i* V7 R" H: j
- textData = currentLine; // 将textData指向currentLine
( {" c3 ?9 c, i - textLength = strlen((const char *)textData); // 计算字符数据的长度6 u. g" i3 L6 P- p- S) R7 M" c- G
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
: L7 d) K9 [! H3 y& T9 D
$ N8 L, ~. M0 S2 d; Y- if (lineIndex < numLines)
7 |$ H8 q. x8 P; T - lineOffset += 4; // 更新lineOffset
- i2 p w X! ^% d7 U. S. a" ^ - ++lineIndex; // 递增行索引' h' H2 s' O7 V1 P; G# P( ~
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
* H0 v/ ]; o t% E- z3 \1 O, z - }1 Q0 o* u4 ]6 i# b, k
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环4 T( b7 H$ ^* S4 v
- glPopAttrib(); // 恢复OpenGL属性状态5 K0 O& ? n: E! p5 V1 O) L
- }
3 D; y6 I1 a6 S, d - }
) x( M& { |2 U3 w9 B
复制代码
! B' F: w; a8 n7 m8 `: ]含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
4 O$ ^- ?/ z8 Q! p+ A K" @1 \
7 W+ i) t! n4 j+ M7 t6 V* N% ]4 Cint xOffset, 字幕的x坐标& l- o. @9 H& X& G
GLint yOffset, 字幕的y坐标- Z$ M. |% K( v/ l- W1 L4 x
int numLines, 字幕的行数(较长的字幕为2,一般为1)
2 c4 d7 G5 {( @" C2 ?int lineOffset, 这个需要再研究
6 N e9 s5 D0 \& V% l6 A7 xint lineHeight, 字体高度(或行高)
G$ z1 L- ~) |8 ~8 k. {GLuint displayListBase, 这个字体对应的base值
6 p" s" N P {6 `6 jchar *text, ... 字符串
, o/ ~4 X- }/ Z3 A1 E9 ~# N. x
% Q0 I* P% C/ L: b |