本帖最后由 shane007 于 2023-9-5 16:49 编辑 }4 `( @/ V' h' e# q
( o3 y( I6 n" n' ]9 K9 N% f
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
/ e: g. D/ v( j6 J: {* N因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。& E/ q3 @9 S1 w# Z& i( R
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
% W3 l& Z+ }' v5 `2 p1 P第1处$ A8 l: @) B+ T0 @. v7 A
- void sub_451474(char *a1, ...)
8 ~3 D' O: X! s2 e& }' D - {
9 ^8 E: y. M% F/ y! i8 h, m - GLsizei v1; // eax
- d) p. _: `9 ?( E- L! j( f - char lists; // [esp+4h] [ebp-800h]9 w' |9 u! C0 z
- va_list va; // [esp+810h] [ebp+Ch]
- ]' L3 }$ Y! z( _0 B5 u4 b, p
5 P8 P4 p' v6 |. U4 G/ t4 w- va_start(va, a1);
& [; @/ i* d" s. z- l) L7 z - if ( a1 )& M. D4 \- k9 t1 [% g2 L
- {
7 g* g& a$ w$ r - vsprintf(&lists, a1, va);
# v" H! w6 l. P) b4 j - glPushAttrib(0x20000u);
/ S I1 f) F5 F, Y: u6 u* V* i" L0 W - glListBase(base);: K q9 U' _& f! J3 a2 j* P' h
- v1 = strlen(&lists);
1 r" ~9 L( Z0 O1 V5 b: I6 L/ E - glCallLists(v1, 0x1401u, &lists);& K3 r2 p3 c7 N- y" L& |
- glPopAttrib();5 i5 V) W2 m, c2 @5 D) U) a
- }
6 f+ U* j, f* L' H! a/ N9 g. H# y - }
复制代码
$ o4 N7 O0 {. u" t/ h) ?
) T# c! q+ g. C7 z! D2 r d
; I# F7 b9 }( O) a1 O* h第2处
( w" V) h \% e6 P% {' L o- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
+ `# O$ n# e- Y2 j( }8 ^ - {
: M/ L; [6 Y+ t* T0 c - int v4; // eax
) \- }* u+ h8 z/ e3 K- E - GLsizei v5; // eax( s3 E/ _ `" v Q' E$ z* j: f! [
- char lists; // [esp+4h] [ebp-800h]
8 M# v0 k( l. o3 Y - va_list va; // [esp+81Ch] [ebp+18h]2 l2 C% e8 j. I$ |4 S4 w4 X
- & q7 b8 z6 F: T/ z# ~' i
- va_start(va, a4);
, M5 r1 K0 b: b" | - if ( a4 )
( ` N7 f8 F5 G8 I" e/ H( j p: B - {) E8 O$ v% O' k! h4 k u
- sub_44F8A0(a3);/ ] ?. d! v0 r5 n
- v4 = sub_40BB44();+ A, D6 d, o) [" S6 N9 _
- glRasterPos2i(x, v4 - a2);. e5 C) O1 G3 K
- vsprintf(&lists, a4, va);
z" d% k) W* i6 k - glPushAttrib(0x20000u);3 T1 m# |2 N6 D$ i% u q7 c2 K
- glListBase(base);" X: A6 e% q4 Y, E; E
- v5 = strlen(&lists);/ e9 z2 p1 l; h: ?, N' B
- glCallLists(v5, 0x1401u, &lists);
8 s: x9 u/ O. c% l9 |$ q+ J5 L, r - glPopAttrib();
! Z. P4 q$ F; P: j( X8 J - }/ `; a* }3 X6 L3 e+ C
- }
复制代码
7 m9 h& `* P4 m' D* x( L0 j
. {" M6 ~) ~$ x; f; A8 f6 V, r7 Q/ d' \4 ]$ u" X
第3处
' m) z! n- V# T/ Z5 m. S7 t- $ b1 [8 \$ g) ]+ x+ t; a
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)- N M* o8 }! a2 q0 ~1 l# k6 R% s
- {
* m$ t$ v X8 h) P0 H - GLvoid *v7; // ST08_4* q/ ]9 N" G$ n6 d, G
- GLsizei v8; // eax
. E8 W5 @' Y+ `3 Q( k1 o3 i- m. W7 Z6 ? - int v9; // [esp+0h] [ebp-1018h]# u0 P4 s+ z, |4 ~5 M
- char v10; // [esp+8h] [ebp-1010h]
5 B3 r9 V: F9 H5 e N$ H7 K - GLvoid *lists; // [esp+100Ch] [ebp-Ch]) v. N6 V/ B0 V- R9 a
- char v12[5]; // [esp+1013h] [ebp-5h]6 \. S6 J* i! E1 ?& D; r
- va_list va; // [esp+103Ch] [ebp+24h]
/ Z7 Q) f( x" Q1 h; Y# D+ W5 R0 @ - / w! ^# W: T9 q5 i- e
- va_start(va, a7);2 i' g! |; C4 f- M; S) T7 Y
- v9 = 1;
) j$ ]+ }4 h2 y4 q+ ?7 M4 h% j& w - if ( a7 )
$ p. z" }4 V. U1 @ S - { I5 Z3 ^, X" D* E4 M% D# s4 Q7 |
- vsprintf(&v10, a7, va);6 J3 B& U: x5 K1 V# x+ O1 B3 y( T
- glPushAttrib(0x20000u);
. V: H; ^5 m: {" c1 M - glListBase(base);3 m, ~3 j; x6 f: Z) W
- lists = &v10;/ V: t# A) ^4 k- P
- do, `% _4 Y/ o6 r( h. r3 Y
- {# `! B6 U" b1 M1 h* @3 w0 ]
- *(_DWORD *)&v12[1] = lists;
7 S- ?4 V% Y0 e. e& {7 W - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
. f0 i% h/ q* X( b* S - ++*(_DWORD *)&v12[1];" p4 W$ e3 W* f- J1 l8 w4 o X+ T9 E
- v12[0] = **(_BYTE **)&v12[1];
& ^% p6 D, z( r; H* b' C, ` }' e - **(_BYTE **)&v12[1] = 0;
& A! {$ [8 z$ |( x: s9 A - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
1 f v$ M/ F: D" h - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
7 T% Y) Y2 ~3 p - y -= a5;
) O5 r; {' e4 F( ~" L- t) H% \ - glRasterPos2i(*(_DWORD *)a4 + a1, y);! S; r/ g6 Q: q# N, I
- v7 = lists;
% m$ T- s, g" s( C" n1 N - v8 = strlen((const char *)lists);
, x1 T) z8 Q" K+ v - glCallLists(v8, 0x1401u, v7);
# a+ R& [, u5 U- T9 x2 T3 _ - if ( v9 < a3 ). f( ~. n4 \0 c; @6 B
- a4 += 4;
3 R1 n, t4 g3 [: @ - ++v9;
, F: o; H7 ?0 ` A6 A8 {3 e6 I - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
) x9 g6 g7 q7 E9 V/ m6 O* \ - }: n7 _6 ~/ _2 y7 X
- while ( v12[0] );
4 O9 F C `9 z, y - glPopAttrib();! h' `/ I- Y2 p" ]# g- x
- }/ j5 n0 A; }8 T2 {$ _
- }3 V) J/ \ S9 g1 B% O# }# w
复制代码
1 `! R2 H7 _& B& @* j调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810* h: c$ a O8 u$ c
! D3 C5 b5 D" h- .text:004512B1 52 push edx ; char *. K( |1 B0 }. a* t# ^" `
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
8 t8 m, G1 L9 P8 u - .text:004512B5 50 push eax ; base, }4 J- J) S# I' r
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]5 `, y- F9 ]0 y5 s6 i+ a
- .text:004512B9 51 push ecx ; int
3 q O0 ?: u @0 f& d - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
: y5 J( s F0 l0 L( L - .text:004512BD 52 push edx ; int8 {- k4 t' u( u
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]8 t+ E' h& {4 b& n7 |2 G% O
- .text:004512C1 50 push eax ; int2 O& H2 L- G. B
- .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
7 `/ g' p V' }( ?% B3 `6 s: t, y - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]: y: V9 V, c" L) K
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
* X( [& c$ d& S: K4 L: N# j! l - .text:004512CB 51 push ecx ; y
( R. h2 Q' u! r e' W - .text:004512CC 8B 55 08 mov edx, [ebp+x]- r. q: i( w- J
- .text:004512CF 52 push edx ; int" Y- l. g, x' G0 B3 k6 }7 r: |
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 H! I, g4 [* E& b% l
chatGPT整理过之后,如下
+ \1 b r7 D/ J8 }" K6 @) A6 f
% v, [2 f0 | t- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
* A$ P& S! L- u+ i% e( L - {7 t+ o# y0 M/ E# H- ^! w% P
- GLvoid *textData; // 存储字符数据的指针
# L8 a1 i c1 p! H; e - GLsizei textLength; // 字符数据的长度% j8 b- L: f9 j Q( X% V
- int lineIndex; // 行索引" u. K5 U2 k7 a
- char formattedText[5]; // 存储格式化后的字符数据
. r! Z/ X$ T, o3 ]& n, `' b2 P - GLvoid *currentLine; // 当前行的字符数据指针3 W2 W$ `9 w: L
- char buffer[5]; // 字符数据缓冲区
6 q$ L! {4 P9 O( M' Y* s - va_list args; // 变长参数列表( V# v) H7 K1 ]: w; q8 @8 j
- : o; I- ?* E2 G: k* S$ v6 i* |1 j
- va_start(args, text); // 初始化变长参数列表
% @1 Z3 Y# f! v. |2 H6 p- a/ } - lineIndex = 1; // 初始化行索引为1( K) @0 p2 u8 {3 \7 R m5 X
- % R6 \5 L5 U0 o, w, U$ T- P# d
- if (text) // 如果文本不为空
/ \/ ~0 @1 n; x1 y - {: R- }( \, ^& s
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
2 w# y V/ |( B# M5 ]0 @ - glPushAttrib(0x20000u); // 推送OpenGL属性状态) ^# _" `$ S9 ~6 y
- glListBase(displayListBase); // 设置显示列表的基础值
& S- c4 x: b V/ d2 i - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
) L" l3 b5 ]: u, C+ U
9 h5 ~ J: T( j0 q/ c3 _0 _. D- do+ U1 D. J# a/ _
- {/ a5 ?0 x& i" E* [- a$ G
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素( ^) B: z: e! B8 E
- 5 D' y! Y4 u+ S
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束8 M+ n' `* U* b, z" [- ]
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
q, I, r$ n$ w* p. L) m
7 J( G# \4 ]$ X. h. K- ^/ T5 [- W- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素( W$ M& S, m' ? p. ]0 Q; [
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符 |: A, M. |% A6 R$ J- e
- & C% z! n, @7 c0 Y ]% n9 N
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
2 l" X6 X6 w1 S1 V4 h- E - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
- z, q+ y9 K9 G4 h* }7 s
3 o6 z$ U# x: R# c1 q+ w- yOffset -= lineHeight; // 更新y坐标5 W+ @# H3 l* g; l
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置0 ?1 ?9 r0 D8 D4 ]" h- I$ N4 X, B3 o
- textData = currentLine; // 将textData指向currentLine# j# t) _& m! `
- textLength = strlen((const char *)textData); // 计算字符数据的长度# q% L& t9 n0 H) Y* C
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
) C. v7 N9 s+ d4 _& M j5 [/ S - 2 a2 K: J& c) I0 M( L
- if (lineIndex < numLines)
3 h6 I6 V+ u- y0 O$ T - lineOffset += 4; // 更新lineOffset% m3 Y2 |' \9 k- n# ?9 @! q
- ++lineIndex; // 递增行索引
3 R2 x' i _$ f+ U% j7 c - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据0 G! S, @2 Q% O- \1 N; j6 V& X
- }7 u( r3 T1 E$ q3 O- l2 P
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环# j7 H" Q. Q! A' k: O$ v) y- y V; ?
- glPopAttrib(); // 恢复OpenGL属性状态0 ]( D" `: l: b% c+ I2 G i
- }6 s! P, A) U7 c4 R
- }2 C$ ^5 q2 t2 Y4 G! V
复制代码 / ]7 I% E8 Z7 \- O
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
9 w3 k2 @8 G9 J8 N3 p- n4 a4 p/ S# a) c
int xOffset, 字幕的x坐标% a. h7 _( _+ J9 A A) y1 d0 U g& `
GLint yOffset, 字幕的y坐标
6 Z5 P( u) v' S. P$ d4 Yint numLines, 字幕的行数(较长的字幕为2,一般为1)) e/ ]9 R6 J( n& z9 q
int lineOffset, 这个需要再研究
" g+ r0 u, J+ ?9 u+ u7 E2 M8 Uint lineHeight, 字体高度(或行高)5 c' H: i5 ^0 V: q
GLuint displayListBase, 这个字体对应的base值
8 C6 X9 q4 d& X9 d7 pchar *text, ... 字符串
- o2 i: y" u8 w# J% N$ i5 J
5 e* |& _5 q0 @! a I7 G |