本帖最后由 shane007 于 2023-9-5 16:49 编辑
|2 l8 U1 k3 k, P( k8 }. V
6 U3 y8 Z* J7 Y; R这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎8 ?0 X- M2 x* S3 X# C) O0 w
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。9 x4 R* S+ d k' X
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
4 d) X' J) N7 ~$ B1 s第1处( H5 }- a8 Y1 v$ N& l$ ^. A6 i
- void sub_451474(char *a1, ...). Q7 i5 w; \& Z) x6 l* t
- {# i. ?. I6 ^8 r. V6 s. C9 O
- GLsizei v1; // eax
6 f& X+ [5 Y2 l" f0 [! E5 R6 O& { - char lists; // [esp+4h] [ebp-800h], E) F% I- Q- I% a; O. M* w
- va_list va; // [esp+810h] [ebp+Ch]
; S- o E: K& ^
% B$ u' K& S, d& ]" b& f( i# m0 w7 L- va_start(va, a1);; ~) F) f0 m/ ]7 I3 p
- if ( a1 )7 @8 L9 \' ]$ E* n
- {# J2 c# O2 M3 z- \' l- v
- vsprintf(&lists, a1, va);$ I3 Q* w! W$ P* h" e9 r' w$ W
- glPushAttrib(0x20000u);1 \- O0 W5 C( i# ^% s6 v
- glListBase(base);$ Y5 K" z$ X( N: T. d0 A1 P
- v1 = strlen(&lists);
$ @. ^" j; M# |/ g% {: H3 Z$ ] - glCallLists(v1, 0x1401u, &lists);
6 Q) y. q' p5 z$ H6 I# ~ - glPopAttrib();
) H0 z. C2 V- I. k - }
+ d, }4 z7 R: Z. ] - }
复制代码
0 _ {# l# F& `* I- W( i4 i u( x
! T3 B& _* H; y2 r4 T2 ^% o3 I
第2处
" {+ o! {1 y, J7 ]2 } n0 d# d) L- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)! z# W8 V& c, U, Z
- {1 a1 H/ ?6 w7 M0 g, _
- int v4; // eax
. u" C. V: O5 X* g9 ?" f - GLsizei v5; // eax1 ^/ G4 w; I/ R, `% f
- char lists; // [esp+4h] [ebp-800h]* k5 \7 z/ e' N4 t. \
- va_list va; // [esp+81Ch] [ebp+18h]# l2 K5 Q7 ~- I3 _% Y
- 4 A* E' h5 c% ~' `8 Q
- va_start(va, a4);- y7 L; @+ J; @6 j5 E* J* N7 z
- if ( a4 )) _/ Z+ R* N3 u! ^# H" M
- {* Q5 q8 v) `9 s# E
- sub_44F8A0(a3);
5 N2 B! F+ W" N* R7 ` - v4 = sub_40BB44();
8 `! `' q/ i+ P, r+ d: y - glRasterPos2i(x, v4 - a2);
|* P0 j# e: q& c# C0 F - vsprintf(&lists, a4, va);
+ F6 M5 q% r" ]) L8 k: P* W - glPushAttrib(0x20000u);( X3 }+ z- C$ _
- glListBase(base);
8 m8 `* X( T% l; ?. H+ c% B8 p - v5 = strlen(&lists);
. v5 W5 W1 c# k. y0 n- G - glCallLists(v5, 0x1401u, &lists);6 x5 a& {6 T# y7 \
- glPopAttrib();# ^- Q, N% M; }" N) Z: T/ q, Y
- }2 b, D1 f4 l# M! B9 h/ d/ h' o
- }
复制代码 0 _# S' K' z6 C& ?
2 _' E. p# J' {% }- h
. v5 s$ q! z) y; ]1 ~4 B0 j: Q
第3处# D/ P) q1 d. V' `# c! v2 P
- $ B$ E: R, {, h8 j) e1 k
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)% t- r$ G7 f5 G# m2 W
- {
: R% j+ v; a& v. K - GLvoid *v7; // ST08_4. t' V* c# K) q! z* L. M5 t4 T% {
- GLsizei v8; // eax
* q% H- E3 J4 g& v; m! x - int v9; // [esp+0h] [ebp-1018h]& B* N0 i; l9 f
- char v10; // [esp+8h] [ebp-1010h]' o9 x- w, y. H% L
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]
, M* C& u6 O6 S5 @0 |, v" E - char v12[5]; // [esp+1013h] [ebp-5h]
" x0 O9 H$ [8 {* w; e' D - va_list va; // [esp+103Ch] [ebp+24h]. w5 K. }3 ~, x' N4 D& X! T
- . {, _/ D+ ~4 U% O9 p
- va_start(va, a7);9 Y/ C0 S* ?- j# O4 u* H- W g
- v9 = 1;# q' y4 X' V1 k7 W9 Z# \0 Q4 G& p
- if ( a7 )
1 l, i. X$ R) r - {5 |, ^6 \( Q2 |- s
- vsprintf(&v10, a7, va);! D) A& v+ c. q0 F
- glPushAttrib(0x20000u);2 |2 `. j' P9 t0 w0 C' D- L9 c$ z
- glListBase(base);
6 B3 ?* _& g) Y* [* R - lists = &v10;5 \$ R/ e$ p3 x, S, D0 P1 u) Y
- do! b# k3 p6 K; @( P! T) C
- {
- _) _1 V: r% m; @9 k4 n - *(_DWORD *)&v12[1] = lists;
" V6 `2 F* w' S6 n# }3 W - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )* i- i/ _/ [: `
- ++*(_DWORD *)&v12[1];
?: t* D! L4 p+ ^6 `" F8 \ - v12[0] = **(_BYTE **)&v12[1];+ U5 ~+ d/ R0 S2 {4 q! V8 L
- **(_BYTE **)&v12[1] = 0;5 v) a+ H" j# q
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )& |7 G( u4 U5 Y) f
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;; l- {; C3 H) b- d v8 s
- y -= a5;
( ^* ^ b: J) N+ E! F# w' o6 U) W - glRasterPos2i(*(_DWORD *)a4 + a1, y);* w5 \$ h$ v4 P( i' f
- v7 = lists;# |$ z' A6 L$ \) n1 [8 ]/ N* ?: N7 ^
- v8 = strlen((const char *)lists);1 J8 y' B; n; p" G
- glCallLists(v8, 0x1401u, v7);4 m( ?- T8 W4 _7 ~9 ]+ b( K
- if ( v9 < a3 )
! {$ a' J! }0 D* { - a4 += 4;" g1 w2 y6 ]4 ^+ ]
- ++v9;
7 b' v s1 }, R - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
* G( E- [! W1 \: r$ i, l, w - }
8 _/ J# J8 Y7 ~; Q/ A - while ( v12[0] );
+ H" G; @. h# \9 _+ C5 Q' ~( H - glPopAttrib(); m+ |/ H- [7 j0 X
- }
! v, s6 z8 F* Y a3 V - }
& [* g. O3 o/ d. [
复制代码 ( e W4 @) m6 Q3 y) T8 y ^
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_4518105 n. V% _" d9 w' J& U. d% p
' T. ~, k" Z: ?2 x* Z
- .text:004512B1 52 push edx ; char *& S7 f2 N0 I1 \9 Y/ M6 {
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
: ?7 x* E; y; c9 M5 e - .text:004512B5 50 push eax ; base
5 i' z) T+ T0 L" q/ m - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
5 D! a% Z1 K. J% f4 Y - .text:004512B9 51 push ecx ; int2 K9 b Z; n& S: I
- .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
" L$ G! d, a$ @, x - .text:004512BD 52 push edx ; int
+ R3 D2 N7 q& G& Y( L d- | - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
, E, k3 b5 [ q% d8 Z6 }; k, c/ p; { - .text:004512C1 50 push eax ; int
7 ^. R$ s! h" t7 y! u5 I# A - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]: m5 Z" t! P" ?. G1 K; Z; P
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]9 A7 P; P; u6 L1 ~7 E7 y
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
+ J& R4 V$ q3 f+ b8 K - .text:004512CB 51 push ecx ; y! A: s# Y/ k z% E0 x) X- D
- .text:004512CC 8B 55 08 mov edx, [ebp+x]% w' C. D D$ i3 K2 M$ }1 x' ^5 r6 y
- .text:004512CF 52 push edx ; int/ h$ e! V& K( U$ B: [/ r( u
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 / P: l7 P* E& A
chatGPT整理过之后,如下
( J% a: C' l. B- o: k2 V
" R: G* J6 k/ }: o1 }8 w% U0 U, M& \- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
. ~/ i5 M9 k# u: c - {
1 e3 a, r J$ `* I/ O - GLvoid *textData; // 存储字符数据的指针) G8 Z! s6 f; |/ Q4 ?7 Z
- GLsizei textLength; // 字符数据的长度, ~+ e8 d& g2 N
- int lineIndex; // 行索引
% }2 @# Z; h% x( `. A6 R - char formattedText[5]; // 存储格式化后的字符数据* q8 L% i6 M1 `0 E; A
- GLvoid *currentLine; // 当前行的字符数据指针; j2 |) L* j6 Z8 M& W
- char buffer[5]; // 字符数据缓冲区+ s, V- `3 M, Q9 N
- va_list args; // 变长参数列表
- K5 @3 x" w& R+ B2 B* _) [
6 g- t1 }; ]4 f0 o5 b- va_start(args, text); // 初始化变长参数列表
e3 R' |! y9 Y7 Z - lineIndex = 1; // 初始化行索引为1
0 v3 q5 x g) t - i$ X+ [) Y. v
- if (text) // 如果文本不为空
+ M- k ^7 I4 r. m; M# F+ n* Q - {
8 U6 h( U1 }6 _- \) s1 Q( G - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中* f8 ~+ R7 Y7 ~
- glPushAttrib(0x20000u); // 推送OpenGL属性状态- ~! A% Q! G' ?) R. o3 s- E
- glListBase(displayListBase); // 设置显示列表的基础值8 H4 y7 E( S& X" L$ e* T: P' f: D, {
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置- f, F" d% I B
- ( i O4 U3 u7 e$ C" H, H# [
- do
. F3 L$ g: r; v7 Y: ~ - {
4 O! y* @( B. a, U9 ?' O7 [1 s5 b - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素$ Z7 `1 O0 a, w5 \4 k9 m6 H) ]
- 8 Z' K# I( v7 h( i
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
* I; P& K% M/ n% {( |3 V - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
" a; r' r# b- R6 y/ d, \ k2 } - 2 N: t4 i; F; R
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
8 |# t0 D/ _9 f4 u; `1 y! |; m - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符6 @4 K! C. F' ^, r8 g( {. v( a% Z1 G
- 2 x. ?, D* X4 D
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)* I9 A- x- a" z% F
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符" U* W$ U8 l- b3 G
: _2 B2 N: ~- P1 W9 I- yOffset -= lineHeight; // 更新y坐标, P8 B @' S# ?' M& E" v
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
: ~( z1 t$ ^, a7 M% ? - textData = currentLine; // 将textData指向currentLine) c; N- K( g( p# t
- textLength = strlen((const char *)textData); // 计算字符数据的长度
6 T }( F* P* o! V4 Q - glCallLists(textLength, 0x1401u, textData); // 调用显示列表3 r. }) G7 s' i: h, g
' U; j, \; y: d; o! n, B- if (lineIndex < numLines)
3 T) Y' Z9 N& U% g - lineOffset += 4; // 更新lineOffset& B z8 T7 o# f7 q
- ++lineIndex; // 递增行索引) m( ]1 W) f* l+ i# e4 }
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据! ~) X; |2 ]" t) }4 N% v
- }
/ p( H3 `! g8 T4 h2 L! S: ~; T; \ - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环7 q* i, M5 D' m' }4 _
- glPopAttrib(); // 恢复OpenGL属性状态( e6 }- V9 O5 ^( v% ?
- }
7 \4 M- I" H" a - }! ^# U9 q% E1 D7 l
复制代码
+ f9 F( v. z) G6 J' m% [# L含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前3 H% H3 L' ?5 q
9 y( r- |4 S! r& L _5 }0 Dint xOffset, 字幕的x坐标
" w$ \( d2 y& L- q8 i6 lGLint yOffset, 字幕的y坐标8 o% g2 L- H- q6 y( ^
int numLines, 字幕的行数(较长的字幕为2,一般为1)
$ ]6 X {; o' J/ x" zint lineOffset, 这个需要再研究9 c5 I7 w; r! X
int lineHeight, 字体高度(或行高)
5 T# s, o7 P9 O: N( h5 v$ tGLuint displayListBase, 这个字体对应的base值( g: q6 O7 K9 U1 |7 X: j* q; Y) x
char *text, ... 字符串) ^! |) l# \- J
6 C8 k* l7 G: d$ q
|