本帖最后由 shane007 于 2023-9-5 16:49 编辑
6 Q/ ?4 Y7 \, q3 s% L+ f9 Q9 J& e, f& c
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
t. f( X, f. m& k因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。' |* {9 K; n0 `" y. w t+ J Y b
https://www.chinaavg.com/forum.php?mod=viewthread&tid=1540819 w/ z- r1 `* ]- R6 M) p1 W
第1处4 _, s) L5 D# f+ v- I6 u0 G8 H6 j
- void sub_451474(char *a1, ...)( @. x" }" L6 d5 n9 ]
- {& t1 D6 x( J% \2 Y! y
- GLsizei v1; // eax
+ f4 q8 W- g& t8 C( z - char lists; // [esp+4h] [ebp-800h]
# h; m6 F( m% E+ A+ ]- c - va_list va; // [esp+810h] [ebp+Ch]8 w8 ] p/ f8 w, P
* i7 V4 M& B5 f+ ?# Z+ N8 b" ]$ g o- va_start(va, a1);& o5 z. n. O! X4 ~: C+ A& O7 P+ G
- if ( a1 )
: C* j, O1 g3 X. p. |+ A - {! D3 V5 K2 n* ?+ N* r# `
- vsprintf(&lists, a1, va);6 M" b6 n: I+ |# w
- glPushAttrib(0x20000u);
3 M$ r$ D/ m5 j; `* x& H8 G - glListBase(base);
0 j2 U u% v8 J" z& J% r- C - v1 = strlen(&lists);
; ^' P- ^1 j4 O. m/ ~) V - glCallLists(v1, 0x1401u, &lists);
8 T. Y/ R. L, w9 G/ w; T5 o - glPopAttrib();
2 V6 e- E. s) t( F$ C* I* C' w) N - }
7 e; f [! @& j6 F0 O - }
复制代码 + N7 d& r0 j s u# `4 ?
, v+ W; t' m5 T) | c8 |" _4 F8 R3 e* |0 A1 N1 G, Z# z/ P
第2处6 C. `% S; x: n8 e0 k3 h
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
{7 G& f S$ A) C - {
9 D' e; m- j) ~6 v! | - int v4; // eax8 ]- j6 x6 V X, O: l; k2 f
- GLsizei v5; // eax
" t/ W+ g/ O2 l q4 | - char lists; // [esp+4h] [ebp-800h]3 D, o1 i6 w& Y
- va_list va; // [esp+81Ch] [ebp+18h]
' E4 T) u% ?6 M1 }) Y% M' I" L5 o
9 s# K$ @, _. k5 d" s- va_start(va, a4);
, U6 Y0 d# w; ~4 y# D - if ( a4 )6 j4 i, e# n6 H- j% S s
- {
( C: \& U) a4 I - sub_44F8A0(a3);
" U9 f6 b8 n& X5 g. Z% O - v4 = sub_40BB44();
( x/ R/ `2 k7 h - glRasterPos2i(x, v4 - a2);7 `5 ^& g# C6 N7 _; g$ L
- vsprintf(&lists, a4, va);
3 Z0 o2 v; l! j6 a& n/ A7 m - glPushAttrib(0x20000u);
3 |: a$ X" _1 Y: m1 f9 @0 \ - glListBase(base);' x/ d3 g$ |; c. @
- v5 = strlen(&lists);
' O, m/ N8 }" U9 n1 t c ^. u+ | - glCallLists(v5, 0x1401u, &lists);0 m1 F" R0 N7 K+ T7 x, r
- glPopAttrib();& U$ g6 g* X, f
- }& z8 K0 w7 R( p% n3 E3 h( F9 v/ ^
- }
复制代码 / x; s# s* B3 H, b7 v7 m
' W) e" x7 I4 S% L
: M' J$ K) D( y. H) r2 @第3处
& @; ?5 U; C% P
6 r5 h8 v9 z1 C, S5 S. Y8 W- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
; [5 Y" q( S: L! S. q. f6 l/ u - {2 K( {8 |) c9 P/ G0 n# ?! I
- GLvoid *v7; // ST08_4
* T$ _/ L: \6 J4 w6 E7 s - GLsizei v8; // eax+ ]9 R4 J( h3 S: A% a q
- int v9; // [esp+0h] [ebp-1018h]3 |9 d2 Q; g8 o2 b
- char v10; // [esp+8h] [ebp-1010h]5 S# N- C/ v v( I1 R
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]' J' {$ b4 {6 {/ ~! e, J
- char v12[5]; // [esp+1013h] [ebp-5h]. }+ Y: `9 G: |+ o5 E
- va_list va; // [esp+103Ch] [ebp+24h]9 [* S* C4 G1 H
# |! b* v# @6 k- D3 `! i- va_start(va, a7);
" G. }7 D7 {4 j4 ^! ] - v9 = 1;+ t4 ]& y* H2 _. a6 @
- if ( a7 )- ^4 D& `4 o* }3 i& z
- {) H1 i$ ^9 P; j& q4 h6 @$ X
- vsprintf(&v10, a7, va);, @* z- i6 y2 c) r" K- t
- glPushAttrib(0x20000u); r9 y- W; q. O2 }
- glListBase(base);5 A' }' c1 {. m6 U) ~
- lists = &v10;* J/ n0 Z% c$ n6 @ v
- do) z6 n4 J; B0 w% ]2 N2 B: y! D: o
- {
8 L/ p! a2 n9 Y - *(_DWORD *)&v12[1] = lists;
8 d: M1 B% t) q& M( V - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )6 W& f% Q6 d; H3 r5 m0 ?
- ++*(_DWORD *)&v12[1];- k- i" G* S4 _5 c8 S- K+ `
- v12[0] = **(_BYTE **)&v12[1]; t/ L: {6 y) c
- **(_BYTE **)&v12[1] = 0;
6 [6 {5 D$ o. I) K& Q - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )% G/ K5 H. O+ L8 b' i) B# C
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
+ Q6 W' q* w) B - y -= a5;
; J8 [4 J5 W% H, p; X) K - glRasterPos2i(*(_DWORD *)a4 + a1, y);
9 W, X4 N, W& n5 D - v7 = lists;1 n: n; h/ z' u4 n! h6 m! j
- v8 = strlen((const char *)lists);* h/ e) M: ~: }7 x" \! T
- glCallLists(v8, 0x1401u, v7);: p; T2 N9 k# N. A2 R
- if ( v9 < a3 )% K7 H& g6 Q$ ]8 a1 k6 z# @
- a4 += 4;4 N) ^+ i1 M [
- ++v9;
0 ]2 `. A0 U0 }- l) t - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
1 H4 a' Z m9 f3 O8 S& K9 W9 o - }" P! Y! C2 [0 W& X# J. g; V
- while ( v12[0] );
1 l& _/ b/ ^( p2 Q - glPopAttrib();
% ^2 b' G e S- N& N - }
/ a' t1 I5 b7 c - }4 m4 m0 G! Y: h E
复制代码 ' |/ ?8 [$ M" T! C- P5 R2 ^
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
. j* d; {" D& M% C
: {' G) ]- [( O, _3 @! _$ E- .text:004512B1 52 push edx ; char *7 U" ~1 f! _6 h4 B
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
4 I6 w1 f2 z# ]2 S# e6 q# {" m - .text:004512B5 50 push eax ; base- R, Y; W' p8 s7 E
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
% Y3 ?0 k' r8 d0 ^( r - .text:004512B9 51 push ecx ; int. s# S" x1 O ]
- .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]% | G" x3 u% K' Y! @3 }/ i7 X
- .text:004512BD 52 push edx ; int. A3 {( H& n+ T& I# W
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
/ o5 C7 J- W/ m5 v7 Z* G- ^ - .text:004512C1 50 push eax ; int
( Q8 K4 i+ o$ k6 [5 y - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]9 L1 W% ]) S+ K5 k
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
# j1 V" Z4 m2 [ - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
8 O8 u( F# P# l ~! U4 |$ m7 d - .text:004512CB 51 push ecx ; y
" g; y0 k8 c3 s4 y0 H8 v0 p5 | - .text:004512CC 8B 55 08 mov edx, [ebp+x]
6 W; U) v* L) [' y/ @, f - .text:004512CF 52 push edx ; int! r; s9 M- S0 [
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 E K+ Z' J5 r6 e: p# C% G6 Z
chatGPT整理过之后,如下
* a, I% j! M: P" }6 b4 @
3 w) g+ p- k1 u' H% A* _- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...); v: V( `, d" S
- {
# b$ V' E' p1 I6 e9 f - GLvoid *textData; // 存储字符数据的指针2 L( X9 f3 [0 e3 X
- GLsizei textLength; // 字符数据的长度
, x( O6 W1 s% p - int lineIndex; // 行索引
3 r+ N( _/ {+ |/ L0 H - char formattedText[5]; // 存储格式化后的字符数据0 v# f2 L# q8 M& z u
- GLvoid *currentLine; // 当前行的字符数据指针
: ]; A8 w8 `" M+ Q, \" m- w - char buffer[5]; // 字符数据缓冲区
) a. h. I" H. a8 ]; Y! B1 T - va_list args; // 变长参数列表
4 u' G0 R- n& r i- ~9 \ - " B+ \' `; L, ]
- va_start(args, text); // 初始化变长参数列表
9 E, ^8 m! }1 [4 e9 E - lineIndex = 1; // 初始化行索引为1
% ?0 N3 x- o" ^# W/ q - , _$ s9 A. `( l9 d
- if (text) // 如果文本不为空
+ `, j: o# W) B5 e9 Y - {
: p) K1 @ _# a. J* k - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中
3 y S6 ^$ P2 @) j% R7 m8 k - glPushAttrib(0x20000u); // 推送OpenGL属性状态& c0 I! J" ]: W) z4 Q2 `% n
- glListBase(displayListBase); // 设置显示列表的基础值
1 p) ?! ?& }7 j( ?" |# H. o - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
* F8 u. a# V4 P( I
2 ~) N6 T; P1 O+ X4 p- do
C. S* M q" z+ {6 \$ r - {
* g* G! M& z) m; u0 F - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素$ I( B& l& \4 |# x" \+ A/ Y5 W' a
- * V- c1 d8 U* L4 N* z0 x
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束2 X' c; I# f+ V5 L/ h
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
6 ~" o7 p% X9 I- g" i
# Q+ [, S& l" ~; ?& }$ i( @- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素5 b; E. |8 ?1 x8 E& W0 \
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符/ Z5 M$ t$ \( ~! k8 [( `8 N
- 6 N2 f: z6 N0 n* T9 U% {8 [
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
5 N( \. T! z7 e! B0 M - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符" B* h# u: b6 E% r0 C
- 8 @& {: {- n9 Y, k; C( ~
- yOffset -= lineHeight; // 更新y坐标% R, t5 t% r" @9 v1 l8 x
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置8 }3 ~7 s4 i. ]7 C9 _/ a' d
- textData = currentLine; // 将textData指向currentLine
$ ^ ?! F0 \1 l8 M0 a' z& K - textLength = strlen((const char *)textData); // 计算字符数据的长度
1 w2 @+ G: R L, f( b - glCallLists(textLength, 0x1401u, textData); // 调用显示列表' b2 H8 \+ b( @- e3 X' W9 W
4 ]4 C0 Y% j3 [2 @: X5 e& p- if (lineIndex < numLines)8 Q$ V, U7 C# q4 `- S. P9 { R, W
- lineOffset += 4; // 更新lineOffset
2 P0 y; F% J/ K# Y# r - ++lineIndex; // 递增行索引! G: y6 y5 L8 O+ u
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据" Z; B- k, P9 s7 p7 V& ?! y
- }9 ]" R: t* R- r- w
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环
& M7 x& u0 j5 G6 ? - glPopAttrib(); // 恢复OpenGL属性状态
2 _. _: d% D: ?3 ~: w: p - }
3 z' x- l1 v5 {9 J. @% d7 H - }$ I% b* I" ]8 N" A |; Y
复制代码
' V: Y4 F0 O" Y! w6 ?2 w含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前& ^0 p6 a- m. E9 t& O3 _7 ?' I. d
$ r% q: o, u X
int xOffset, 字幕的x坐标' n. G( U5 g6 T5 M' a: f# c
GLint yOffset, 字幕的y坐标# l9 N) m4 s" s G9 M
int numLines, 字幕的行数(较长的字幕为2,一般为1)
) ]1 }" d; _0 J) `; ?. u+ Tint lineOffset, 这个需要再研究: m2 h# c2 C/ Y% i0 o
int lineHeight, 字体高度(或行高)
. k, [7 S& E3 r- z5 C; QGLuint displayListBase, 这个字体对应的base值" X/ o$ ~: R/ V% O
char *text, ... 字符串
6 p+ F/ K3 D* U% @* v7 E- j3 |* [1 D2 q) k& s7 d+ l4 W( ^9 M
|