本帖最后由 shane007 于 2023-9-5 16:49 编辑
1 [8 x5 a% ?: P
) l& P# u$ i; {9 n! _8 I4 X这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
5 A5 x% Y5 Z, L6 F4 h因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
8 I' H7 n6 b- a Z( Xhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=1540816 V3 ~* M$ I. b
第1处
z2 A; S \. f2 T( i2 u% L! ?- void sub_451474(char *a1, ...)! X# [+ R& } H
- {
' W: C: h$ u0 l* [1 M - GLsizei v1; // eax/ b$ @7 R& r+ {0 m* L$ o2 I
- char lists; // [esp+4h] [ebp-800h]
- A7 J, \/ b( F- H5 P6 w - va_list va; // [esp+810h] [ebp+Ch]& ]% S0 D' `8 H& H% j% I9 C& Y7 M
8 J3 [ t. c; M: }& j8 ]" X' X+ ^- va_start(va, a1);, X/ ?& J/ [# k8 o! Y3 e) y
- if ( a1 )
1 o5 t; u; `' f4 H, Y/ P+ B& F - {
' _& C* [/ @" r) _9 l* W - vsprintf(&lists, a1, va);. j3 l; O4 v, L7 ~+ b
- glPushAttrib(0x20000u);% N2 Q$ L" D( p, @$ o* d+ W
- glListBase(base);
! J; P1 ?& C+ N0 F6 I$ y. O - v1 = strlen(&lists);1 C* K I: f2 c& T- j1 H
- glCallLists(v1, 0x1401u, &lists);
9 `* B' n- E# ] - glPopAttrib();" [9 B9 u3 }; a( R% J# H1 H
- }7 s& D4 E/ q; d/ c
- }
复制代码
# A w1 L T5 m% z( v; d
" Q6 c& f+ K& I6 I# }8 j2 b
& R# w$ n: o( `9 k C! f# j第2处: U9 P% e* B" J7 I* s* B
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)( O: n1 o- a3 `( c" m- }% j5 x
- {6 ^$ w/ V) n3 t) S
- int v4; // eax) U' d' [* g1 r. Q# l
- GLsizei v5; // eax2 T- l' P1 ~7 j3 t. K
- char lists; // [esp+4h] [ebp-800h]
& s8 i7 _7 D$ V5 N - va_list va; // [esp+81Ch] [ebp+18h]0 x& t$ ~0 v- q' s9 o" V
4 e& z! x8 w. Q7 h5 U' p- va_start(va, a4);
: s6 ]9 X6 o1 _8 ~3 H - if ( a4 )
) J7 _3 u# M, _: m: ~% y; |; c: H3 e6 j - {) t2 z3 p$ i# \4 E/ {( g( N
- sub_44F8A0(a3);- n, S- N6 H) V/ N
- v4 = sub_40BB44();
+ \. e% V- J) ^% `+ E G- \' @7 A: | - glRasterPos2i(x, v4 - a2);" X0 d( @& z! B5 E+ y
- vsprintf(&lists, a4, va);9 y0 {: d" k% P2 L6 l) V; n3 I
- glPushAttrib(0x20000u);
$ C0 N8 x- Q% |# b6 C- m - glListBase(base);
4 b! a: g0 a2 W - v5 = strlen(&lists);
* C" n1 e! |+ d. N$ X- ]8 ~ - glCallLists(v5, 0x1401u, &lists);
& s/ R8 O$ e6 }6 f - glPopAttrib();" N) ?' f5 p6 l; `3 j( W
- }6 P/ F8 ?" w& _3 f
- }
复制代码 2 `1 |2 \: z+ U n' g! P8 ?
* _' |3 s7 S: N; Y$ O' Z L
1 e5 m9 m0 F7 q2 a$ o第3处+ E0 W5 S& C6 |6 r: V, m
- : c6 g8 X$ e+ g0 @ I6 G$ [
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)6 _' P8 V' W& E+ X M4 Z* C% M
- {# A( g% c! t% K1 I* S
- GLvoid *v7; // ST08_4 @9 f6 _8 l1 n0 I$ T1 O3 F- n7 |
- GLsizei v8; // eax4 a! C {' t. t" c5 l
- int v9; // [esp+0h] [ebp-1018h]' C3 {& G4 ~1 ~5 _4 k
- char v10; // [esp+8h] [ebp-1010h]/ W3 i7 @& x# x2 z* C% D. J
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]
- T9 U# q2 {( n; h7 Q - char v12[5]; // [esp+1013h] [ebp-5h]
" B; `4 }# e3 D! Q, g9 ~( Z/ j - va_list va; // [esp+103Ch] [ebp+24h]+ F" G6 J! K8 m! U2 |+ U
( g# b* f- [8 k% e- va_start(va, a7);2 o g; `9 |" f0 Q c
- v9 = 1;! E8 H6 o& F$ O' W5 W1 F
- if ( a7 )
& e2 i0 W. U) e% [) N) F7 [ - {
3 P. C% z, Z) t4 d" c# ~- g$ a# a - vsprintf(&v10, a7, va);
6 K% F9 E( P6 ~9 O, [" `6 j, A - glPushAttrib(0x20000u);
2 f9 [$ h! E- {" U# f+ o - glListBase(base);& B3 h% w* U! Q
- lists = &v10;
( v4 U2 q& M. E - do" Q. i/ ]! A1 m
- {9 c: z$ E- \* O# C" O
- *(_DWORD *)&v12[1] = lists;
) w# N3 _9 [4 B& K' e! ` - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
( H, `7 a* u3 o& g4 h - ++*(_DWORD *)&v12[1];' G) q" U( z, @& ~5 U
- v12[0] = **(_BYTE **)&v12[1];' Z6 c; Z7 i4 W
- **(_BYTE **)&v12[1] = 0;
) m* I" K# y. w# J/ D8 A" s( v - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
+ H) W7 `% k+ P" l/ ]2 Y - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;6 g2 [% ]2 A- ^4 B, E
- y -= a5;' v$ i: k/ P% N7 s# k' r. q" Y; X w
- glRasterPos2i(*(_DWORD *)a4 + a1, y);
3 }9 Z. x+ B( Y9 q, l, r - v7 = lists;4 @8 {' M! y# `& v: G
- v8 = strlen((const char *)lists);
& q C: G3 ^5 o. v8 l0 B - glCallLists(v8, 0x1401u, v7);
3 o9 B& s4 d1 o - if ( v9 < a3 )
* r3 s2 y- Y" s3 } - a4 += 4;9 V& j# r) ]% w: T" Z+ j9 c- H
- ++v9;& C5 m6 N5 m% `+ T4 W
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);7 |6 {* I8 F5 l o
- }
3 ?7 b. e/ ?: O - while ( v12[0] );
7 j, r$ Q. s- y, u3 o - glPopAttrib();
( y; a" z* S4 A+ m - }8 ~* Q" O) x R# y/ l8 K6 X
- }6 y. @) r% {* y3 ?: u
复制代码
- y3 S) m' [7 W! ^调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
( y1 Z9 ]% s( O7 X) f8 Q6 t+ M- Q
- .text:004512B1 52 push edx ; char *2 ? t/ x) Y- ]/ ~; O" m: ?
- .text:004512B2 8B 45 30 mov eax, [ebp+base]) w& p" z. }% A6 a; [9 r
- .text:004512B5 50 push eax ; base6 I0 `( R7 w1 C' d& t& C* c) T, g
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]( R% e1 _ o: ~9 N4 A
- .text:004512B9 51 push ecx ; int
+ o# }% H/ q3 `9 [ - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
! l3 _1 \# I6 s - .text:004512BD 52 push edx ; int
. [+ y, j0 H: z) Q( o+ M4 Q o" U) X - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]! Q& k+ f0 J4 x; ~
- .text:004512C1 50 push eax ; int+ A. J7 p: @8 {$ e% r: _
- .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
" @8 ]" E1 B% j* q: Z - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
* P: G8 X; t1 r/ h, D2 m* g - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]9 _; t1 D: v! ?; ~0 J; G( _/ ?
- .text:004512CB 51 push ecx ; y
4 r+ P% F% E/ b - .text:004512CC 8B 55 08 mov edx, [ebp+x]
* s1 f0 K7 ^7 K {, s5 M - .text:004512CF 52 push edx ; int& G. W" p9 ^, p# {$ t' _7 t: K" z
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
! p: C. ^& u: |; a% i$ i7 p$ IchatGPT整理过之后,如下
2 D6 s, E1 o/ g' V6 E- m. E4 [& V: `% N5 x1 s% F9 w
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
* g# f# |) l& B4 S2 P; Z# m- \ - {) N4 l y' X; k) r
- GLvoid *textData; // 存储字符数据的指针
2 x% G7 G' |$ k) Q0 f _ - GLsizei textLength; // 字符数据的长度
+ B# ~5 z% ^( a' Y. W3 U |9 [" }7 K - int lineIndex; // 行索引/ Q( b. X# O' }( V7 s
- char formattedText[5]; // 存储格式化后的字符数据
, Q w8 X! n/ e. ^ - GLvoid *currentLine; // 当前行的字符数据指针
; x( a3 ?0 @; t& R: h0 w7 e% l - char buffer[5]; // 字符数据缓冲区
$ n A& Z, W H; B( j - va_list args; // 变长参数列表( [0 i( L+ L* i# v; r$ n! [. o
- 0 S" c( U, l m8 r; u1 ~! S/ L* U
- va_start(args, text); // 初始化变长参数列表
8 o2 Q) [/ D6 R+ u& W6 {' d3 D - lineIndex = 1; // 初始化行索引为1
7 k b9 k3 d. l4 z) Y - & u$ o m& E$ K, W7 ]5 W5 A) g; M" i
- if (text) // 如果文本不为空
8 ]7 r+ [+ ^, V; { - {/ Q& `7 e# W3 N. u6 h# V
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中; W* v; a8 w. w4 |" a* J1 O8 b
- glPushAttrib(0x20000u); // 推送OpenGL属性状态# S# M+ e O; s4 T" w. g8 e
- glListBase(displayListBase); // 设置显示列表的基础值6 z) t0 e! A6 b2 m O
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置
9 |+ ~# h2 u$ d- K - " w7 G6 g( U' O# i3 k2 H
- do7 Z, P. u, y" m/ ^6 R
- {
' l9 \$ w/ c6 [& [1 {( t3 _ - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素9 m( L$ u M0 `6 N8 {& T
- : W1 y" L6 M* Y1 Z3 U
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束7 O* n A- ?3 ?) s6 A5 S; {5 ~3 n# u
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
0 S% [2 L: |' ?: F - 5 S4 {; w8 a& _$ J0 a8 W
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
6 B0 p) `0 D- f$ _7 r) k# q - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
3 X! t6 I+ a7 n" q0 c - 4 G6 y# g, W; p z" P
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
) {9 Y0 u* \& `- x" t2 T - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
& P6 f! J; S& T7 m1 ~6 K - $ j: S; t6 ?% ]) w5 \
- yOffset -= lineHeight; // 更新y坐标$ f5 I4 p& L5 k* V
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
4 w$ D' s' u& O/ V" a - textData = currentLine; // 将textData指向currentLine& o1 m- M" |3 |
- textLength = strlen((const char *)textData); // 计算字符数据的长度
% A5 C4 d3 Q( E% i# P. v - glCallLists(textLength, 0x1401u, textData); // 调用显示列表& ^8 p8 I2 X5 g" \# z! d: H- _
- 7 c7 P( @7 {6 [+ k+ `
- if (lineIndex < numLines)0 _+ _- X- U" R& k& X9 O' w# T
- lineOffset += 4; // 更新lineOffset* g4 L3 c( A# M
- ++lineIndex; // 递增行索引# e0 Z8 f4 X2 N7 w
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据' G1 F% s' b8 h8 E/ l
- }
* I+ |0 b; I2 v3 G( t - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
2 ?$ V0 _1 G/ R/ ~( T - glPopAttrib(); // 恢复OpenGL属性状态6 I" @& A3 J6 @. I
- }
/ d9 ?# y9 k9 F - }
% Y" q! ]- S! l- [: t! f
复制代码 $ ]6 g+ k0 U* f3 F# [6 s
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
6 T" |; {2 E- U% _$ _# R+ Z0 Q/ U9 c$ P# I7 O6 l
int xOffset, 字幕的x坐标
7 D- s2 I, U. j9 S$ x0 U3 DGLint yOffset, 字幕的y坐标
7 q) ~9 L& E7 R9 J( Bint numLines, 字幕的行数(较长的字幕为2,一般为1)
8 c$ i9 X8 j8 v2 Yint lineOffset, 这个需要再研究
; M0 ^4 `9 U* K! J2 Xint lineHeight, 字体高度(或行高)3 {8 ~0 E" B% ]
GLuint displayListBase, 这个字体对应的base值
' t1 F1 k, W: u1 @/ Tchar *text, ... 字符串 J' h9 K4 q3 b! w Z1 U
' r$ \. V" ^/ S9 N |