本帖最后由 shane007 于 2023-9-5 16:49 编辑 - h' e1 K& x, A7 a" j# K
) Q5 G9 f) @& x
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
# ]' o# j0 R4 q2 o) N因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。! \9 a: H8 ?+ e
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
l0 b# ]2 X% A9 h# Q% Z第1处1 e+ Q. C. u& i
- void sub_451474(char *a1, ...)
2 L2 M: c" h4 x# P% _ k - {
+ {/ J X i8 O1 X1 u8 ~ - GLsizei v1; // eax
. f$ R+ l5 p7 q! \2 d. D - char lists; // [esp+4h] [ebp-800h]$ f2 u9 L2 M$ c- ?
- va_list va; // [esp+810h] [ebp+Ch]' x1 Q b# o5 z! F
# G& ~. e# E3 Q: B+ X- va_start(va, a1);
7 w% U/ n. f) e5 ?7 U3 e, c: i7 N( s- T - if ( a1 )
! [: }# G# a( r, v - {
3 g* b1 t2 s! F { - vsprintf(&lists, a1, va);
) r. w: w( B& z+ | - glPushAttrib(0x20000u); `5 F% u N# y( B5 ?' P" A
- glListBase(base);6 P9 p$ a; G8 B& g: X' j0 ]/ P
- v1 = strlen(&lists);; z# u# U, O0 F8 S
- glCallLists(v1, 0x1401u, &lists);* h( Q" Q7 R2 Q5 g
- glPopAttrib();$ y8 F5 {0 N# n1 G
- }
& b6 S. J/ q4 u% r U K - }
复制代码 ' I$ |- m1 r+ i# W; e U& a
% {/ ?# ~, s( }, k0 w3 b) L, L0 Y* `5 P3 C, a
第2处
" V2 |. ?" Z" m5 I7 m2 y8 N- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
% Z6 _6 {$ ^( p e, k7 K - {8 ?, A% y# E+ k }! ]& ?
- int v4; // eax
1 D J6 f( H6 V: a - GLsizei v5; // eax& w, a! L2 x/ T2 u
- char lists; // [esp+4h] [ebp-800h]- p9 V0 I6 T+ N
- va_list va; // [esp+81Ch] [ebp+18h]4 E) t5 b7 R# N1 V2 J' U' p/ c& n5 j
- 9 S& x7 d# \! b
- va_start(va, a4);; J% _3 `( j; K( w0 z$ q
- if ( a4 )/ ]& W' F! \# t# Z/ x3 m
- {# \! ]2 s0 V, D1 |0 l i
- sub_44F8A0(a3);
/ D- Z, {& U6 }: [! p8 E# Q2 E - v4 = sub_40BB44();! m: \- J( A2 q# @
- glRasterPos2i(x, v4 - a2);
! S; E5 C% N, h' { - vsprintf(&lists, a4, va);
3 V1 g* a* k6 s - glPushAttrib(0x20000u);$ v1 H: P, u9 ^
- glListBase(base);
1 r; d/ G: S! V, Y+ E a& W- }' U - v5 = strlen(&lists);/ h. l6 N+ H7 m- Z
- glCallLists(v5, 0x1401u, &lists);; A! W4 O$ \3 z9 e2 ]! f: R
- glPopAttrib();
: ~& _3 X: S4 ]4 C" l7 j2 ] - }( `1 \, f% U3 ]1 z. b
- }
复制代码 ) b9 Q$ ?$ [" Q a
8 y/ _! `! Q3 R8 C
5 A2 _/ g( m% p# C第3处
/ N+ M! C& [9 p: f' g% T
* ~- x' }5 `, j' j' ~! [/ z- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
1 s8 e5 P. h" T - {
$ B/ Q3 E% X8 J4 Q; u, E/ E7 d - GLvoid *v7; // ST08_4" o% G# W* b( ^9 u9 B
- GLsizei v8; // eax; s( U! Y/ d% b0 {
- int v9; // [esp+0h] [ebp-1018h]
$ Y, q7 v5 c C9 j* [. `2 l - char v10; // [esp+8h] [ebp-1010h]
0 o2 u" [. c+ o - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
, F8 {) R3 |4 w0 Y5 t% I& G/ E4 P - char v12[5]; // [esp+1013h] [ebp-5h]
% T: F( j }1 _; E3 o - va_list va; // [esp+103Ch] [ebp+24h]6 Y+ {% u y" N/ e# r
( I# p; S. c, e! S& I- va_start(va, a7);
~# ]: o4 \5 y2 Y/ y5 p - v9 = 1;
- A& `; n" {; w - if ( a7 )
, n/ a* C4 u0 u- a - {$ n/ O# Z0 D: n$ {
- vsprintf(&v10, a7, va);
5 L3 c- ?) ?' y' Q- k. H - glPushAttrib(0x20000u);
) w8 @1 \% s! X3 y" q5 g( t" {9 n+ i- | - glListBase(base);; |* t$ E2 h' T/ m4 O
- lists = &v10;
: k; [0 }$ e o* N& r - do
8 e, `" h' \4 }1 W6 k7 @# i0 N6 H - {8 f7 s, R8 C4 f- x& H1 Z% K
- *(_DWORD *)&v12[1] = lists;0 Y7 |6 ], e- B- \8 X
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
% _) Y# H; h5 \2 ] - ++*(_DWORD *)&v12[1];
; F/ K+ |+ U* o. m$ h8 G - v12[0] = **(_BYTE **)&v12[1];$ a9 V# e h" k7 G' ^' ]; g; q
- **(_BYTE **)&v12[1] = 0;, I, y2 m0 J$ ~5 S
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
1 m& S* q5 r3 C - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;+ N- X. T1 D. [6 z! V! s! }- V4 t/ z
- y -= a5;& S8 f4 |& z( n+ O
- glRasterPos2i(*(_DWORD *)a4 + a1, y);
$ c' {+ P5 B' B0 E# o4 ]/ g- [3 } - v7 = lists;
* Z8 t7 I8 Y& n - v8 = strlen((const char *)lists);- n) y1 y7 [: ~+ v# I
- glCallLists(v8, 0x1401u, v7);
$ Y: E" r* c" y" ^# r - if ( v9 < a3 )3 O6 u( h9 T- G% Z- e$ Q
- a4 += 4;4 b A1 Q' o8 R9 L& j8 _+ V
- ++v9;
g9 x. j1 j: K5 G" k - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
& F% k! ]0 j' N7 ?$ p3 \3 R - }
0 u5 |, A8 }1 _ - while ( v12[0] );
) k- J) E$ V6 w- P, [% q) k/ c - glPopAttrib();
! x2 A) t3 y2 J+ h - }
& x0 y2 f# S3 i - }: @% \7 B) ^8 Q& u' k. h
复制代码
+ i$ o/ V4 J* J# A# a; T+ L0 P2 ?. w3 B调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_4518105 Z3 {4 a" ^8 P( B0 j* V5 D
1 S6 n' ?7 `' S' W- .text:004512B1 52 push edx ; char ** v, y! n) e: N# W" N' h# b
- .text:004512B2 8B 45 30 mov eax, [ebp+base]5 k& Z; _1 f* G. P( U
- .text:004512B5 50 push eax ; base
' A s- D9 ]7 \+ F - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
4 _1 u% Z+ { J+ W+ [ - .text:004512B9 51 push ecx ; int. E1 ]1 C; h" S$ W% W
- .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
# _/ G* d& r& W - .text:004512BD 52 push edx ; int
# b' a; u J5 G - .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
2 D& @% x7 U, m - .text:004512C1 50 push eax ; int/ l+ g; ~/ p/ O! p# ]/ S
- .text:004512C2 8B 4D 0C mov ecx, [ebp+y]# C0 C u1 c! y* Q! y" F0 F4 U
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
- q$ y/ A9 o1 `* j9 g- _6 O; B1 ~ - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
( ]8 T/ R4 J2 q - .text:004512CB 51 push ecx ; y
2 V0 s5 t$ m- S - .text:004512CC 8B 55 08 mov edx, [ebp+x]
! ]% {. ?5 `! V0 T* Z - .text:004512CF 52 push edx ; int
. E5 y/ f& |/ j5 k - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
# j- v2 v& @) n' P. Q& {chatGPT整理过之后,如下. g" T: i2 m; i' H
' y* u, e, m; n
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
/ V4 z5 Y! w$ P% f/ ~( p - {
) V( A& ?' [7 C0 o) {' d7 ] - GLvoid *textData; // 存储字符数据的指针
; j, m- ?# E, ~ - GLsizei textLength; // 字符数据的长度
6 ]8 I& q2 k8 v$ S- @ - int lineIndex; // 行索引
- v& T2 q8 Z: a8 n6 N - char formattedText[5]; // 存储格式化后的字符数据+ v% G; ?* [) A
- GLvoid *currentLine; // 当前行的字符数据指针1 F# R1 `6 [ Q9 l, r
- char buffer[5]; // 字符数据缓冲区- D9 F6 |# l, G) Y# c5 l. k6 n4 S/ a
- va_list args; // 变长参数列表9 A# y/ }& w S$ B' \$ k; V# W- }" O
- 3 B' ` H/ c5 e3 z, Q: p3 R
- va_start(args, text); // 初始化变长参数列表9 \; l. k6 F) ~% c, n" o& D
- lineIndex = 1; // 初始化行索引为1 }4 o8 y! j& j, o
- p: a. o: K/ m6 s# M$ ?; v( @( t7 R
- if (text) // 如果文本不为空: X1 U, Y2 p% ^- y
- {2 B0 N+ K$ B# p T( Q
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中) _+ ~8 i2 g4 x) J% q7 ~" I* m
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
" l+ J. H; M. V& V% @5 n- n8 {" A - glListBase(displayListBase); // 设置显示列表的基础值5 w6 g4 Y: ?% N2 I9 l* c. V4 F
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置
5 p+ X+ o z8 {
# l. p* T: k% C7 Z- do, q. Z+ w0 J! t
- { o' U! e" r8 E; { x+ \
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素: U; Y6 g7 K% L: w+ a% z" r- S: |
- 0 ~7 i# d7 I- @# {( d+ p
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
: Z( ?# X" m! x/ H- r# ` - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
$ _! U& [, o( M$ W$ ` - 5 d" Z5 T8 p" b& _
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
7 I# z8 p4 j8 C; G0 s2 a3 L. B9 F - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
% N) a F6 d! s* U* J* P5 _ - , ^3 r5 _; G) l+ l9 X
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
. U) E& |& D. @6 f+ M - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
; P. j: a7 h( t' P8 u
* y6 I, M6 d. L- yOffset -= lineHeight; // 更新y坐标! `1 r" S* d, \0 R# K, b$ m
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置4 n" k7 ^, h; {# g$ q/ R `
- textData = currentLine; // 将textData指向currentLine
( _' ]3 o! _: }7 W2 k- _$ W7 ^ - textLength = strlen((const char *)textData); // 计算字符数据的长度% }7 g+ ]- @( l, I: A
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
! L; v5 [ ~! l( g8 O1 G- [- J8 ]& @9 r) _
* U" U) T% `7 \5 |; u- if (lineIndex < numLines)) Y; n+ m+ v. Q! H2 V9 [: ^
- lineOffset += 4; // 更新lineOffset
# \$ P/ r) Z p - ++lineIndex; // 递增行索引/ @! K! H, X; Z" M: a. f" { a
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
4 a' e2 h- @. y- d2 @8 b) E - }0 J$ h5 T: P: z
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
, L% L8 C; D' g: b, Q( h6 T* H - glPopAttrib(); // 恢复OpenGL属性状态2 H) o; e* g& M4 J3 }- Y7 H) z
- }+ P# U7 V8 V/ A, m/ F
- }
; b2 y+ `7 O* b* Z" J: x
复制代码
* _; [0 _. h8 p" e9 V含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
: p1 R6 V4 K+ G1 ^
% j/ w0 G, e) N. ~* @6 v) p# Bint xOffset, 字幕的x坐标
8 d1 a) j+ L# y, cGLint yOffset, 字幕的y坐标
1 X" g; H; q6 W. Tint numLines, 字幕的行数(较长的字幕为2,一般为1)& r& V$ u# M. U
int lineOffset, 这个需要再研究4 M' D4 k8 N6 C+ ]+ \+ t
int lineHeight, 字体高度(或行高)
& |1 n6 Y' V& B& R, U( u! J% n8 tGLuint displayListBase, 这个字体对应的base值 N4 R: k/ S) [+ M# T
char *text, ... 字符串
3 D v! \* x" d* g, N( T* D
+ Y m c5 p& H& A5 I9 V5 _ |