本帖最后由 shane007 于 2023-9-5 16:49 编辑 ! y: t# B* Y S+ k, {
- b! n; A& ~" P/ [7 Z
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎8 I, T, z) q, K& h. u" O! V
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。' \8 z& e* I* D( b3 l% X
https://www.chinaavg.com/forum.php?mod=viewthread&tid=1540811 h, k+ c- g8 b2 _$ ?
第1处& P, K0 G& C+ r
- void sub_451474(char *a1, ...)
, L4 w0 Q1 {; g+ W) }+ A' T - {5 Z4 Q- u: p, f% l7 ~9 X. \4 I1 B
- GLsizei v1; // eax
# u- b. V% y+ P, E% [, L+ ` - char lists; // [esp+4h] [ebp-800h]
$ Y. x2 B' C! b+ V( P, z9 c0 e) B I - va_list va; // [esp+810h] [ebp+Ch]% S4 j: ^7 `+ ^
5 Y/ w# n7 r: z9 J/ @- va_start(va, a1);
' N3 l! G3 G9 g- J$ r. P - if ( a1 )6 @( }6 t2 h3 {- Y0 }
- {& b, h8 d- {& t( q7 X
- vsprintf(&lists, a1, va);
* k9 C* Y& C# H - glPushAttrib(0x20000u);
- s, C6 X2 Z& p, c - glListBase(base);
: F F9 Q6 J/ Y/ F* ?8 [ E - v1 = strlen(&lists);
1 W8 y P1 `7 M! ?. Q - glCallLists(v1, 0x1401u, &lists);
; }5 ^' h7 A0 Y6 U+ o- N* } - glPopAttrib();
! Q5 F, z5 S0 t% B0 ` W' z0 j - }
1 E6 U: e) G. o/ Q! f - }
复制代码 # E( J' u. N' v. N
) @; d4 @2 j @# |( J0 `/ O: O0 J! e7 ~2 Z$ p7 C1 D: e
第2处2 s9 [, M6 P" l! O/ G
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
6 d! C! F+ d8 E: { - {
2 }' R6 ~6 } {' ^8 g6 z) D1 F5 D - int v4; // eax( O. G8 Y( J. k( t- w1 t, G
- GLsizei v5; // eax
4 q8 {5 C& U5 R( S8 F6 A: y - char lists; // [esp+4h] [ebp-800h]
# O& P( P( ^! W/ ~ - va_list va; // [esp+81Ch] [ebp+18h]
& E: P, ?, S+ ?6 A
' ~1 h# H# O/ w# C0 I# b- va_start(va, a4);
$ ]9 @2 D" C2 F% p4 S - if ( a4 )( R! j" D/ b) g6 Y/ R2 p( z- H
- {
/ Y" P8 G7 l, X! M5 R/ d* w, b - sub_44F8A0(a3);
/ `4 v+ o, ]9 Z! l2 F2 h - v4 = sub_40BB44();
8 L# z' G4 l5 U9 e2 c8 O& z7 k - glRasterPos2i(x, v4 - a2);
1 M' v# e2 U6 g, B7 b - vsprintf(&lists, a4, va);
/ o8 P0 ?1 j; U8 a. ] - glPushAttrib(0x20000u);/ }0 S) N) Y" Z9 x. q
- glListBase(base);3 o+ z! x0 F5 ^0 X
- v5 = strlen(&lists);, V( r2 [/ ?# q% W. g0 r
- glCallLists(v5, 0x1401u, &lists);6 E& n W) t8 ~& y, u
- glPopAttrib();
/ N' W( `* [# \ - }7 M$ H0 q+ E; v4 i* L" W7 t3 q
- }
复制代码 ; k2 I' E: J( p, f
* C |1 ~4 U8 q9 A
7 ~9 P6 h; W9 N! q: y0 l第3处# e4 S2 z& p. F4 Y) p* H
( o) \" x- i3 r, O) _$ B" L; c g- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
& Q3 Z q$ G! k3 J. S) _6 @! ^3 N - {
: k+ i3 Q, b# ?' j( t1 e+ T - GLvoid *v7; // ST08_4! E* C( {. @0 S3 a; l+ `' v
- GLsizei v8; // eax! N7 U+ f; a# \
- int v9; // [esp+0h] [ebp-1018h]
# Z) j7 L ?7 x; ]8 c4 r - char v10; // [esp+8h] [ebp-1010h]
( f4 F2 n" d; ]* t1 S& C - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
, y; R5 e3 Q9 D) l- ] - char v12[5]; // [esp+1013h] [ebp-5h]# C5 R; ^) k6 j, C0 s
- va_list va; // [esp+103Ch] [ebp+24h]( _$ }: t1 s/ |
( N' m- P3 U) y- va_start(va, a7);. Z- D- c# G6 g" m# t
- v9 = 1;
, F* |! ^3 {; B8 u' T - if ( a7 )( }" h' d4 |3 M2 v4 u0 }
- {
$ q' Y$ m! p) e - vsprintf(&v10, a7, va);
; L& |9 W% \# i8 m) ^& v - glPushAttrib(0x20000u);3 g; h% j7 l) _8 u$ [7 h3 `* `
- glListBase(base); y1 V7 _3 d1 y# [& ] m- E
- lists = &v10;. }9 b$ t* t; L2 r# F+ b4 x
- do
- q. Z" k9 K/ U7 H1 ~: } - {
; z4 _' K6 K9 R7 k9 Q1 k - *(_DWORD *)&v12[1] = lists;
3 a" i$ W, P+ U0 h - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
0 j4 d0 M- _$ d( c& f - ++*(_DWORD *)&v12[1];; l% P* q5 W4 I- R+ L1 H* ^! n
- v12[0] = **(_BYTE **)&v12[1];+ j: D5 i" n4 [" A% A6 {, k @1 I
- **(_BYTE **)&v12[1] = 0;
2 O& ]0 |, h; N [( g( q Y - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
1 K8 s( y9 y8 r - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;7 ]+ h8 s: e4 R6 f( N
- y -= a5;
6 a8 D5 M/ i q - glRasterPos2i(*(_DWORD *)a4 + a1, y);
3 o1 ?4 B5 s5 P" n' W9 J1 F - v7 = lists;
) g; Z; @* `! {/ F - v8 = strlen((const char *)lists);
7 ~& n6 _: x. w; Z - glCallLists(v8, 0x1401u, v7);! n. g! n3 p0 b+ n0 |
- if ( v9 < a3 )
! F+ i5 C9 f% g" b! J - a4 += 4;6 \& d3 L, b& _. n6 r1 U
- ++v9;; q0 O, V- o: i, u; r E" Q! d
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
: T- U/ U7 H: a" O2 }% ]- D" r - }( S) @* [# O) }& x9 g6 J$ n
- while ( v12[0] );
2 Z8 t: w( e7 L% I7 f4 V( e/ H - glPopAttrib();9 h" ?& Y5 y6 r: a2 g0 H4 O# ]+ I
- }; O# s) c. m2 k+ D' A9 @" O6 \
- }9 `/ M: Z# d( D$ [
复制代码 ; R4 e9 n, c9 z1 ^0 J A
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
$ ^7 @! _# F. H& c* F, t4 ]# c
$ M- @7 G4 Z) B/ U- Y; v- .text:004512B1 52 push edx ; char *# e, U3 ?& ~7 x5 A: o+ ?, v/ e6 E
- .text:004512B2 8B 45 30 mov eax, [ebp+base] q. s3 j+ b S* n
- .text:004512B5 50 push eax ; base, Q- g$ G+ ?/ t! d; _' ?
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
* C0 Q5 |9 |( y$ h$ r, ?( s - .text:004512B9 51 push ecx ; int
n- Y( c+ v* T( a- W5 n - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
5 ~6 g7 H' U+ ~ - .text:004512BD 52 push edx ; int5 O ~1 m$ h( I' C4 w3 U
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]$ `' x) {7 `2 W$ u
- .text:004512C1 50 push eax ; int
' U; H7 ]% |3 k. } - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
3 F4 y, `3 {/ f$ _1 Q+ V# W - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]- q: P& K5 A6 E% c% K
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]$ M4 P+ @0 K" W! @# h) h
- .text:004512CB 51 push ecx ; y2 c2 T, k$ X: y
- .text:004512CC 8B 55 08 mov edx, [ebp+x]
4 p% P& m& a, Q) I% D) y" j+ l - .text:004512CF 52 push edx ; int
9 g6 ` w, ]" g - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 7 ~# e0 j2 K ~" e* x2 A7 K
chatGPT整理过之后,如下( E, ]; J0 B7 d( d, t: k
0 B# r! K" F1 N- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
0 [+ y8 M0 `2 W - {
4 Z& K, A- M i% {- I: T - GLvoid *textData; // 存储字符数据的指针5 c B1 v. L' t3 l$ N6 ~* X* @
- GLsizei textLength; // 字符数据的长度$ I6 w) D" {6 |% h( L" a6 E% W
- int lineIndex; // 行索引
. |" C4 @! ^5 u. }2 y. R - char formattedText[5]; // 存储格式化后的字符数据
! t3 Q, G7 a+ J! `9 n9 a5 w - GLvoid *currentLine; // 当前行的字符数据指针
+ ?8 f' {7 s) q2 K: }# Q& Y ~7 G - char buffer[5]; // 字符数据缓冲区
1 h7 Q5 V3 ^/ [3 K' O - va_list args; // 变长参数列表' v6 i$ g P* Y4 ]2 O1 t* F+ e
& w5 |0 s6 [1 Q S }6 n- va_start(args, text); // 初始化变长参数列表6 {0 J1 ?& S: B l
- lineIndex = 1; // 初始化行索引为11 u- ~" Z9 w) F1 U9 X) c
, B- s. s% J. z% n4 z3 e9 p6 ~- if (text) // 如果文本不为空
/ Y# g- ?' V o3 y( N. k% d - {8 |, O- B: n# U1 U& _2 z
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中$ _" u( R4 `9 w7 n- _
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
; P& Y: m0 _$ |* N: K - glListBase(displayListBase); // 设置显示列表的基础值* }2 [, T: o' r# A" X- s. T
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置! ^; O% J; Y; f5 D% v0 ^6 T. Z; I. T
- % p1 ~* n: ?. C, h+ \; r, T
- do
! Y: I- n2 C) e, j0 W' D: p - {1 @6 R! _. E- x7 O
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
8 U% }' F8 i4 c* p4 j* |. ^ - * ^% @' V+ T1 H( x \/ b
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束/ \. Y2 p$ @: f
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素2 C$ i) O+ ?/ v! r
- " n! t0 B# [3 ?/ X6 W& ^
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素0 G% Z$ k& f' T+ K
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符5 U$ t, R2 W, T' q- v
- ; F. h+ M2 T) t- L
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
: R4 V- n$ B+ y3 G1 f( \3 ? - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
/ ?* u0 l- q! |5 B- c" n( _
' M+ J' [* K' f& Y" Q8 [% f- yOffset -= lineHeight; // 更新y坐标
3 Q, D# I+ D4 N1 t - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
& s! u5 u5 n6 B - textData = currentLine; // 将textData指向currentLine
. M, k ?4 n$ J5 \: F) c - textLength = strlen((const char *)textData); // 计算字符数据的长度" S. i& [1 l/ `) k, \ M4 l, I
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
* P! F- ^7 D( l" N0 x& V1 ^/ ?7 U - - `8 k( |% u; L4 l
- if (lineIndex < numLines)8 b2 Z- D4 ?7 _% S2 G, T9 g
- lineOffset += 4; // 更新lineOffset
+ Z5 W& f& a" U- _ - ++lineIndex; // 递增行索引, l& c e- L# ]
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据0 R6 S) `8 A4 \1 f# F1 ~
- }
* t6 E p! W8 s( S0 `( n! {$ M! j - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环2 z% V& W) d1 u2 f$ o1 H( E
- glPopAttrib(); // 恢复OpenGL属性状态
1 a$ r) P) P S - }' N% O) p) ]/ A+ }
- }
. q V, x& Y6 Y0 W) ?2 w
复制代码 + A5 n4 m. o% a% E @' r! z7 P% Q1 M
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前& a ^ c# x6 s& E4 p7 w/ D: S U3 [# _- s
0 V. ~0 b, h F( v% |1 {2 U( w2 T2 h* Qint xOffset, 字幕的x坐标3 x" G4 j/ h* w
GLint yOffset, 字幕的y坐标
% s( m* W2 R& j! wint numLines, 字幕的行数(较长的字幕为2,一般为1)
* r* n& z. D* _# o5 I9 aint lineOffset, 这个需要再研究
% V8 L% N, F. C r8 mint lineHeight, 字体高度(或行高)1 v4 b$ w+ L' [, d1 @# n# }
GLuint displayListBase, 这个字体对应的base值* z3 ]4 r7 t0 w# l
char *text, ... 字符串
) s3 o6 u* m# `' O. k, e- A+ y: x- j. q2 U3 N( v) l( i
|