本帖最后由 shane007 于 2023-9-5 16:49 编辑
9 U, j" v7 ]7 S3 i0 N
4 \; u0 [, F: s( p6 _这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
: a( j# \( D: f- q$ K H因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
: U; f- t* G9 s1 ~. `https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
$ i8 H7 X. u* H2 _7 g: ~第1处; R8 I. S! E' S$ K. R8 G# K
- void sub_451474(char *a1, ...)1 b: { [3 e& N7 T% i* r
- {4 t) F( ^) D$ W6 D9 x% q1 c D
- GLsizei v1; // eax
9 G+ V+ r8 ]/ A$ ]; g( a" y' e$ n - char lists; // [esp+4h] [ebp-800h]
2 J" l9 Q8 A8 u* k$ |$ s$ ] - va_list va; // [esp+810h] [ebp+Ch]+ M2 `: A* y& Z
- # b5 ~$ W" p0 `
- va_start(va, a1);
' }8 z* h& `( R3 T& v8 Y+ }6 P7 q - if ( a1 )
4 G3 l: ~: _0 p$ } - {% M: o. a) t6 Q: S# I
- vsprintf(&lists, a1, va);
- B' j: U: |* c% K2 S9 c# W, T - glPushAttrib(0x20000u);
/ o# T2 a1 W& k* e. k+ L: r - glListBase(base);
4 a6 M7 M) [) d6 r8 b/ V - v1 = strlen(&lists);. H% n. A! A3 O- a F
- glCallLists(v1, 0x1401u, &lists);; j8 Z( n. [- {( I5 }
- glPopAttrib();
2 q! o8 [$ M) z1 p$ b( g - }) U: k! ]2 ~; q+ v( I1 z) V
- }
复制代码
8 M0 |/ E W; I: E2 ^) x3 u! a& y: G0 l. a- W% C/ M
8 m' Y9 K: Q% V' _3 |第2处
R2 z8 R( w2 B- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)) V5 t3 y$ p2 X' h7 V s
- {' V) \4 T: W% c: }5 \4 \+ U
- int v4; // eax @! _$ v8 l4 p0 m" l
- GLsizei v5; // eax
; y9 E+ @; p$ r+ d" S& A - char lists; // [esp+4h] [ebp-800h]
! X- B: U4 k4 w' l m - va_list va; // [esp+81Ch] [ebp+18h]
6 _2 u1 b# r) u i" F* g: M
7 R6 Y9 K5 v( v7 P# L+ O9 \( t- va_start(va, a4);0 c( v! G2 p' u( ]8 n& W" H
- if ( a4 )2 `: X; t: b5 N8 x: z7 l% [
- {
4 @ i: E! w+ C, V - sub_44F8A0(a3);7 H* h1 Q! C& ~+ p7 J7 Z. s
- v4 = sub_40BB44();" x3 {+ j, a! M/ P5 @" Z$ o
- glRasterPos2i(x, v4 - a2);
: F- }9 [3 F7 h2 a9 K - vsprintf(&lists, a4, va);
2 W. j# p- g7 v( w4 k - glPushAttrib(0x20000u);
3 d; ~8 g( N- N4 g* n9 l* ?2 T - glListBase(base);
5 M* i( v9 E4 u - v5 = strlen(&lists);4 E% |" p# [ W; v
- glCallLists(v5, 0x1401u, &lists);1 \% i/ z# B7 W, n x
- glPopAttrib();" Q' Q# B3 |" Z$ ^
- }
0 T* w3 `8 K7 v1 T" M1 p J: c - }
复制代码
2 v( x" {# f" L- @( _2 Q/ ^
: H! M) G' [2 V7 \" g/ a7 D, W+ H" _6 q+ f' \
第3处
; v2 M$ J) o# q" |+ E- 8 C6 U/ V: u4 C0 Q/ Y; u
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)' O5 G0 D N3 A6 E
- {) p% ]# \4 d1 n8 h" m- o
- GLvoid *v7; // ST08_4( Y) _- p* R n: J8 V
- GLsizei v8; // eax
! t& C3 U* |( Q6 B+ k - int v9; // [esp+0h] [ebp-1018h]8 H# R' {% X% K7 |# Y- l
- char v10; // [esp+8h] [ebp-1010h]
+ c D& y, ^& }7 v& E& i, Q - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
% T8 E3 m* ]- u" |/ [ - char v12[5]; // [esp+1013h] [ebp-5h]
4 c3 a/ a0 K9 i' c. ^ - va_list va; // [esp+103Ch] [ebp+24h]5 f4 m/ q' m! G0 I
6 A& y6 y+ a% _# Q! c- va_start(va, a7);
: z2 J3 Z5 T, q' C - v9 = 1;- ^) u/ ~) B" r" z$ H+ z& L3 I
- if ( a7 )
8 {: T" l8 q# Y+ G3 V - {
) I1 T' j3 C/ p) x! T - vsprintf(&v10, a7, va);" a$ V$ z- ~6 M% R4 q S" J& P
- glPushAttrib(0x20000u);
1 K) Y' r0 m2 |5 @" x - glListBase(base);5 D$ j' V6 H- A0 R( z
- lists = &v10;9 R! e6 _) \6 A: _# C2 E4 S1 F
- do
/ ]; |) \7 R3 V% i+ S - {8 T4 f6 O$ G& I# P; ?) Q3 M1 y
- *(_DWORD *)&v12[1] = lists;
9 }% K; [5 K% R. S+ e) W4 V0 f - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 ). `* v3 i; }; m6 f# _7 T8 v+ R2 m
- ++*(_DWORD *)&v12[1];, B% E8 d5 D3 ~: ]/ R
- v12[0] = **(_BYTE **)&v12[1];1 m5 {5 t" `: o* ]" [
- **(_BYTE **)&v12[1] = 0;
5 z1 y- V$ q4 Y6 @- ] - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )" ^9 ]5 W* [# B2 o' c. G% G' [3 F- R
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;, O0 ?2 c7 B" o- N
- y -= a5;- o* G( n/ a0 d6 F
- glRasterPos2i(*(_DWORD *)a4 + a1, y);
. ? G: k, n& f7 {5 H& C. |& t - v7 = lists;
4 {+ H3 t0 i5 U4 x - v8 = strlen((const char *)lists);
, ^( h7 Z+ z/ o! l - glCallLists(v8, 0x1401u, v7);
6 O: e- T. `# W: N - if ( v9 < a3 )
# \" |6 V% f7 x. O$ O - a4 += 4;
5 s" r- E. R: ^% K0 i4 e - ++v9;6 J, V/ n! I e
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);& w& D$ a" L, |9 Z0 q& j9 u' s
- }
+ ?+ a! [( g0 c7 N4 _! J - while ( v12[0] );" w8 v/ R5 W+ x, w
- glPopAttrib(); `4 f$ |% y0 \9 M! u
- }0 f1 o6 p0 u, W0 ]
- }
0 y% P+ v$ m/ `/ Z% m2 n
复制代码 / y0 m Z2 c- I/ T9 p# I
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810- S& p- @; N. p( X: z+ @4 ~9 f/ G: S
6 F% E6 V. p& {8 D4 R1 I& D# U2 X/ G: J
- .text:004512B1 52 push edx ; char *; p2 _1 N; ~7 J7 p0 }7 z
- .text:004512B2 8B 45 30 mov eax, [ebp+base], R5 o, X5 y* u
- .text:004512B5 50 push eax ; base
" A/ Y: ^' w- f! u; C. N8 _1 Z7 L - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]( w3 h4 H( R# X8 M
- .text:004512B9 51 push ecx ; int
- {5 t) z$ Y- ~; z/ C - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]# N8 ~# u5 j' Y' _' y' q
- .text:004512BD 52 push edx ; int7 \" D( c4 v9 u) t
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
& S! [7 m P; b - .text:004512C1 50 push eax ; int
* `6 _9 ?% K, _& X- Y' L, R - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]" Y7 M3 W: X; M4 t5 ^( D! v; `
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
- I* P. ~5 ]1 q - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]" Q1 ~, ]/ F2 k! b6 t
- .text:004512CB 51 push ecx ; y
; R& `) T2 S0 _ - .text:004512CC 8B 55 08 mov edx, [ebp+x]
- o% Q6 ]# s( L; s - .text:004512CF 52 push edx ; int* ?- {/ S9 q/ W; n
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 , p, \9 A1 x5 q+ W) _% X( H! d9 V& J
chatGPT整理过之后,如下4 X4 m3 F+ c0 |7 q- U, s& x
% d E( ^/ [0 _5 \
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)! V5 a3 W4 h$ g1 p/ K
- {
( O8 N _3 v$ H - GLvoid *textData; // 存储字符数据的指针7 g6 ~6 d+ @. m7 n+ W
- GLsizei textLength; // 字符数据的长度
1 I# W) k' N! H6 J2 L2 J - int lineIndex; // 行索引" p% [$ Q$ i; n; i
- char formattedText[5]; // 存储格式化后的字符数据& q% y7 P' z A' K) Q! C; I
- GLvoid *currentLine; // 当前行的字符数据指针
9 |% g2 p- b2 @ v& p - char buffer[5]; // 字符数据缓冲区
5 \8 z [1 i, B( V E+ A2 T* E$ l - va_list args; // 变长参数列表
0 G' s4 q3 N& {/ C" d, `% f$ t
8 T- z# \0 h; q( W* A4 K1 e* Z# l- va_start(args, text); // 初始化变长参数列表
! R. y2 n/ F1 u. f - lineIndex = 1; // 初始化行索引为17 t& {: a J/ i8 ]
% _- c7 p% r# T6 H2 K k- if (text) // 如果文本不为空
8 @9 s% h6 w2 Q; H f6 p! f% t - {
# {2 M" _" J( X - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
( k) T9 K1 ]+ }5 W2 l2 C4 l+ I - glPushAttrib(0x20000u); // 推送OpenGL属性状态7 C1 i) S7 U! v6 R( L
- glListBase(displayListBase); // 设置显示列表的基础值
' `: k* D2 f& M; \* K5 F2 u - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
! }" E+ U0 G; U( L9 |1 Z# r - % O! @0 r. R+ x, N
- do. L p$ @2 U- b# c9 K9 f- a
- {
2 w" u, [1 m# b& r& D; k - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素# o% M' J# Y3 b/ g- G) `' t+ z& p
' y. ]/ y+ v7 J1 h) i- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束8 U# A* a d0 n Z, o
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素0 j; E/ M7 |. c5 y* j0 b
- ; U0 T! y; Y$ ?, T; K( [ E
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素5 Y& q2 M0 u/ _$ k$ O# z
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
, k0 ]' n5 W; L A; ?6 A - # l" o- L6 A! y6 L& G9 R
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
2 R' K# V3 [$ {, b U2 I7 c - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
* l6 v. I) T7 q1 d
( Y# p. e/ z( _3 ~5 i- yOffset -= lineHeight; // 更新y坐标6 ^) E0 D- W, l1 s8 a8 a I
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置( u4 O, W7 U q- `9 w& v) n
- textData = currentLine; // 将textData指向currentLine
- \: [* C* [8 i( d) G/ e) S - textLength = strlen((const char *)textData); // 计算字符数据的长度
* Y8 T" P, U1 R5 `* y - glCallLists(textLength, 0x1401u, textData); // 调用显示列表, f& Z; J9 M4 q# i; Z- j$ O' E1 v8 O! N
- 2 I7 x( @ s, q) k9 ]
- if (lineIndex < numLines)& `; B1 T$ Y3 {" h4 m9 I
- lineOffset += 4; // 更新lineOffset
r+ ~! t& k$ y o - ++lineIndex; // 递增行索引, q/ }8 h m7 ?# u& I% |7 A
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
+ G) R& ~/ e! y3 H# \+ U - }* g) n! ^1 b; Q* n
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环! N; g/ S" ^# I6 Y) g
- glPopAttrib(); // 恢复OpenGL属性状态* b0 s! D' D) t/ c: M* ]' K
- }
9 t2 _% Z, E- h! k7 K3 [; O7 a - }, p( z; y5 S8 u3 N& b. h9 G
复制代码 ; y- N) y$ C/ K+ D# k
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前1 Y! W: E7 |/ A: k) L! d3 _, ^
4 m4 a% y1 W7 g. y% P+ a3 mint xOffset, 字幕的x坐标4 ~ ~; c* L2 ~( Z3 r- d: y+ W
GLint yOffset, 字幕的y坐标
_$ T3 _6 K* c% N' O6 B$ sint numLines, 字幕的行数(较长的字幕为2,一般为1)
6 ]" i6 Q1 i* W% b7 v Gint lineOffset, 这个需要再研究
( {( _& i% R2 W* b2 O0 Q/ ^) t; pint lineHeight, 字体高度(或行高)& x% B+ W0 ~1 c' N
GLuint displayListBase, 这个字体对应的base值& I! ^0 {9 K8 l2 S' `
char *text, ... 字符串0 D6 [0 y0 M9 w5 C. o
; M& ~, W) G1 O& `! g
|