本帖最后由 shane007 于 2023-9-5 16:49 编辑
+ T# J' [7 B( k5 F# b4 u: f' i6 T; c7 S" h M0 J- G1 x, v
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
+ j# _* l8 U; K, Q0 M5 y' \0 b, `( ?因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
- T# V6 O9 S- e6 b1 T( d. Z2 Dhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
' Q1 z+ J; j5 j) v4 G4 s. P第1处% ^1 N) I( B' r. D
- void sub_451474(char *a1, ...)% J8 \8 h( Q& V
- {" R' y0 W. q- f* z, u2 _" \
- GLsizei v1; // eax
' X" N2 t' M$ v: Z - char lists; // [esp+4h] [ebp-800h]8 C8 m+ a; X0 o2 X* j" n- J$ t
- va_list va; // [esp+810h] [ebp+Ch]
& @4 N3 @1 X: [! v- ~. e; e+ c0 ^
) A4 F+ d5 h+ b' s- va_start(va, a1);, O, ]0 E* k7 U0 |6 H/ M
- if ( a1 )
( a. Y- |/ I5 }3 m/ Y6 _7 N - {
$ E" I- E2 \4 K4 ~7 q - vsprintf(&lists, a1, va);
( V% w+ N5 H# D- a$ | |3 e - glPushAttrib(0x20000u);$ |7 m, r9 \' [1 d5 n. g# R
- glListBase(base);
1 X8 @0 E$ f7 m/ c9 z& \ - v1 = strlen(&lists);$ s) n$ z; Q" p4 ~. e- f
- glCallLists(v1, 0x1401u, &lists);
/ v7 j9 b' X9 @ S+ y& { - glPopAttrib();
( ?. B n, p* k - }4 G/ V6 p! F; R
- }
复制代码
) `0 u! C: J Q1 L- N) X5 s1 F; j$ V0 p0 I- J, v
) ]' w) p% |4 P: e6 e) o
第2处
, c2 D0 P. V& r+ L- J& ~% Q- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
: N) J6 H+ j+ Y% [" Q0 o7 z) {* i+ ` - {& Q7 F7 J) S" i/ {
- int v4; // eax
. W& P8 F( C3 w& J - GLsizei v5; // eax
, K; r0 k) g- ]& ~2 Z% N- G1 {* A3 v+ M# Q - char lists; // [esp+4h] [ebp-800h]: n6 ]: _/ k- {- {8 F; Q0 I
- va_list va; // [esp+81Ch] [ebp+18h]
" [1 \3 ?. c8 B+ ?5 A: ^7 \ - ) q, g2 r4 F. N6 f7 l
- va_start(va, a4);$ l& U- A% r) Z9 c/ a0 b
- if ( a4 )
* w1 _8 x/ h6 c' w& Z* q- Y - {9 Y# r* d" t0 q( L$ O
- sub_44F8A0(a3);
! j) J" v: J6 q8 j - v4 = sub_40BB44();
% E) T( v5 j7 v( c1 @+ w - glRasterPos2i(x, v4 - a2);
4 c( w/ p* H8 } - vsprintf(&lists, a4, va);
5 O! M+ \0 q9 W* d - glPushAttrib(0x20000u);9 C: L) ?0 m: ]) P( C: y/ j7 T
- glListBase(base);: F. }( y. P0 `$ B8 `) g
- v5 = strlen(&lists);) I% Z( Z: d* ~" j& ?3 z
- glCallLists(v5, 0x1401u, &lists);
) U; Z; ]5 v; S0 s8 O& t2 E - glPopAttrib();: U8 C. |" i( P" H, s" N
- }2 Z/ |/ S; o* |
- }
复制代码
" }7 l# O1 r8 U2 \ N3 N: q: Y( p& A+ ~ p
/ k4 b- W3 g" ^1 ?; t( Y! f) n第3处
5 m/ j: O% Z- D! T/ e" y8 a
4 @' I# q, t' g6 ?5 d# L' h- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...) @5 y0 [5 w: n3 ~ j
- {, g' Y) Z7 Q Q3 ~
- GLvoid *v7; // ST08_4
$ [2 ]; x- m0 ?/ ?; G- _: k - GLsizei v8; // eax
6 }2 A- `& G) T - int v9; // [esp+0h] [ebp-1018h]5 i- ` q8 G/ |4 L) M X
- char v10; // [esp+8h] [ebp-1010h]
3 i( K2 `% J/ Z% y- } - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
( H; q+ k, C2 h1 i+ W; X7 F4 M - char v12[5]; // [esp+1013h] [ebp-5h]/ [8 ~7 U( }: I+ S$ O
- va_list va; // [esp+103Ch] [ebp+24h]* c7 v' s& t* w+ F* p* s
4 Q4 y" Q* B2 w. p6 P& ^- M8 ]2 N2 Y- va_start(va, a7);
6 r* \; h5 R" t6 m - v9 = 1;3 y3 N8 j8 v, `* p
- if ( a7 )3 D) l k% A e: s4 r
- {$ Y3 \. p8 {% @4 W- a7 |
- vsprintf(&v10, a7, va);
+ ?8 L m. N. a1 C0 } - glPushAttrib(0x20000u);. E: ]/ w# M! a# \
- glListBase(base);
* t! S" ]& u) `* Y* w! U - lists = &v10;
( e4 D! V* Z% o8 i% | - do
4 R/ ~1 q& y( k2 @7 | - {/ o$ v. u$ g$ }
- *(_DWORD *)&v12[1] = lists;/ j2 `$ h& T- B
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )" z2 M2 c! ~0 h g9 _- {3 R" c B
- ++*(_DWORD *)&v12[1];
) u: w3 S9 z6 \2 | - v12[0] = **(_BYTE **)&v12[1];8 H' ]2 ]8 K- }" m/ ]3 A
- **(_BYTE **)&v12[1] = 0;) W8 M7 W% T: w
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
9 q7 B& O: j1 j$ M; m/ W - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
( e$ t" s7 Y& `# g - y -= a5;. U3 e0 ]- W' n
- glRasterPos2i(*(_DWORD *)a4 + a1, y);" b4 \/ b" `" \9 U# c- W
- v7 = lists;
+ ]" I: K! v7 f. C - v8 = strlen((const char *)lists);5 }$ S7 ]0 _$ q
- glCallLists(v8, 0x1401u, v7); h& g1 M9 |% j' B
- if ( v9 < a3 )5 A9 x2 l$ A& l* y& H# J" ?( S
- a4 += 4;
9 |4 W D `' Q+ ~& C - ++v9;5 t7 I# \- l4 c$ G
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);% {) m0 U% d( k( _0 B5 t( ?
- }
9 @: _, q& S/ p1 A9 N4 S8 v1 l' [3 u - while ( v12[0] );
D0 t. Q# X" D$ t4 b" f - glPopAttrib();, v; q; Y8 U1 I' C# p7 `, a
- }
2 ~& ^3 |# D' _. {, V9 K, E. S) e - }
# h' n2 r% t" D- \( {
复制代码 ' m) s( N# r% G: @1 l( c
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
4 u* p) D( p6 I% x: r* A3 M: m! [: E. O& ~) F- B8 H9 {& V
- .text:004512B1 52 push edx ; char *0 c7 ~ ~( U- ]7 J( o% Z) `& z
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
+ n6 `. z8 Z1 v# w - .text:004512B5 50 push eax ; base
5 @+ S) S) _5 ~& x; a& f( G$ J+ g# q - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
, ]( Z* A5 H# W; D - .text:004512B9 51 push ecx ; int
' l" ?% A. C0 K" P) K+ v l. O J - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]: o8 [& g* D, o
- .text:004512BD 52 push edx ; int6 R$ R9 s r% `7 C' N( S
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
6 |3 f8 v/ A5 u/ m/ U. B/ d - .text:004512C1 50 push eax ; int
; w, N7 x: G2 W3 c2 A - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
# h* T u& o# v7 w7 \; a3 Y - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]0 S0 @! s2 h) r
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
$ `+ T6 r) Q9 F$ L O! a8 U5 g. R - .text:004512CB 51 push ecx ; y+ T/ ]9 M3 v3 @. d, m- d
- .text:004512CC 8B 55 08 mov edx, [ebp+x]
- v: |% S/ `3 C5 s: ~% Y" b - .text:004512CF 52 push edx ; int
! K7 e1 e# c' ^. r4 q- R - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 3 e, V" q# u& ` y; Z
chatGPT整理过之后,如下
: W/ E0 C* n7 f4 K* `$ Z- W1 q6 h9 t6 @8 H" r4 t
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
* J. S" u' n, q. p - {
5 d, t% _) ^6 L1 w$ F7 P - GLvoid *textData; // 存储字符数据的指针8 O+ v2 D; q# {
- GLsizei textLength; // 字符数据的长度/ @& L; L, o8 P6 [
- int lineIndex; // 行索引
1 @3 D: B1 v( ?$ r: S) u - char formattedText[5]; // 存储格式化后的字符数据) t: ?9 Q$ S0 }! p
- GLvoid *currentLine; // 当前行的字符数据指针5 C0 O* }2 |* v1 D& S0 H3 r
- char buffer[5]; // 字符数据缓冲区
1 ` V7 P/ E. a - va_list args; // 变长参数列表
* G0 l1 \' R ~* ~5 w Z( A1 w; w7 ^ - , f' A0 R) n# m* J% \1 \( G4 e( e
- va_start(args, text); // 初始化变长参数列表
# b2 [6 {' Z* o" E! U0 R4 R - lineIndex = 1; // 初始化行索引为1% N2 i8 D7 S" |) E- u2 E) L- c8 x
+ q" U. o4 |, W* |2 v J- if (text) // 如果文本不为空! R7 q, W4 b0 q6 [ W
- {
+ R0 v: R/ ~5 E - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中2 V& o; O4 q8 K: ~- t( P+ I. P
- glPushAttrib(0x20000u); // 推送OpenGL属性状态9 @6 ]0 W( [! m- U) D# n7 f m
- glListBase(displayListBase); // 设置显示列表的基础值, S0 K; ?$ F3 O* Z
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置5 `! i1 g: f. p. ?* X; y
- - Q7 \2 A4 [9 N! U$ G6 m& D
- do
) A; [) t: @0 J# A4 s$ Q C* h - {7 w7 F2 \7 ]" g; Y
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素 E* v9 V) R( \% C+ v
- ) U+ b: v4 I% d/ E/ k0 t% R
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
5 Z, N1 }9 E) m p( k - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素3 q. S" S( i+ N: f: u2 @
- . ~) j+ _4 Q% e1 I. m2 m. C9 F e
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
- g; \ L! Q8 i( x' n* \* {8 a - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符6 I6 k4 _7 g0 L. A: K( q
- 9 V/ ] N! E. p6 k+ `
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)' t7 K; q" T7 N5 u" U' H2 v
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符# j6 X3 K5 B* ?1 `1 o: z0 V
- ( [/ ~+ B) i# d7 L+ K9 ]0 Z$ d
- yOffset -= lineHeight; // 更新y坐标& B% V8 I ]" I/ V
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置) ^3 `# {% m9 _+ C' X0 D/ ?
- textData = currentLine; // 将textData指向currentLine; W7 x9 m4 V" \( f% r2 s. m) U
- textLength = strlen((const char *)textData); // 计算字符数据的长度
; L, {9 F" K1 v) M; r. v - glCallLists(textLength, 0x1401u, textData); // 调用显示列表, w$ ]3 I9 J& J D
- * q5 n- }) d# M/ H7 G
- if (lineIndex < numLines)) T- Z1 j j# D2 p1 `9 e: n
- lineOffset += 4; // 更新lineOffset: g" S& n$ j; a8 h
- ++lineIndex; // 递增行索引
8 J) {/ g! Z: y - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
9 {: T) }0 j+ o) }! I - }5 _) H5 L/ L9 [+ R O5 p. o4 |
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环; L* u. K9 b6 b$ s' V3 r
- glPopAttrib(); // 恢复OpenGL属性状态
4 I* m. o, X' Y. h8 t2 b - }
. D6 W# |( i/ X" X6 W% t - }
9 L. @; S0 e( u
复制代码
~9 j N# J- U% P, i! j含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前, G5 d2 a7 y) I9 t% M% F
- t" O. {2 B# Aint xOffset, 字幕的x坐标. n# c7 Y9 `' l, @
GLint yOffset, 字幕的y坐标9 j4 w6 N( [! Q/ w% q2 L
int numLines, 字幕的行数(较长的字幕为2,一般为1)
# ^' Y1 |* s$ z& B. Cint lineOffset, 这个需要再研究
% C; _- ~, H: cint lineHeight, 字体高度(或行高)
2 }) p# n. f0 z: ^GLuint displayListBase, 这个字体对应的base值9 }6 N( j# t* @5 _
char *text, ... 字符串" B* G1 u+ m7 @. p3 @
8 H# p% |8 I3 k6 C) B |