本帖最后由 shane007 于 2023-9-5 16:49 编辑
. V2 {. c4 b6 l Z5 H" H( ~4 a
" w! ?0 M- g4 w4 e* R3 s A1 z这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
p" ?# f; Y& d3 o8 L! K K因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
1 l, a/ q" B6 y. I- r$ ihttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
$ W' M8 Z6 `+ C9 E7 N) k第1处
# d/ Z8 C/ D: D9 J# R- void sub_451474(char *a1, ...)" x J& h; P# R, G8 I
- {
# i8 c/ d1 Z6 Z" Z) Y# R - GLsizei v1; // eax
! i$ ~ b& D9 I! Y. |. k - char lists; // [esp+4h] [ebp-800h]- `$ t) f% c, Z* x4 a$ Y9 q& L
- va_list va; // [esp+810h] [ebp+Ch]
- ?! ^ z5 ?* \* c Q9 x - . o/ I- l* R/ O- `# [8 @; [5 M4 G
- va_start(va, a1);
/ S7 c) L5 Q' x) _- u2 c" O - if ( a1 )
9 u6 o6 I# I6 j/ C - {- O- P$ y% o: @
- vsprintf(&lists, a1, va);
# j2 g9 r% v: S/ v T6 |, ~ - glPushAttrib(0x20000u);
X3 ?) }) O* u# c! Q/ ? - glListBase(base);
2 m4 N# g/ O ?& A4 \9 \% C - v1 = strlen(&lists);2 W" `! K- c Y9 p' y: ~, v
- glCallLists(v1, 0x1401u, &lists);
# }* E( X8 r2 o' N" E - glPopAttrib();) l; V& { o. i' k
- }
$ q8 u0 X# k c5 }% o- k0 J - }
复制代码 % O2 s3 ?7 L3 f9 }' Z* D# j/ Y' r
/ T9 S) R! s! r( v0 L0 ?7 c
2 e( a! Z, I) ~! C8 U( ~第2处
8 t6 T7 ~, O: F- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)6 Q4 ~0 w1 C/ m- l% h
- {2 b% q( f6 D" R ~1 S. W
- int v4; // eax0 {( x4 {6 {6 N% B
- GLsizei v5; // eax2 o, u" f9 a. C- l
- char lists; // [esp+4h] [ebp-800h]! A3 \+ K$ B1 o) p5 ~8 W
- va_list va; // [esp+81Ch] [ebp+18h]
/ b9 `2 A+ ^) L: |+ u
1 k4 K, y0 r* u m- va_start(va, a4);
; m* h3 ^6 v& b: V. T, | - if ( a4 )
0 s* D8 M; ]. V - {
( Y* i6 S6 o3 Y2 Y - sub_44F8A0(a3);% _3 s8 ^7 L" c, A" }
- v4 = sub_40BB44();& ` a2 G( I8 x, n$ {
- glRasterPos2i(x, v4 - a2);7 A% k: l* [, q6 @4 T
- vsprintf(&lists, a4, va);* J/ ~' H4 T/ q. o2 d) V
- glPushAttrib(0x20000u);
' J0 k+ C( S) Y+ G7 S0 [2 \ - glListBase(base);6 B4 O1 F2 B7 r5 e0 t' h
- v5 = strlen(&lists);" p' l* n0 E7 p( r& w5 E
- glCallLists(v5, 0x1401u, &lists);8 ~- l1 h& {, G* [7 ?
- glPopAttrib();
: G. d( D% u& \ - }9 |' U: x; I/ Z. y# f( s
- }
复制代码 + }/ R) I' [- O1 ^, y+ U- [0 w8 }
4 E p0 ~3 s5 \: Y7 f3 F7 H$ H% M# H- m* `" n) M$ \
第3处
) y9 A" T9 M* J5 u+ S, D- / }; d4 {" |# w8 X' Y, a% Q
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)9 K( h: c6 W9 c6 q5 G! G
- {- ]4 G, T+ g, m+ C; Z- W
- GLvoid *v7; // ST08_4/ p4 s( h8 I9 O- i7 C3 c( i
- GLsizei v8; // eax% ?7 `$ S( s w) f
- int v9; // [esp+0h] [ebp-1018h]+ ?& _0 Y. v& C# ?7 S
- char v10; // [esp+8h] [ebp-1010h]
9 q4 M' K; _' D' y - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
, p6 y, K' c3 N) g3 F - char v12[5]; // [esp+1013h] [ebp-5h]4 N4 P! J3 ?$ H
- va_list va; // [esp+103Ch] [ebp+24h]7 C b4 w; A/ [! J
$ q ~( f2 J$ X- va_start(va, a7);) L' P! l" {2 b$ P5 z# m2 S3 _- b
- v9 = 1;
: ~4 y+ c3 h' ]$ m: r) t8 O% I - if ( a7 )
+ j; U# ~% B" H0 a" N" q" d! O - {; k3 @( D2 o6 ]" l6 M( j
- vsprintf(&v10, a7, va);' v B2 v, C# e; S K; ? G: m
- glPushAttrib(0x20000u);
2 _: J! s( M9 a - glListBase(base);) K& H* m8 @, u9 [' |0 I
- lists = &v10;
+ P4 f9 n% g' \( T4 m# g* ` - do
/ l8 d& c! Z7 E- H9 H - {
/ V/ O9 h: Z- A, H* r# U! o - *(_DWORD *)&v12[1] = lists;
8 D: A- L0 u3 W1 S - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )4 h4 n6 k0 d: s6 c: ^3 N3 V
- ++*(_DWORD *)&v12[1];
# S6 F% \" i0 y9 ^: j6 i; [ - v12[0] = **(_BYTE **)&v12[1]; S9 Y S0 L J& R+ ~8 z- \ q
- **(_BYTE **)&v12[1] = 0;' B7 _2 W9 S% Z6 }; h- F
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )* A* i9 i0 `$ b5 [( {: N
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
! F u( P! t: j0 g2 Q" s2 b - y -= a5;
+ \, _* z- n$ d2 g8 P - glRasterPos2i(*(_DWORD *)a4 + a1, y);; [2 y* }" B8 V+ A% m
- v7 = lists;2 o/ l) K! N( S: l" `4 r& L
- v8 = strlen((const char *)lists);
: o! O f+ ^2 A( z. } g - glCallLists(v8, 0x1401u, v7);
- o( V, R( D9 F. ` - if ( v9 < a3 )+ S, S5 k/ g% T, q" D4 d- }3 C: ~
- a4 += 4;9 i4 `' ~9 I6 W9 w
- ++v9;
# m" J k* d ^/ C) F3 b - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);2 t3 i* N2 v1 v* e0 ?, N/ E
- }
& J- g* g% g3 ` - while ( v12[0] );( Z5 I* e, o2 J7 J* N- g p
- glPopAttrib();* u/ e( w2 I2 o. w0 n: c
- }
2 U5 ?" @2 D$ B' ]# f - }
3 n+ t* L/ C; K& F3 d+ k; {* Y
复制代码 3 a, l4 @8 C! S( e" G. i9 T- Q0 Y& b. l
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
2 y( q. f# J9 e( z. q, i3 G$ Z% V% ?) J4 Q7 _' e/ j9 ]9 D. S
- .text:004512B1 52 push edx ; char *$ Q3 g- b+ g6 w: M
- .text:004512B2 8B 45 30 mov eax, [ebp+base]5 G7 X# R2 L. P( f9 J7 }
- .text:004512B5 50 push eax ; base
/ Q5 q% o2 A/ {) ^% \+ I - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
D( C( t2 d& _5 K* o6 ]+ b - .text:004512B9 51 push ecx ; int
8 X l$ e5 v1 n: I0 e* F, I$ X - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]# x6 T# Y1 Z \1 R) n+ f, n) Q
- .text:004512BD 52 push edx ; int+ w# O; S" [: I" o6 q
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]& {! s9 f; o1 d. a
- .text:004512C1 50 push eax ; int
% N* b2 H- ~4 j( R& w7 N - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
. Q" C# X" H1 R - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
0 X1 R6 @% `" c; B- ^* v; u4 D% G - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
. i* @. k# g) y - .text:004512CB 51 push ecx ; y
) T2 I0 n; R& w: ~& F# ^; X4 L, L - .text:004512CC 8B 55 08 mov edx, [ebp+x]% e; ^' [4 s7 q
- .text:004512CF 52 push edx ; int9 C4 y- {: h# L+ Z) e# i; E
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
1 A9 A# _+ _0 w1 c% xchatGPT整理过之后,如下 z6 O( e w4 @ B; |
' s& V2 O, F/ d$ |: @- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...) B) e% B/ b' o4 N( U. l0 T7 P9 b
- {
3 j$ L) a) [6 I8 M2 w, ? - GLvoid *textData; // 存储字符数据的指针
& m( e2 V& T; X O. @5 `3 a - GLsizei textLength; // 字符数据的长度
3 E( O. k K# i1 T5 K0 }6 i2 O [4 Z* B - int lineIndex; // 行索引, S& W# n) E, ]( r5 S }
- char formattedText[5]; // 存储格式化后的字符数据
; ?3 F1 Q! Q) m7 i5 w - GLvoid *currentLine; // 当前行的字符数据指针9 K5 R8 y+ K+ y( ?, I( u$ _3 @7 B
- char buffer[5]; // 字符数据缓冲区
0 S" T; w ^( Q( g% u' P - va_list args; // 变长参数列表% a( D" V6 Q: H. M4 d
- " Z( S, z0 ]7 t3 L( T* L
- va_start(args, text); // 初始化变长参数列表: M" o: o5 Z- |5 H5 K0 \. q
- lineIndex = 1; // 初始化行索引为1
+ K e* }; G, b' V5 l& i - 2 \$ t+ P1 k; e+ U3 B: {
- if (text) // 如果文本不为空( H/ ^. d/ K% h* r8 F
- {5 X7 t1 S8 M1 b; W: C4 E+ i
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中, N; p1 S/ x" n9 s/ c% t
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
. b% [" A; X& p/ M6 q - glListBase(displayListBase); // 设置显示列表的基础值; O' \& }" x0 R- P; z4 \
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置5 X9 U1 T, @9 r
1 a' M& v2 L w- K- do& m' f R2 p/ V" y; K8 R
- {2 ]8 Q8 d4 @/ Q3 w) A' ?2 | @
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素) A9 o; R7 n: U# ~. @' q
- 6 d. g) B5 H0 H& b6 j; ^$ b
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
" }5 r. h" @, ^ ` - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素1 D) o6 \3 i6 R0 m1 n: C
1 D8 e1 |8 @. X" }6 l4 \- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素/ H5 T4 j1 D- V s/ c/ \
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符! @; U# E0 M( P" S7 t$ C
- * i% H% l' n6 T" p& _& o4 t- F$ K, [
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
' E) v" K0 p7 t" N6 A - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
3 u" X5 ]. s" M$ s# _( e9 } - / X; @3 s8 v( {4 R3 {
- yOffset -= lineHeight; // 更新y坐标
, b4 p g) X$ Y- S0 J- U - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
, i8 h& O8 R2 f, l4 b - textData = currentLine; // 将textData指向currentLine" V" q1 S; c7 m2 `7 {
- textLength = strlen((const char *)textData); // 计算字符数据的长度 H4 R" |) h4 k4 H$ J) b
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
2 u8 V' z$ x9 b8 Y. B1 P - 0 G' Z: {/ U9 k5 s4 b+ p. N
- if (lineIndex < numLines)
- F! p$ O6 w/ q+ b j3 } - lineOffset += 4; // 更新lineOffset
" B$ h$ `4 ~" u% {& \$ g - ++lineIndex; // 递增行索引0 f' l+ g. s" h' A
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据/ J2 B# N# X' z
- }% I, C' }* Y& _9 p; q- \
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环+ D, C" P) Q% `7 x! B% \) C
- glPopAttrib(); // 恢复OpenGL属性状态
5 K' h; c0 ?! j/ `' Z1 J - }$ u' G0 Z3 W6 H
- }0 E) I2 O" K% W
复制代码 6 r/ K; y) J" M& F
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
" C4 t# P" f, d- ?+ [9 E7 T6 r
- a2 N; Y, `( u8 Tint xOffset, 字幕的x坐标
/ f1 t# Z3 d& M9 h/ Y1 HGLint yOffset, 字幕的y坐标
% k$ b: W& }7 J# W$ mint numLines, 字幕的行数(较长的字幕为2,一般为1)# z' Z7 E) F) h0 \- Q
int lineOffset, 这个需要再研究: b& n/ C5 w% K& Y
int lineHeight, 字体高度(或行高)
! X# \0 _) R7 d( y. {8 t+ a* x8 N/ ~5 mGLuint displayListBase, 这个字体对应的base值
) \. t! E# b% j' zchar *text, ... 字符串" t. d/ ^6 [" |: p' |& G
3 o. l# ]. w) ] |