本帖最后由 shane007 于 2023-9-5 16:49 编辑
# e5 ]3 a3 y( y7 I' z1 Y: b" u
D4 v: V* }, L) Z; J+ O9 Y这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎0 T4 x$ l/ Z7 `4 P1 T+ O. p$ z
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
4 V1 H9 a# |, S! i, k6 k: Jhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=1540812 k( u5 \9 i/ T, l! u3 t
第1处5 y- H! z& v2 |4 g
- void sub_451474(char *a1, ...)
( @+ X6 Y' K3 l% z! T9 H - {
- {4 x: U( S w3 T- B; J - GLsizei v1; // eax
2 e8 h3 w! z9 o) `+ w - char lists; // [esp+4h] [ebp-800h]
% K: O, ^# ^, y, W( W* W - va_list va; // [esp+810h] [ebp+Ch]
9 r1 a& m9 Z0 H - ' U) i0 V" v% d0 e5 m& _0 |2 ^
- va_start(va, a1);
+ U8 }. e0 S+ E - if ( a1 )
+ v1 e1 b- ^/ t$ Y2 c2 G% {# y* u* j - {; E- v- K, [- a3 k. O9 z4 o- s
- vsprintf(&lists, a1, va);
+ ]: Z2 ^( G7 R. @- c - glPushAttrib(0x20000u);: o/ U, }, W6 g1 v6 r
- glListBase(base);: K9 w, k& P0 o" R$ G" M7 L' A
- v1 = strlen(&lists);
* C# |- y* d& D, K, `. {) E - glCallLists(v1, 0x1401u, &lists);
8 y H) S! l8 p2 T8 e( Y, h) b - glPopAttrib();
8 B3 N8 F; N$ L! U - }
# h% l2 V Y3 z - }
复制代码
+ L; h8 B7 Y8 i% q A4 v! J6 f6 h8 O# g T# p# Z8 T. |
; d3 d+ O5 W) `, a
第2处
7 P. x! A. V5 j, O9 P) I( x4 ?- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
7 m, A a% b" l: K; I3 q+ X - {
R0 ]0 i3 K1 o# R - int v4; // eax
7 n" t% ~' X) D9 ^% s8 F - GLsizei v5; // eax
7 O. t) w+ _6 ?. J# G" y0 J% o8 u; H - char lists; // [esp+4h] [ebp-800h]9 W) L: Z' s& y$ Z0 g0 w( u
- va_list va; // [esp+81Ch] [ebp+18h]8 Z- U3 e4 \6 e5 t" O! h5 _" ~
- % i5 `& s8 k, ?% I
- va_start(va, a4);
1 }" {6 \/ }: T+ [7 D' ^ - if ( a4 )
$ n, ]! @! X- K - {4 f% K$ R- S6 _% j- z V* w
- sub_44F8A0(a3);
: V: v1 k7 K0 @- d3 \# f - v4 = sub_40BB44();
) X1 @: M. Z0 s$ f6 H9 B - glRasterPos2i(x, v4 - a2);& s- v; S0 p0 ` y8 q" i
- vsprintf(&lists, a4, va);
. b" t& G# o( k; e - glPushAttrib(0x20000u);
8 U l. x7 v" L& i) y& C - glListBase(base);
+ B- B5 s- Z! g9 a" F! s# W - v5 = strlen(&lists);
3 X: x ]+ [' w% D! x2 v - glCallLists(v5, 0x1401u, &lists);
+ Y" G6 N1 b) W7 p - glPopAttrib();
0 f/ @, N) E0 T! ~ - }
( |1 M: Q% q7 k% l$ g! a - }
复制代码 ' H1 O+ b5 z- C# L1 c1 \
0 I4 J5 N' f) N/ l% ~/ D8 v
, e& {1 i6 ~8 U* C4 ]
第3处
6 u$ _5 N4 f3 x3 i/ T9 Y& n
2 w; J! T2 v- T. l9 R1 E- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
0 W/ M1 _2 q7 p( |' i, u% t - {
4 ~3 A- {) l' \6 ?0 k - GLvoid *v7; // ST08_4" P4 I2 u6 O/ V$ _% y
- GLsizei v8; // eax' A. i7 G& u7 z: z0 w
- int v9; // [esp+0h] [ebp-1018h]
" m# l! k' ?" Q$ }7 t - char v10; // [esp+8h] [ebp-1010h] |# g- C# U+ ~' ]3 a, ^: [
- GLvoid *lists; // [esp+100Ch] [ebp-Ch] U4 n+ `9 `0 U# x9 N$ U
- char v12[5]; // [esp+1013h] [ebp-5h]; n g% E+ c: i. b; z2 D' F
- va_list va; // [esp+103Ch] [ebp+24h]' h1 F1 R' B9 }5 i9 l
- + X3 n7 Z6 I& S; h! Q7 E
- va_start(va, a7);
& ?& ~) z! d8 h; [. n5 ^+ t - v9 = 1;
" t! J) N5 z' t& Q" S J - if ( a7 )+ i' M& R! _5 x3 p" N) G. |2 B
- { c6 z+ |/ M/ G0 L. E* l
- vsprintf(&v10, a7, va);% T) ?/ S" ?4 h( C+ \, s9 ^! L7 |
- glPushAttrib(0x20000u);6 Z4 ?0 l7 z" a
- glListBase(base);
/ W+ i( X1 v/ h/ l, I" k - lists = &v10;
1 Q) t2 W7 L" i" M - do
5 |" _! Y% Y; B1 x! Y - {
, V% z3 m" p0 @: f- a - *(_DWORD *)&v12[1] = lists;2 S6 D0 J1 M) @2 L. l# P
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )) I4 N9 f' O! f c5 K/ u. D
- ++*(_DWORD *)&v12[1];
) Y0 g- n; `5 Y8 Q) C. V9 C - v12[0] = **(_BYTE **)&v12[1];$ f8 {1 s4 G2 r9 p5 P9 M
- **(_BYTE **)&v12[1] = 0;0 m- P, @0 ^- W
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 ). X' b) A& K9 z" {
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0; p! }; N. R- s
- y -= a5;
. R2 x& m0 a+ y! q - glRasterPos2i(*(_DWORD *)a4 + a1, y);
2 N+ Q9 n5 I t% G n7 A% ~ - v7 = lists;
- g! A% ]( R# ?8 w- w; ?( a# {! l" s - v8 = strlen((const char *)lists);
) A# O) Z( ~, S% `3 S - glCallLists(v8, 0x1401u, v7);
2 Q2 H+ {. `% Z) c' M& @9 C - if ( v9 < a3 )0 ^% Q1 r- r/ {' v& A5 e2 R0 P
- a4 += 4;
/ r: ]4 z2 r0 a! y% J- N# u: I - ++v9;
$ N; ~4 p v( o- d5 Q - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
+ N( B* d z1 q% M, [" T - }
1 ]# F; \7 q6 j- \' N - while ( v12[0] );5 {0 Y9 S' c" d+ I: J& k
- glPopAttrib();
! c: J4 o, a/ S5 |# d! S1 |: d - }
" C' X6 v3 f9 Q/ |6 k q! G5 Y' y - }
* L& m( C, I# ~! e4 o
复制代码 : K" O% P7 U& o- X
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810/ t% n, g% T+ {: b j$ d
# p! z. A( ]7 Q8 I9 ?3 f" Y- g+ S$ V- .text:004512B1 52 push edx ; char *
$ p" O1 g+ q# n* U# u - .text:004512B2 8B 45 30 mov eax, [ebp+base]$ X# j( D( L8 {7 |) ?/ P; }
- .text:004512B5 50 push eax ; base
: _+ \% N9 t3 Z( V6 |6 Q) z5 Z - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]: [' ?) b- }7 k( z2 N- K: g
- .text:004512B9 51 push ecx ; int
# [/ v! X o$ T8 F0 @( v' H7 G - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]5 c8 C3 W3 c0 r. R5 N: ~
- .text:004512BD 52 push edx ; int
; E; X% `8 [. Q5 k" e: L - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
" w. l& i4 D0 v) a: f: M6 d - .text:004512C1 50 push eax ; int
& v+ q5 t$ i9 w0 t F) n7 t6 i - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]# P* I3 I k: y" o
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
5 K1 }4 w" n+ m% v, n8 [; _7 M - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]) t( T! B$ I" ]) V5 P
- .text:004512CB 51 push ecx ; y& G: c! _0 g3 m( A, h
- .text:004512CC 8B 55 08 mov edx, [ebp+x]
8 z+ ]: y( g# a0 Q, j - .text:004512CF 52 push edx ; int
& L! B D" v" e' C - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
/ }0 E0 n8 |9 P5 Q2 @; l2 p& CchatGPT整理过之后,如下
- t& K0 y' t/ V" u! r" C4 ^; S/ S) ~+ ~
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
6 \! x! y6 k4 O - {; U, ~1 C& ^' w, _
- GLvoid *textData; // 存储字符数据的指针
7 h7 V: G3 Q: N b' H- q$ w - GLsizei textLength; // 字符数据的长度: R G2 {% G+ p! z( f( I
- int lineIndex; // 行索引
: ^3 F! w+ z; g" G6 F6 a5 w - char formattedText[5]; // 存储格式化后的字符数据
* y. Q1 |. |: \$ K I N" l - GLvoid *currentLine; // 当前行的字符数据指针
4 q, I) [, n4 a4 s" G% C, O. p" n - char buffer[5]; // 字符数据缓冲区 I, A+ [1 T8 z1 [" x
- va_list args; // 变长参数列表; w6 g4 e K7 P, s
- 6 q! y$ n' M1 L% V7 u& f; \
- va_start(args, text); // 初始化变长参数列表
; H6 w: r0 K7 k1 w( [% [ - lineIndex = 1; // 初始化行索引为1
( k% g$ d4 K- b) y - 4 S8 o# Y6 h% D# U2 p% b! H
- if (text) // 如果文本不为空2 B: J9 V: Y, a5 a( U% c, u4 F
- {8 s W/ t1 k, x; X z5 [9 C7 e
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中! K' ~( b- G! R3 `
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
, g$ ]2 I5 C$ W$ ]* G - glListBase(displayListBase); // 设置显示列表的基础值
* }& W# n4 n5 q4 N3 h$ t - currentLine = formattedText; // 将currentLine指向formattedText的内存位置/ t5 _, y7 ^" k# P- o6 ?
- 1 n1 X. B9 W4 f" ^/ ] ]0 a4 ~
- do
/ ]- m9 V8 G2 y0 i6 ~' e) Q6 l - {
5 I7 d! ~ ^6 X+ T5 E2 N3 g - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
# u$ q/ R3 \" D/ u( i9 E - : M( \1 |! M5 `, X4 ?
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束! S2 z( g9 O5 P0 T
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素# y: L( ^3 y9 O
& ]- A' w7 N! C3 @% i4 |- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素5 J" k8 _6 X9 ?" v
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
0 w% O% a5 s8 t4 b - ! g( k5 s/ W4 G- h. _% a) B4 t
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)9 ~$ k* M3 D7 S( N5 l8 O% }/ m
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符1 b6 z v6 m; g: p; F8 [3 a& b
3 ]% L7 W- {3 o. |- yOffset -= lineHeight; // 更新y坐标$ H4 u* K8 P% X
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
3 F y: n( `2 C - textData = currentLine; // 将textData指向currentLine% n% I' x+ s0 f' H0 v3 l
- textLength = strlen((const char *)textData); // 计算字符数据的长度0 }+ a6 V: \+ r
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
: J1 p' X: P% k/ f7 P - " S' |/ |9 v& f' l2 Y& t
- if (lineIndex < numLines)9 J9 j/ [% z0 J# ~
- lineOffset += 4; // 更新lineOffset" A5 L% |) @- O9 ?7 r, I
- ++lineIndex; // 递增行索引
" z9 Y4 i+ Y: ` - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
8 z4 K6 ^* t0 z; q - } K' L0 Q" e W6 a- o
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
6 g+ a7 k) r6 O. G - glPopAttrib(); // 恢复OpenGL属性状态
3 T2 t& y1 F+ |5 d. s' ] - }
3 r5 r3 M2 v w" C - }
2 W2 F: X8 w) j* e, g j
复制代码
& A' D$ X# [) L含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
# J7 G9 b! z% Z
! |1 h; F) E( t3 V1 N" Cint xOffset, 字幕的x坐标( B- W+ f9 ~ O3 K8 w! U( r
GLint yOffset, 字幕的y坐标 X, E* H& v L* \+ R' x l# d
int numLines, 字幕的行数(较长的字幕为2,一般为1). F" p- E7 W/ U5 J' l. d* y& |
int lineOffset, 这个需要再研究. n: j8 v: d+ h+ E8 F
int lineHeight, 字体高度(或行高)! V/ o2 w) s! o. Q) s
GLuint displayListBase, 这个字体对应的base值* {5 `. U3 a }$ t# M1 Q
char *text, ... 字符串
- v. E+ K) H7 c: o# Z% }" f8 e
1 f3 Y9 n4 E( Y; P. E |