本帖最后由 shane007 于 2023-9-5 16:49 编辑
% l0 k% d- H5 M0 P; l
9 s; c4 h% q- k; u6 Y i这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
; m' u: e7 N/ S5 I/ Q因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
3 ^6 t0 o+ m0 ?https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081: H3 G* n g' u/ Y, ?9 `
第1处9 V3 F( A9 m5 I2 i) F4 \
- void sub_451474(char *a1, ...)" h9 u( u7 }) U! h; J2 k3 j& F
- {2 u j) o6 L2 n; h/ `. g9 G
- GLsizei v1; // eax) q6 U) |# ^6 p& L! w$ n
- char lists; // [esp+4h] [ebp-800h]
$ B: Y8 m! Y& m5 Y2 b! i - va_list va; // [esp+810h] [ebp+Ch]+ a+ o$ w+ D6 m+ e1 ]
- " u% t- S; e4 J& B5 D/ g
- va_start(va, a1);- b7 f5 \0 H4 V& t( L
- if ( a1 )
0 Q7 y2 \* w# x- O2 w4 u - {
9 Q3 N" g4 |9 \2 ~+ Y8 }: E, @ - vsprintf(&lists, a1, va); d# t9 e' C J
- glPushAttrib(0x20000u);
' u! D- z/ f4 @; w; f# p+ O% F# g - glListBase(base);
l, U* t: V9 P% ^* n1 J$ W - v1 = strlen(&lists);7 T- C5 y' Q3 F# r
- glCallLists(v1, 0x1401u, &lists);
9 b" Q& Q3 B2 ]; k2 j - glPopAttrib();
: ?4 w! ?. x. @" b g - }4 F. r* q1 Y! F: j+ d3 E
- }
复制代码 : Z$ | e1 y- R9 P6 e- }3 I
- T2 n! P0 n; g3 d0 U2 A
! S9 \/ c7 K+ V* O; T第2处
* w, H8 q2 v, Y* ]8 R# \7 E- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
- d) _$ A$ M [+ |- _2 Q) @ - {# c' E* \) T6 {) Z7 A! U# u$ G
- int v4; // eax' ?; U& c0 G q
- GLsizei v5; // eax$ {! Y: h" }" y: s$ g
- char lists; // [esp+4h] [ebp-800h]
8 C# g) f1 h1 }' N! G0 p4 s - va_list va; // [esp+81Ch] [ebp+18h]
1 ?- C5 S2 c! Q% k( l. ? - % ^. a1 {8 o& b. P
- va_start(va, a4);
: z1 ]; c, ^- m2 Z3 y/ J0 N - if ( a4 )
- B+ Q1 h1 j& H4 L, e - {
* G! `/ \6 {0 m4 c; ~! j7 | - sub_44F8A0(a3);/ C/ |" o& j0 V1 I
- v4 = sub_40BB44();8 u) `3 x [5 `2 q( z, h" `1 t; |8 \
- glRasterPos2i(x, v4 - a2);
$ \, u( C% @4 T4 a - vsprintf(&lists, a4, va); b/ ?: X' F2 A% H0 k& p
- glPushAttrib(0x20000u);
: L& y% X1 g3 m, O9 p. _% B# l5 A - glListBase(base);
. M+ ]5 r# n A; v - v5 = strlen(&lists);- C* k! Z" `/ D+ w4 R+ W
- glCallLists(v5, 0x1401u, &lists);! L* v( ^8 O7 o- K8 W8 I
- glPopAttrib();
( G( b N/ p( S& g! R6 S6 ?# ` - }. A& a9 u/ h" }1 B! Z
- }
复制代码
3 Q$ T3 N$ v. r* V* z
; P* B. a' v/ q3 x9 i, R8 y: ^, C: K
第3处
: ~& w o9 i% A; h/ C- 2 j* R+ G4 L+ h3 Y
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
9 g: D* C0 c3 h# t* {% t! Z3 d - {$ p4 z @. C% ^& g/ h" X
- GLvoid *v7; // ST08_4
6 T! Y: N+ ]( q* A) [ - GLsizei v8; // eax
" A2 t* e; B- g6 e2 E6 n; h - int v9; // [esp+0h] [ebp-1018h]+ _" U; a% o' n7 [* O; ]: U" ~
- char v10; // [esp+8h] [ebp-1010h]: [. s0 u2 s& x* D
- GLvoid *lists; // [esp+100Ch] [ebp-Ch], J5 p! D5 }/ v4 Y6 H) g
- char v12[5]; // [esp+1013h] [ebp-5h]8 z' Y: y, m, t
- va_list va; // [esp+103Ch] [ebp+24h]
' y/ M7 s( s$ o: J - # W* H$ s( P% ?$ w: p
- va_start(va, a7);5 o0 { `5 \* S5 y2 h, X* f9 ]( E
- v9 = 1;' ~. M( s: G5 V5 c- y6 n6 i: O% \
- if ( a7 )' y; s+ p/ a8 g3 N6 o7 W& J/ M& [
- {
' p3 { l( D# d g* Y: B - vsprintf(&v10, a7, va);9 j% @- ]/ R3 ?3 M X3 E
- glPushAttrib(0x20000u);
8 \) s8 ?4 S2 G" u: V) [ - glListBase(base);
6 w! G/ ~, u5 B6 x$ E( A7 q - lists = &v10;
3 S0 B$ f% }; C$ V- D1 |$ u - do
/ e; y x. v1 a8 O# o1 G - {0 k" i" s* `" b' k* ~4 G
- *(_DWORD *)&v12[1] = lists;: m0 i7 E* M9 I# k, H1 R
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
' {6 W- Z3 u" c/ [ S/ x: ~ - ++*(_DWORD *)&v12[1];
0 G' b9 R/ o1 q; {- g& G/ E9 | - v12[0] = **(_BYTE **)&v12[1];
2 B. p- e! `/ p! G; V: b8 A& q - **(_BYTE **)&v12[1] = 0;5 a; M! _: ]+ ^( @, j' c' K
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
7 u4 W7 B; x1 U; f f, ]6 U) |4 y - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;% p3 a4 m% B A; Z
- y -= a5;
/ H( L% T7 n, n k0 p7 ?# g - glRasterPos2i(*(_DWORD *)a4 + a1, y);
* k& Y3 ~+ [ r- j. P - v7 = lists;
$ t J- |; J& M" X$ P b) b4 ] - v8 = strlen((const char *)lists);
; }) n! Q' d5 }, `7 n - glCallLists(v8, 0x1401u, v7);
: s7 e Y" z0 {2 O - if ( v9 < a3 )5 K; E3 [ R P$ d
- a4 += 4;
; |7 F9 H, T6 [ - ++v9;
" D1 ]+ @, i* |0 L - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
4 n' H- O% \" O! i5 V" D$ k+ s+ J - }2 }' v# z. K7 {. Y M. s: Z8 c: t
- while ( v12[0] );
/ y) H$ K ~9 R* C; b' v - glPopAttrib();
% s5 l7 z1 F/ Z! _! r0 Q0 o- A' J - }' j$ m( ~5 u9 J, O- O
- }' c3 o+ a& i, l0 l- F5 l0 G
复制代码
~: T6 B, [- D! l# ^6 r调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
; b! b1 S# i% d( o2 S1 Z: A2 F$ Y' |) j: d8 v5 A
- .text:004512B1 52 push edx ; char *4 u5 j$ x K" Q5 b" r" x0 [$ i
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
$ u$ `8 c2 \4 y1 ^# @4 K) n3 c( ] - .text:004512B5 50 push eax ; base
! W i8 S8 o# E2 h7 j( v - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]" R8 x- x% A/ r- a. M% ~: [
- .text:004512B9 51 push ecx ; int
$ w9 D! v1 r& v# [, t u' e - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]8 O3 b! I/ Y8 G3 H8 ]
- .text:004512BD 52 push edx ; int
4 H5 M4 t" \- \/ B, {5 ]; K" y - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
' X$ |- D2 V, c9 z# v" V+ t2 O - .text:004512C1 50 push eax ; int
0 p; ]$ y. @* ]' p - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
# A7 Q% f( @9 g8 j - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
& [6 _. y* f4 q - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]! b+ ^! Y6 E' j' ~6 i
- .text:004512CB 51 push ecx ; y
+ @ G: T4 [; t9 z3 ? - .text:004512CC 8B 55 08 mov edx, [ebp+x]
" e) q @- K2 f' r3 N6 M8 ? - .text:004512CF 52 push edx ; int
0 V# e6 E2 H, Q6 L* D - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 1 J7 M) k* e; s4 O3 \. Y1 W+ K
chatGPT整理过之后,如下; m. k; q0 C' {: ?7 l
9 C' C, q5 j- x* T! v7 Z! h# q* P" k- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)1 h% C: ?4 m) }; r
- {
6 K+ m; r$ \4 a/ c& i6 k - GLvoid *textData; // 存储字符数据的指针
. L& ^- b4 B6 }9 L - GLsizei textLength; // 字符数据的长度. B2 Q. ^% E5 ~ m. f3 R
- int lineIndex; // 行索引* G( `) z0 l+ [9 T( p
- char formattedText[5]; // 存储格式化后的字符数据, q* Y. Q3 I: I/ G6 v
- GLvoid *currentLine; // 当前行的字符数据指针
0 c$ `7 I2 P8 A- k9 T# e) d: E# Z - char buffer[5]; // 字符数据缓冲区* c- h# K: g. Y8 Y! g% q
- va_list args; // 变长参数列表
: i) g9 W* b, h1 n4 Z - 3 _- Q; E& m+ z) j
- va_start(args, text); // 初始化变长参数列表2 h* B5 }2 ]+ w
- lineIndex = 1; // 初始化行索引为13 n0 m. j5 c/ o
- 6 F" d8 l4 L* R. L% ~
- if (text) // 如果文本不为空
1 y3 K( U2 Q2 F# w$ l - {' N6 N3 V3 x) K: q
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中+ f" c0 K# Y0 d9 f p; @
- glPushAttrib(0x20000u); // 推送OpenGL属性状态$ [1 F' A7 l5 V1 `! V4 ?5 R! Z. G
- glListBase(displayListBase); // 设置显示列表的基础值
" z3 \2 j. f9 k - currentLine = formattedText; // 将currentLine指向formattedText的内存位置3 A0 a& z# B; D) w1 D7 ~' v
- . t" I ]. `- u1 T( [
- do
8 [* j4 w6 a% k' [2 w/ E' n - {
. g; w2 C; ^1 e8 n L2 \# W - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素+ Z8 B% I+ N" n7 X
- & \1 Y) E( \5 k& t! Y1 j
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
6 A+ _- y! [- n) t6 ]$ t - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素4 h: a a+ T7 l9 F c1 B& n
- . c2 @& f. Y8 X
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素0 o) q: q: M0 r, P0 }
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符1 c7 w( l, O) ?" `7 W
- 5 p* A. D8 j* A8 |( H
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
- \4 y: Y4 ~, F: {5 v/ q - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
: T! e8 K- T* L L& r* _ - & r( P7 N0 Q2 U$ a* P5 E( q
- yOffset -= lineHeight; // 更新y坐标
- k& y& Y- z) j( g. G! Z" Y - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
/ S/ {* K- k* V5 c9 c1 G/ W% s, h" T - textData = currentLine; // 将textData指向currentLine' W" f6 f& S& K8 }% R2 w
- textLength = strlen((const char *)textData); // 计算字符数据的长度
+ C( v k+ a4 n- y1 s( ` - glCallLists(textLength, 0x1401u, textData); // 调用显示列表
- @0 K+ p1 x, Q( }0 X - # J9 _% j* q$ W
- if (lineIndex < numLines)) O- |8 c1 j/ }6 o7 a
- lineOffset += 4; // 更新lineOffset
) P% A$ [* J8 w0 N9 s - ++lineIndex; // 递增行索引" `' }% S; R- z1 c5 f
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据2 f# d0 i' M" f: I. j1 p. B' x
- }
9 _8 S0 M3 F" ]- P2 M4 _ - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
+ V5 w4 Y! T+ L8 u( k4 i; {8 r- B - glPopAttrib(); // 恢复OpenGL属性状态
$ r0 }8 M3 U. L& X+ Y. F - }. A& Q* o2 v$ S1 h3 t1 K
- }) ^9 Z7 E8 l/ l4 x
复制代码 * u( L9 |+ A. t* o% y" o: `
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
; Z7 a1 j: L4 _7 V$ a' g' y
- e: G9 r |0 zint xOffset, 字幕的x坐标+ G' s8 o7 ~1 w. D
GLint yOffset, 字幕的y坐标
3 B: r. |3 @# R9 tint numLines, 字幕的行数(较长的字幕为2,一般为1)
, \! D \, \5 _2 q8 m1 H& Wint lineOffset, 这个需要再研究: X% W4 M( p! v+ `/ |
int lineHeight, 字体高度(或行高)/ a1 C( Y3 v. j, H
GLuint displayListBase, 这个字体对应的base值5 |5 o( A* \: B4 {6 K" w
char *text, ... 字符串
, Y% S- y; C- e+ N0 ~) G: w3 [/ i6 B8 Y( Y
|